Coverage Report

Created: 2026-06-15 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmInstrumentationQuery.cxx
Line
Count
Source
1
#include "cmInstrumentationQuery.h"
2
3
#include <algorithm>
4
#include <ctime>
5
#include <functional>
6
#include <iterator>
7
#include <set>
8
#include <vector>
9
10
#include <cmext/string_view>
11
12
#include <cm3p/json/value.h>
13
14
#include "cmJSONHelpers.h"
15
#include "cmStringAlgorithms.h"
16
17
std::vector<std::string> const cmInstrumentationQuery::OptionString{
18
  "staticSystemInformation",
19
  "dynamicSystemInformation",
20
  "captureOutput",
21
  "compileTrace",
22
  "cdashSubmit",
23
  "cdashVerbose",
24
  "trace"
25
};
26
std::vector<std::string> const cmInstrumentationQuery::HookString{
27
  "postGenerate",    "preBuild",  "postBuild",        "preCMakeBuild",
28
  "postCMakeBuild",  "postCTest", "postCMakeInstall", "postCMakeWorkflow",
29
  "prepareForCDash", "manual"
30
};
31
32
namespace ErrorMessages {
33
using ErrorGenerator =
34
  std::function<void(Json::Value const*, cmJSONState* state)>;
35
ErrorGenerator ErrorGeneratorBuilder(std::string const& errorMessage)
36
4
{
37
4
  return [errorMessage](Json::Value const* value, cmJSONState* state) -> void {
38
0
    state->AddErrorAtValue(errorMessage, value);
39
0
  };
40
4
};
41
42
static ErrorGenerator InvalidArray = ErrorGeneratorBuilder("Invalid Array");
43
JsonErrors::ErrorGenerator InvalidRootQueryObject(
44
  JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields)
45
0
{
46
0
  return JsonErrors::INVALID_NAMED_OBJECT(
47
0
    [](Json::Value const*, cmJSONState*) -> std::string {
48
0
      return "root object";
49
0
    })(errorType, extraFields);
50
0
}
51
};
52
53
using JSONHelperBuilder = cmJSONHelperBuilder;
54
using Version = cmInstrumentationQuery::Version;
55
56
template <typename E>
57
static std::function<bool(E&, Json::Value const*, cmJSONState*)> EnumHelper(
58
  std::vector<std::string> const toString, std::string const& type)
