Coverage Report

Created: 2026-09-14 06:43

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