59
8
{
60
8
  return [toString, type](E& out, Json::Value const* value,
61
8
                          cmJSONState* state) -> bool {
62
0
    for (size_t i = 0; i < toString.size(); ++i) {
63
0
      if (value->asString() == toString[i]) {
64
0
        out = (E)i;
65
0
        return true;
66
0
      }
67
0
    }
68
0
    state->AddErrorAtValue(
69
0
      cmStrCat("Not a valid ", type, ": \"", value->asString(), '"'), value);
70
0
    return false;
71
0
  };
Unexecuted instantiation: cmInstrumentationQuery.cxx:EnumHelper<cmInstrumentationQuery::Option>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::{lambda(cmInstrumentationQuery::Option&, Json::Value const*, cmJSONState*)#1}::operator()(cmInstrumentationQuery::Option&, Json::Value const*, cmJSONState*) const
Unexecuted instantiation: cmInstrumentationQuery.cxx:EnumHelper<cmInstrumentationQuery::Hook>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::{lambda(cmInstrumentationQuery::Hook&, Json::Value const*, cmJSONState*)#1}::operator()(cmInstrumentationQuery::Hook&, Json::Value const*, cmJSONState*) const
72
8
}
cmInstrumentationQuery.cxx:std::__1::function<bool (cmInstrumentationQuery::Option&, Json::Value const*, cmJSONState*)> EnumHelper<cmInstrumentationQuery::Option>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
59
4
{
60
4
  return [toString, type](E& out, Json::Value const* value,
61
4
                          cmJSONState* state) -> bool {
62
4
    for (size_t i = 0; i < toString.size(); ++i) {
63
4
      if (value->asString() == toString[i]) {
64
4
        out = (E)i;
65
4
        return true;
66
4
      }
67
4
    }
68
4
    state->AddErrorAtValue(
69
4
      cmStrCat("Not a valid ", type, ": \"", value->asString(), '"'), value);
70
4
    return false;
71
4
  };
72
4
}
cmInstrumentationQuery.cxx:std::__1::function<bool (cmInstrumentationQuery::Hook&, Json::Value const*, cmJSONState*)> EnumHelper<cmInstrumentationQuery::Hook>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
59
4
{
60
4
  return [toString, type](E& out, Json::Value const* value,
61
4
                          cmJSONState* state) -> bool {
62
4
    for (size_t i = 0; i < toString.size(); ++i) {
63
4
      if (value->asString() == toString[i]) {
64
4
        out = (E)i;
65
4
        return true;
66
4
      }
67
4
    }
68
4
    state->AddErrorAtValue(
69
4
      cmStrCat("Not a valid ", type, ": \"", value->asString(), '"'), value);
70
4
    return false;
71
4
  };
72
4
}
73
static auto const OptionHelper = EnumHelper<cmInstrumentationQuery::Option>(
74
  cmInstrumentationQuery::OptionString, "option");
75
static auto const OptionListHelper =
76
  JSONHelperBuilder::Vector<cmInstrumentationQuery::Option>(
77
    ErrorMessages::InvalidArray, OptionHelper);
78
static auto const HookHelper = EnumHelper<cmInstrumentationQuery::Hook>(
79
  cmInstrumentationQuery::HookString, "hook");
80
static auto const HookListHelper =
81
  JSONHelperBuilder::Vector<cmInstrumentationQuery::Hook>(
82
    ErrorMessages::InvalidArray, HookHelper);
83
static auto const CallbackHelper = JSONHelperBuilder::String();
84
static auto const CallbackListHelper = JSONHelperBuilder::Vector<std::string>(
85
  ErrorMessages::InvalidArray, CallbackHelper);
86
87
JsonErrors::ErrorGenerator InvalidVersionObject(
88
  JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields)
89
0
{
90
0
  return JsonErrors::INVALID_NAMED_OBJECT(
91
0
    [](Json::Value const*, cmJSONState*) -> std::string {
92
0
      return "version object";
93
0
    })(errorType, extraFields);
94
0
}
95
96
static auto const VersionObjectHelper =
97
  JSONHelperBuilder::Object<Version>(InvalidVersionObject, false)
98
    .Bind("major"_s, &Version::Major, JSONHelperBuilder::Int(), true)
99
    .Bind("minor"_s, &Version::Minor, JSONHelperBuilder::Int(), false);
100
101
bool VersionHelper(Version& out, Json::Value const* value, cmJSONState* state)
102
0
{
103
0
  out.Minor = 0;
104
0
  if (value->isInt()) {
105
0
    out.Major = value->asInt();
106
0
  } else if (value->isObject()) {
107
0
    if (!VersionObjectHelper(out, value, state)) {
108
0
      return false;
109
0
    }
110
0
  } else {
111
0
    state->AddErrorAtValue("Version must be an integer or object", value);
112
0
    return false;
113
0
  }
114
0
  return true;
115
0
}
116
117
using QueryRoot = cmInstrumentationQuery::QueryJSONRoot;
118
119
static auto const QueryRootHelper =
120
  JSONHelperBuilder::Object<QueryRoot>(ErrorMessages::InvalidRootQueryObject,
121
                                       false)
122
    .Bind("version"_s, &QueryRoot::version, VersionHelper, true)
123
    .Bind("options"_s, &QueryRoot::options, OptionListHelper, false)
124
    .Bind("hooks"_s, &QueryRoot::hooks, HookListHelper, false)
125
    .Bind("callbacks"_s, &QueryRoot::callbacks, CallbackListHelper, false);
126
127
static auto const QueryRootVersionOnlyHelper =
128
  JSONHelperBuilder::Object<QueryRoot>(ErrorMessages::InvalidRootQueryObject,
129
                                       true)
130
    .Bind("version"_s, &QueryRoot::version, VersionHelper, true);
131
132
bool cmInstrumentationQuery::ReadJSON(std::string const& filename,
133
                                      std::string& errorMessage,
134
                                      std::set<Option>& options,
135
                                      std::set<Hook>& hooks,
136
                                      std::vector<Callback>& callbacks)
137
0
{
138
0
  Json::Value root;
139
0
  this->parseState = cmJSONState(filename, &root);
140
0
  if (!this->parseState.errors.empty()) {
141
0
    errorMessage = this->parseState.GetErrorMessage(true);
142
0
    return false;
143
0
  }
144
0
  if (!QueryRootVersionOnlyHelper(this->queryRoot, &root, &this->parseState)) {
145
0
    errorMessage = this->parseState.GetErrorMessage(true);
146
0
    return false;
147
0
  }
148
0
  if (!ValidDataVersion(this->queryRoot.version)) {
149
    // Ignore invalid data versions
150
0
    return true;
151
0
  }
152
0
  if (!QueryRootHelper(this->queryRoot, &root, &this->parseState)) {
153
0
    errorMessage = this->parseState.GetErrorMessage(true);
154
0
    return false;
155
0
  }
156
0
  std::move(this->queryRoot.options.begin(), this->queryRoot.options.end(),
157
0
            std::inserter(options, options.end()));
158
0
  std::move(this->queryRoot.hooks.begin(), this->queryRoot.hooks.end(),
159
0
            std::inserter(hooks, hooks.end()));
160
0
  for (auto const& callback : this->queryRoot.callbacks) {
161
0
    callbacks.push_back({ callback, this->queryRoot.version });
162
0
  }
163
0
  return true;
164
0
}
165
166
bool cmInstrumentationQuery::ValidDataVersion(Version version)
167
0
{
168
0
  auto const latest = LatestDataVersion();
169
0
  return version.Major == latest.Major && version.Minor <= latest.Minor;
170
0
}
171
172
Version cmInstrumentationQuery::LatestDataVersion()
173
4
{
174
4
  Version latest;
175
4
  latest.Major = 1;
176
4
  latest.Minor = 1;
177
4
  return latest;
178
4
}