Merge topic 'ctest-json-test-prop-raw'

572e4b5d2a ctest: Add --show-only=json-v1-raw option

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !12288
This commit is contained in:
Brad King
2026-08-04 10:53:33 -04:00
committed by Kitware Robot
15 changed files with 455 additions and 68 deletions
+10 -3
View File
@@ -260,6 +260,13 @@ The options for running tests are:
Dump the test information in JSON format.
See `Show as JSON Object Model`_.
``json-v1-raw``
.. versionadded:: 4.5
Dump the test information in JSON format, but leaves test property
values as raw strings. See `Show as JSON Object Model`_.
.. option:: -L <regex>, --label-regex <regex>
Run tests with labels matching regular expression as described under
@@ -1895,9 +1902,9 @@ Show as JSON Object Model
.. versionadded:: 3.14
When the ``--show-only=json-v1`` command line option is given, the test
information is output in JSON format. Version 1.0 of the JSON object
model is defined as follows:
When the ``--show-only=json-v1`` or ``--show-only=json-v1-raw`` command
line option is given, the test information is output in JSON format.
Version 1.0 of the JSON object model is defined as follows:
``kind``
The string "ctestInfo".
@@ -55,6 +55,8 @@
* ``json-v1``
* ``json-v1-raw``
.. _`CMakePresets.testPresets.execution.repeat`:
``repeat``
+3 -2
View File
@@ -3391,9 +3391,10 @@
"type": "string",
"enum": [
"human",
"json-v1"
"json-v1",
"json-v1-raw"
],
"description": "An optional string. Equivalent to passing --show-only on the command line. Value must be \"human\" or \"json-v1\"."
"description": "An optional string. Equivalent to passing --show-only on the command line. Value must be \"human\", \"json-v1\", or \"json-v1-raw\"."
},
"testPresets.execution.repeat@v2..v9": {
"type": "object",
+5 -1
View File
@@ -1657,9 +1657,11 @@ properties:
enum:
- human
- json-v1
- json-v1-raw
description:
An optional string. Equivalent to passing --show-only on the
command line. Value must be "human" or "json-v1".
command line. Value must be "human", "json-v1", or
"json-v1-raw".
sphinxDescription: |
An optional string. Equivalent to passing
:ctest-option:`--show-only` on the command line. The string
@@ -1668,6 +1670,8 @@ properties:
* ``human``
* ``json-v1``
* ``json-v1-raw``
repeat:
type: object
description:
@@ -0,0 +1,6 @@
ctest-json-test-prop-raw
------------------------
* The CTest option ``--show-only=[format]`` now has a ``json-v1-raw`` format.
When this format is used, the ``value`` for each test property is the
original unparsed string value specified in CMake.
+108 -44
View File
@@ -1170,134 +1170,197 @@ static Json::Value DumpCTestProperty(std::string const& name,
return property;
}
static Json::Value DumpCTestPropertyRaw(std::string const& name,
std::string const& value)
{
Json::Value property = Json::objectValue;
property["name"] = name;
property["value"] = value;
return property;
}
static Json::Value DumpCTestProperties(
cmCTestTestHandler::cmCTestTestProperties& testProperties)
cmCTestTestHandler::cmCTestTestProperties& testProperties, bool raw)
{
Json::Value properties = Json::arrayValue;
std::unordered_map<std::string, std::string>& rawProperties =
testProperties.RawProperties;
if (!testProperties.AttachOnFail.empty()) {
properties.append(DumpCTestProperty(
"ATTACHED_FILES_ON_FAIL", DumpToJsonArray(testProperties.AttachOnFail)));
properties.append(
DumpCTestProperty("ATTACHED_FILES_ON_FAIL",
raw ? rawProperties["ATTACHED_FILES_ON_FAIL"]
: DumpToJsonArray(testProperties.AttachOnFail)));
}
if (!testProperties.AttachedFiles.empty()) {
properties.append(DumpCTestProperty(
"ATTACHED_FILES", DumpToJsonArray(testProperties.AttachedFiles)));
properties.append(
DumpCTestProperty("ATTACHED_FILES",
raw ? rawProperties["ATTACHED_FILES"]
: DumpToJsonArray(testProperties.AttachedFiles)));
}
if (testProperties.Cost != 0.0f) {
properties.append(
DumpCTestProperty("COST", static_cast<double>(testProperties.Cost)));
properties.append(DumpCTestProperty(
"COST",
raw ? rawProperties["COST"]
: Json::Value(static_cast<double>(testProperties.Cost))));
}
if (!testProperties.Depends.empty()) {
properties.append(
DumpCTestProperty("DEPENDS", DumpToJsonArray(testProperties.Depends)));
DumpCTestProperty("DEPENDS",
raw ? rawProperties["DEPENDS"]
: DumpToJsonArray(testProperties.Depends)));
}
if (testProperties.Disabled) {
properties.append(DumpCTestProperty("DISABLED", testProperties.Disabled));
properties.append(DumpCTestProperty(
"DISABLED",
raw ? rawProperties["DISABLED"] : Json::Value(testProperties.Disabled)));
}
if (!testProperties.Environment.empty()) {
properties.append(DumpCTestProperty(
"ENVIRONMENT", DumpToJsonArray(testProperties.Environment)));
properties.append(
DumpCTestProperty("ENVIRONMENT",
raw ? rawProperties["ENVIRONMENT"]
: DumpToJsonArray(testProperties.Environment)));
}
if (!testProperties.EnvironmentModification.empty()) {
properties.append(DumpCTestProperty(
"ENVIRONMENT_MODIFICATION",
DumpToJsonArray(testProperties.EnvironmentModification)));
raw ? rawProperties["ENVIRONMENT_MODIFICATION"]
: DumpToJsonArray(testProperties.EnvironmentModification)));
}
if (!testProperties.ErrorRegularExpressions.empty()) {
properties.append(DumpCTestProperty(
"FAIL_REGULAR_EXPRESSION",
DumpRegExToJsonArray(testProperties.ErrorRegularExpressions)));
raw ? rawProperties["FAIL_REGULAR_EXPRESSION"]
: DumpRegExToJsonArray(testProperties.ErrorRegularExpressions)));
}
if (!testProperties.SkipRegularExpressions.empty()) {
properties.append(DumpCTestProperty(
"SKIP_REGULAR_EXPRESSION",
DumpRegExToJsonArray(testProperties.SkipRegularExpressions)));
raw ? rawProperties["SKIP_REGULAR_EXPRESSION"]
: DumpRegExToJsonArray(testProperties.SkipRegularExpressions)));
}
if (!testProperties.FixturesCleanup.empty()) {
properties.append(DumpCTestProperty(
"FIXTURES_CLEANUP", DumpToJsonArray(testProperties.FixturesCleanup)));
"FIXTURES_CLEANUP",
raw ? rawProperties["FIXTURES_CLEANUP"]
: DumpToJsonArray(testProperties.FixturesCleanup)));
}
if (!testProperties.FixturesRequired.empty()) {
properties.append(DumpCTestProperty(
"FIXTURES_REQUIRED", DumpToJsonArray(testProperties.FixturesRequired)));
"FIXTURES_REQUIRED",
raw ? rawProperties["FIXTURES_REQUIRED"]
: DumpToJsonArray(testProperties.FixturesRequired)));
}
if (!testProperties.FixturesSetup.empty()) {
properties.append(DumpCTestProperty(
"FIXTURES_SETUP", DumpToJsonArray(testProperties.FixturesSetup)));
properties.append(
DumpCTestProperty("FIXTURES_SETUP",
raw ? rawProperties["FIXTURES_SETUP"]
: DumpToJsonArray(testProperties.FixturesSetup)));
}
if (!testProperties.GeneratedResourceSpecFile.empty()) {
properties.append(
DumpCTestProperty("GENERATED_RESOURCE_SPEC_FILE",
testProperties.GeneratedResourceSpecFile));
raw ? rawProperties["GENERATED_RESOURCE_SPEC_FILE"]
: testProperties.GeneratedResourceSpecFile));
}
if (!testProperties.Labels.empty()) {
properties.append(
DumpCTestProperty("LABELS", DumpToJsonArray(testProperties.Labels)));
properties.append(DumpCTestProperty(
"LABELS",
raw ? rawProperties["LABELS"] : DumpToJsonArray(testProperties.Labels)));
}
if (!testProperties.Measurements.empty()) {
properties.append(DumpCTestProperty(
"MEASUREMENT", DumpMeasurementToJsonArray(testProperties.Measurements)));
"MEASUREMENT",
raw ? rawProperties["MEASUREMENT"]
: DumpMeasurementToJsonArray(testProperties.Measurements)));
}
if (!testProperties.RequiredRegularExpressions.empty()) {
properties.append(DumpCTestProperty(
"PASS_REGULAR_EXPRESSION",
DumpRegExToJsonArray(testProperties.RequiredRegularExpressions)));
raw ? rawProperties["PASS_REGULAR_EXPRESSION"]
: DumpRegExToJsonArray(testProperties.RequiredRegularExpressions)));
}
if (!testProperties.ResourceGroups.empty()) {
properties.append(DumpCTestProperty(
"RESOURCE_GROUPS",
DumpResourceGroupsToJsonArray(testProperties.ResourceGroups)));
raw ? rawProperties["RESOURCE_GROUPS"]
: DumpResourceGroupsToJsonArray(testProperties.ResourceGroups)));
}
if (testProperties.WantAffinity) {
properties.append(
DumpCTestProperty("PROCESSOR_AFFINITY", testProperties.WantAffinity));
DumpCTestProperty("PROCESSOR_AFFINITY",
raw ? rawProperties["PROCESSOR_AFFINITY"]
: Json::Value(testProperties.WantAffinity)));
}
if (testProperties.Processors != 1) {
properties.append(
DumpCTestProperty("PROCESSORS", testProperties.Processors));
DumpCTestProperty("PROCESSORS",
raw ? rawProperties["PROCESSORS"]
: Json::Value(testProperties.Processors)));
}
if (!testProperties.RequiredFiles.empty()) {
properties.append(DumpCTestProperty(
"REQUIRED_FILES", DumpToJsonArray(testProperties.RequiredFiles)));
properties.append(
DumpCTestProperty("REQUIRED_FILES",
raw ? rawProperties["REQUIRED_FILES"]
: DumpToJsonArray(testProperties.RequiredFiles)));
}
if (!testProperties.ProjectResources.empty()) {
properties.append(DumpCTestProperty(
"RESOURCE_LOCK", DumpToJsonArray(testProperties.ProjectResources)));
"RESOURCE_LOCK",
raw ? rawProperties["RESOURCE_LOCK"]
: DumpToJsonArray(testProperties.ProjectResources)));
}
if (testProperties.RunSerial) {
properties.append(
DumpCTestProperty("RUN_SERIAL", testProperties.RunSerial));
DumpCTestProperty("RUN_SERIAL",
raw ? rawProperties["RUN_SERIAL"]
: Json::Value(testProperties.RunSerial)));
}
if (testProperties.SkipReturnCode != -1) {
properties.append(
DumpCTestProperty("SKIP_RETURN_CODE", testProperties.SkipReturnCode));
DumpCTestProperty("SKIP_RETURN_CODE",
raw ? rawProperties["SKIP_RETURN_CODE"]
: Json::Value(testProperties.SkipReturnCode)));
}
if (testProperties.Timeout) {
properties.append(
DumpCTestProperty("TIMEOUT", testProperties.Timeout->count()));
DumpCTestProperty("TIMEOUT",
raw ? rawProperties["TIMEOUT"]
: Json::Value(testProperties.Timeout->count())));
}
if (testProperties.TimeoutSignal) {
properties.append(DumpCTestProperty("TIMEOUT_SIGNAL_NAME",
testProperties.TimeoutSignal->Name));
properties.append(
DumpCTestProperty("TIMEOUT_SIGNAL_NAME",
raw ? rawProperties["TIMEOUT_SIGNAL_NAME"]
: testProperties.TimeoutSignal->Name));
}
if (testProperties.TimeoutGracePeriod) {
properties.append(
DumpCTestProperty("TIMEOUT_SIGNAL_GRACE_PERIOD",
testProperties.TimeoutGracePeriod->count()));
properties.append(DumpCTestProperty(
"TIMEOUT_SIGNAL_GRACE_PERIOD",
raw ? rawProperties["TIMEOUT_SIGNAL_GRACE_PERIOD"]
: Json::Value(testProperties.TimeoutGracePeriod->count())));
}
if (!testProperties.TimeoutRegularExpressions.empty()) {
properties.append(DumpCTestProperty(
"TIMEOUT_AFTER_MATCH", DumpTimeoutAfterMatch(testProperties)));
properties.append(
DumpCTestProperty("TIMEOUT_AFTER_MATCH",
raw ? rawProperties["TIMEOUT_AFTER_MATCH"]
: DumpTimeoutAfterMatch(testProperties)));
}
if (testProperties.WillFail) {
properties.append(DumpCTestProperty("WILL_FAIL", testProperties.WillFail));
properties.append(
DumpCTestProperty("WILL_FAIL",
raw ? rawProperties["WILL_FAIL"]
: Json::Value(testProperties.WillFail)));
}
if (!testProperties.Directory.empty()) {
properties.append(
DumpCTestProperty("WORKING_DIRECTORY", testProperties.Directory));
properties.append(DumpCTestProperty(
"WORKING_DIRECTORY",
raw ? rawProperties["WORKING_DIRECTORY"] : testProperties.Directory));
}
if (!testProperties.CustomProperties.empty()) {
for (auto const& it : testProperties.CustomProperties) {
properties.append(DumpCTestProperty(it.first, it.second));
Json::Value property = raw ? DumpCTestPropertyRaw(it.first, it.second)
: DumpCTestProperty(it.first, it.second);
properties.append(std::move(property));
}
}
return properties;
@@ -1409,7 +1472,8 @@ static Json::Value DumpCTestInfo(
}
testInfo["command"] = DumpToJsonArray(commandAndArgs);
}
Json::Value properties = DumpCTestProperties(testProperties);
Json::Value properties = DumpCTestProperties(
testProperties, testRun.GetCTest()->GetOutputAsJsonRaw());
if (!properties.empty()) {
testInfo["properties"] = properties;
}
+40
View File
@@ -338,6 +338,14 @@ bool cmCTestSetDirectoryPropertiesCommand::InitialPass(
return this->TestHandler->SetDirectoryProperties(args);
}
void AppendRawProperty(std::string& property, std::string const& value)
{
if (!property.empty() && !value.empty()) {
property += ';';
}
property += value;
}
// get the next number in a string with numbers separated by ,
// pos is the start of the search and pos2 is the end of the search
// pos becomes pos2 after a call to GetNextNumber.
@@ -2392,32 +2400,42 @@ bool cmCTestTestHandler::SetTestsProperties(
}
}
} else if (key == "WILL_FAIL"_s) {
rt.RawProperties[key] = val;
rt.WillFail = cmIsOn(val);
} else if (key == "DISABLED"_s) {
rt.RawProperties[key] = val;
rt.Disabled = cmIsOn(val);
} else if (key == "ATTACHED_FILES"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmExpandList(val, rt.AttachedFiles);
} else if (key == "ATTACHED_FILES_ON_FAIL"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmExpandList(val, rt.AttachOnFail);
} else if (key == "RESOURCE_LOCK"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList lval{ val };
rt.ProjectResources.insert(lval.begin(), lval.end());
} else if (key == "FIXTURES_SETUP"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList lval{ val };
rt.FixturesSetup.insert(lval.begin(), lval.end());
} else if (key == "FIXTURES_CLEANUP"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList lval{ val };
rt.FixturesCleanup.insert(lval.begin(), lval.end());
} else if (key == "FIXTURES_REQUIRED"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList lval{ val };
rt.FixturesRequired.insert(lval.begin(), lval.end());
} else if (key == "TIMEOUT"_s) {
rt.RawProperties[key] = val;
rt.Timeout = cmDuration(atof(val.c_str()));
} else if (key == "TIMEOUT_SIGNAL_NAME"_s) {
rt.RawProperties[key] = val;
#ifdef _WIN32
rt.AppendError("TIMEOUT_SIGNAL_NAME is not supported on Windows.");
#else
@@ -2443,6 +2461,7 @@ bool cmCTestTestHandler::SetTestsProperties(
}
#endif
} else if (key == "TIMEOUT_SIGNAL_GRACE_PERIOD"_s) {
rt.RawProperties[key] = val;
#ifdef _WIN32
rt.AppendError(
"TIMEOUT_SIGNAL_GRACE_PERIOD is not supported on Windows.");
@@ -2465,46 +2484,60 @@ bool cmCTestTestHandler::SetTestsProperties(
}
#endif
} else if (key == "COST"_s) {
rt.RawProperties[key] = val;
rt.Cost = static_cast<float>(atof(val.c_str()));
} else if (key == "REQUIRED_FILES"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmExpandList(val, rt.RequiredFiles);
} else if (key == "RUN_SERIAL"_s) {
rt.RawProperties[key] = val;
rt.RunSerial = cmIsOn(val);
} else if (key == "FAIL_REGULAR_EXPRESSION"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList lval{ val };
for (std::string const& cr : lval) {
rt.ErrorRegularExpressions.emplace_back(cr, cr);
}
} else if (key == "SKIP_REGULAR_EXPRESSION"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList lval{ val };
for (std::string const& cr : lval) {
rt.SkipRegularExpressions.emplace_back(cr, cr);
}
} else if (key == "PROCESSORS"_s) {
rt.RawProperties[key] = val;
rt.Processors = atoi(val.c_str());
if (rt.Processors < 1) {
rt.Processors = 1;
}
} else if (key == "PROCESSOR_AFFINITY"_s) {
rt.RawProperties[key] = val;
rt.WantAffinity = cmIsOn(val);
} else if (key == "RESOURCE_GROUPS"_s) {
AppendRawProperty(rt.RawProperties[key], val);
if (!ParseResourceGroupsProperty(val, rt.ResourceGroups)) {
return false;
}
} else if (key == "GENERATED_RESOURCE_SPEC_FILE"_s) {
rt.RawProperties[key] = val;
rt.GeneratedResourceSpecFile = val;
} else if (key == "SKIP_RETURN_CODE"_s) {
rt.RawProperties[key] = val;
rt.SkipReturnCode = atoi(val.c_str());
if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) {
rt.SkipReturnCode = -1;
}
} else if (key == "DEPENDS"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmExpandList(val, rt.Depends);
} else if (key == "ENVIRONMENT"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmExpandList(val, rt.Environment);
} else if (key == "ENVIRONMENT_MODIFICATION"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmExpandList(val, rt.EnvironmentModification);
} else if (key == "LABELS"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList Labels{ val };
rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end());
// sort the array
@@ -2513,6 +2546,7 @@ bool cmCTestTestHandler::SetTestsProperties(
auto new_end = std::unique(rt.Labels.begin(), rt.Labels.end());
rt.Labels.erase(new_end, rt.Labels.end());
} else if (key == "MEASUREMENT"_s) {
AppendRawProperty(rt.RawProperties[key], val);
size_t pos = val.find_first_of('=');
if (pos != std::string::npos) {
std::string mKey = val.substr(0, pos);
@@ -2522,13 +2556,16 @@ bool cmCTestTestHandler::SetTestsProperties(
rt.Measurements[val] = "1";
}
} else if (key == "PASS_REGULAR_EXPRESSION"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList lval{ val };
for (std::string const& cr : lval) {
rt.RequiredRegularExpressions.emplace_back(cr, cr);
}
} else if (key == "WORKING_DIRECTORY"_s) {
rt.RawProperties[key] = val;
rt.Directory = val;
} else if (key == "TIMEOUT_AFTER_MATCH"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList propArgs{ val };
if (propArgs.size() != 2) {
cmCTestLog(this->CTest, WARNING,
@@ -2582,6 +2619,8 @@ bool cmCTestTestHandler::SetDirectoryProperties(
std::string cwd = cmSystemTools::GetLogicalWorkingDirectory();
if (cwd == rt.Directory) {
if (key == "LABELS"_s) {
AppendRawProperty(rt.RawProperties[key], val);
cmList DirectoryLabels{ val };
rt.Labels.insert(rt.Labels.end(), DirectoryLabels.begin(),
DirectoryLabels.end());
@@ -2622,6 +2661,7 @@ bool cmCTestTestHandler::AddTest(std::vector<std::string> const& args)
test.Args = args;
test.CTestDirectory = cmSystemTools::GetLogicalWorkingDirectory();
test.Directory = test.CTestDirectory;
test.RawProperties["WORKING_DIRECTORY"] = test.CTestDirectory;
cmCTestOptionalLog(this->CTest, DEBUG,
"Set test directory: " << test.Directory << std::endl,
this->Quiet);
+31
View File
@@ -11,6 +11,7 @@
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -150,50 +151,80 @@ public:
std::string Name;
// working directory for test, overridden by WORKING_DIRECTORY property
std::string Directory;
std::string DirectoryRaw;
// Original directory of test creation
std::string CTestDirectory;
std::vector<std::string> Args;
std::vector<std::string> RequiredFiles;
std::string RequiredFilesRaw;
std::vector<std::string> Depends;
std::string DependsRaw;
std::vector<std::string> AttachedFiles;
std::string AttachedFilesRaw;
std::vector<std::string> AttachOnFail;
std::string AttachOnFailRaw;
std::vector<std::pair<cmsys::RegularExpression, std::string>>
ErrorRegularExpressions;
std::string ErrorRegularExpressionsRaw;
std::vector<std::pair<cmsys::RegularExpression, std::string>>
RequiredRegularExpressions;
std::string RequiredRegularExpressionsRaw;
std::vector<std::pair<cmsys::RegularExpression, std::string>>
SkipRegularExpressions;
std::string SkipRegularExpressionsRaw;
std::vector<std::pair<cmsys::RegularExpression, std::string>>
TimeoutRegularExpressions;
std::string TimeoutRegularExpressionsRaw;
std::map<std::string, std::string> Measurements;
std::string MeasurementsRaw;
std::map<std::string, std::string> CustomProperties;
std::unordered_map<std::string, std::string> RawProperties;
bool IsInBasedOnREOptions = true;
bool WillFail = false;
std::string WillFailRaw;
bool Disabled = false;
std::string DisabledRaw;
float Cost = 0;
std::string CostRaw;
int PreviousRuns = 0;
bool RunSerial = false;
std::string RunSerialRaw;
cm::optional<cmDuration> Timeout;
std::string TimeoutRaw;
cm::optional<Signal> TimeoutSignal;
std::string TimeoutSignalRaw;
cm::optional<cmDuration> TimeoutGracePeriod;
std::string TimeoutGracePeriodRaw;
cmDuration AlternateTimeout;
int Index = 0;
// Requested number of process slots
int Processors = 1;
std::string ProcessorsRaw;
bool WantAffinity = false;
std::string WantAffinityRaw;
std::vector<size_t> Affinity;
// return code of test which will mark test as "not run"
int SkipReturnCode = -1;
std::string SkipReturnCodeRaw;
std::vector<std::string> Environment;
std::string EnvironmentRaw;
std::vector<std::string> EnvironmentModification;
std::string EnvironmentModificationRaw;
std::vector<std::string> Labels;
std::string LabelsRaw;
std::set<std::string> ProjectResources; // RESOURCE_LOCK
std::string ProjectResourcesRaw;
std::set<std::string> FixturesSetup;
std::string FixturesSetupRaw;
std::set<std::string> FixturesCleanup;
std::string FixturesCleanupRaw;
std::set<std::string> FixturesRequired;
std::string FixturesRequiredRaw;
std::set<std::string> RequireSuccessDepends;
std::vector<std::vector<cmCTestTestResourceRequirement>> ResourceGroups;
std::string ResourceGroupsRaw;
std::string GeneratedResourceSpecFile;
std::string GeneratedResourceSpecFileRaw;
std::string BuildDepends;
// Private test generator properties used to track backtraces
cmListFileBacktrace Backtrace;
+13
View File
@@ -134,6 +134,7 @@ struct cmCTest::Private
bool ShowOnly = false;
bool OutputAsJson = false;
int OutputAsJsonVersion = 1;
bool OutputAsJsonRaw = false;
// TODO: The ctest configuration should be a hierarchy of
// configuration option sources: command-line, script, ini file.
@@ -2355,6 +2356,13 @@ int cmCTest::Run(std::vector<std::string> const& args)
this->Impl->Quiet = true;
this->Impl->OutputAsJson = true;
this->Impl->OutputAsJsonVersion = 1;
} else if (format == "json-v1-raw") {
// Force quiet mode so the only output
// is the json object model.
this->Impl->Quiet = true;
this->Impl->OutputAsJson = true;
this->Impl->OutputAsJsonVersion = 1;
this->Impl->OutputAsJsonRaw = true;
} else if (format == "human") {
} else if (!format.empty()) {
cmSystemTools::Error(
@@ -3104,6 +3112,11 @@ int cmCTest::GetOutputAsJsonVersion()
return this->Impl->OutputAsJsonVersion;
}
bool cmCTest::GetOutputAsJsonRaw() const
{
return this->Impl->OutputAsJsonRaw;
}
bool cmCTest::ShouldUseHTTP10() const
{
return this->Impl->UseHTTP10;
+2
View File
@@ -183,6 +183,8 @@ public:
int GetOutputAsJsonVersion();
bool GetOutputAsJsonRaw() const;
bool ShouldUseHTTP10() const;
bool ShouldPrintLabels() const;
+2 -1
View File
@@ -60,7 +60,8 @@ cmDocumentationEntry const cmDocumentationOptions[] = {
{ "-N,--show-only[=format]",
"Disable actual execution of tests. The optional 'format' defines the "
"format of the test information and can be 'human' for the current text "
"format or 'json-v1' for json format. Defaults to 'human'." },
"format, 'json-v1' for json format, or 'json-v1-raw' where the json "
"format stores the raw test property values. Defaults to 'human'." },
{ "-L <regex>, --label-regex <regex>",
"Run tests with labels matching regular expression. "
"With multiple -L, run tests where each "
@@ -554,6 +554,7 @@ function(run_ShowOnly)
add_test(ShowOnly \"${CMAKE_COMMAND}\" -E echo)
set_tests_properties(ShowOnly PROPERTIES
GENERATED_RESOURCE_SPEC_FILE \"/Path/Does/Not/Exist\"
LABELS TestLabel
RESOURCE_GROUPS \"2,threads:2,gpus:4;gpus:2,threads:4\"
REQUIRED_FILES RequiredFileDoesNotExist
_BACKTRACE_TRIPLES \"file1;1;add_test;file0;;\"
@@ -564,11 +565,19 @@ function(run_ShowOnly)
USER_DEFINED_A \"User defined property A value\"
USER_DEFINED_B \"User defined property B value\"
)
set_tests_properties(ShowOnly PROPERTIES
REQUIRED_FILES AnotherRequiredFileDoesNotExist
)
set_directory_properties(PROPERTIES
LABELS DirectoryLabel
)
add_test(ShowOnlyNotAvailable NOT_AVAILABLE)
")
run_cmake_command(show-only_human ${CMAKE_CTEST_COMMAND} --show-only=human)
run_cmake_command(show-only_bad ${CMAKE_CTEST_COMMAND} --show-only=bad)
run_cmake_command(show-only_json-v1 ${CMAKE_CTEST_COMMAND} --show-only=json-v1)
run_cmake_command(show-only_json-v1-raw
${CMAKE_CTEST_COMMAND} --show-only=json-v1-raw)
endfunction()
run_ShowOnly()
@@ -0,0 +1 @@
show_only_json_check_python(1-raw)
@@ -0,0 +1,193 @@
import sys
from show_only_json_check import *
def check_kind(k):
assert is_string(k)
assert k == "ctestInfo"
def check_version(v):
assert is_dict(v)
assert sorted(v.keys()) == ["major", "minor"]
assert is_int(v["major"])
assert is_int(v["minor"])
assert v["major"] == 1
assert v["minor"] == 0
def check_backtracegraph(b):
assert is_dict(b)
assert sorted(b.keys()) == ["commands", "files", "nodes"]
check_backtracegraph_commands(b["commands"])
check_backtracegraph_files(b["files"])
check_backtracegraph_nodes(b["nodes"])
def check_backtracegraph_commands(c):
assert is_list(c)
assert len(c) == 1
assert is_string(c[0])
assert c[0] == "add_test"
def check_backtracegraph_files(f):
assert is_list(f)
assert len(f) == 2
assert is_string(f[0])
assert is_string(f[1])
assert f[0] == "file1"
assert f[1] == "file0"
def check_backtracegraph_nodes(n):
assert is_list(n)
assert len(n) == 2
node = n[0]
assert is_dict(node)
assert sorted(node.keys()) == ["file"]
assert is_int(node["file"])
assert node["file"] == 1
node = n[1]
assert is_dict(node)
assert sorted(node.keys()) == ["command", "file", "line", "parent"]
assert is_int(node["command"])
assert is_int(node["file"])
assert is_int(node["line"])
assert is_int(node["parent"])
assert node["command"] == 0
assert node["file"] == 0
assert node["line"] == 1
assert node["parent"] == 0
def check_command(c):
assert is_list(c)
assert len(c) == 3
assert is_string(c[0])
check_re(c[0], r"/cmake(\.exe)?$")
assert is_string(c[1])
assert c[1] == "-E"
assert is_string(c[2])
assert c[2] == "echo"
def check_generated_resource_spec_file_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "GENERATED_RESOURCE_SPEC_FILE"
assert p["value"] == "/Path/Does/Not/Exist"
def check_labels_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "LABELS"
assert p["value"] == "TestLabel;DirectoryLabel"
def check_reqfiles_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "REQUIRED_FILES"
assert p["value"] == \
"RequiredFileDoesNotExist;AnotherRequiredFileDoesNotExist"
def check_timeout_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "TIMEOUT"
assert p["value"] == "1234.5"
def check_timeout_signal_name_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "TIMEOUT_SIGNAL_NAME"
assert p["value"] == "SIGINT"
def check_timeout_signal_grace_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "TIMEOUT_SIGNAL_GRACE_PERIOD"
assert p["value"] == "2.1"
def check_willfail_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "WILL_FAIL"
assert p["value"] == "true"
def check_resource_groups_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "RESOURCE_GROUPS"
assert p["value"] == "2,threads:2,gpus:4;gpus:2,threads:4"
def check_workingdir_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "WORKING_DIRECTORY"
assert p["value"].endswith("Tests/RunCMake/CTestCommandLine/ShowOnly")
def check_defined_properties(p_list):
for property_id, p in zip(["A", "B"], p_list):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_string(p["value"])
assert p["name"] == "USER_DEFINED_" + property_id
assert p["value"] == "User defined property " + property_id + " value"
def check_properties(p):
assert is_list(p)
if sys.platform in ("win32"):
assert len(p) == 9
check_generated_resource_spec_file_property(p[0])
check_labels_property(p[1])
check_resource_groups_property(p[2])
check_reqfiles_property(p[3])
check_timeout_property(p[4])
check_willfail_property(p[5])
check_workingdir_property(p[6])
check_defined_properties(p[7:9])
else:
assert len(p) == 11
check_generated_resource_spec_file_property(p[0])
check_labels_property(p[1])
check_resource_groups_property(p[2])
check_reqfiles_property(p[3])
check_timeout_property(p[4])
check_timeout_signal_name_property(p[5])
check_timeout_signal_grace_property(p[6])
check_willfail_property(p[7])
check_workingdir_property(p[8])
check_defined_properties(p[9:11])
def check_tests(t):
assert is_list(t)
assert len(t) == 1
test = t[0]
assert is_dict(test)
assert sorted(test.keys()) == ["backtrace", "command", "name", "properties"]
assert is_int(test["backtrace"])
assert test["backtrace"] == 1
check_command(test["command"])
assert is_string(test["name"])
assert test["name"] == "ShowOnly"
check_properties(test["properties"])
assert is_dict(ctest_json)
assert sorted(ctest_json.keys()) == ["backtraceGraph", "kind", "tests", "version"]
check_backtracegraph(ctest_json["backtraceGraph"])
check_kind(ctest_json["kind"])
check_version(ctest_json["version"])
check_tests(ctest_json["tests"])
@@ -73,14 +73,25 @@ def check_generated_resource_spec_file_property(p):
assert p["name"] == "GENERATED_RESOURCE_SPEC_FILE"
assert p["value"] == "/Path/Does/Not/Exist"
def check_labels_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_list(p["value"])
assert p["name"] == "LABELS"
assert len(p["value"]) == 2
assert p["value"][0] == "DirectoryLabel"
assert p["value"][1] == "TestLabel"
def check_reqfiles_property(p):
assert is_dict(p)
assert sorted(p.keys()) == ["name", "value"]
assert is_string(p["name"])
assert is_list(p["value"])
assert p["name"] == "REQUIRED_FILES"
assert len(p["value"]) == 1
assert len(p["value"]) == 2
assert p["value"][0] == "RequiredFileDoesNotExist"
assert p["value"][1] == "AnotherRequiredFileDoesNotExist"
def check_timeout_property(p):
assert is_dict(p)
@@ -190,25 +201,27 @@ def check_defined_properties(p_list):
def check_properties(p):
assert is_list(p)
if sys.platform in ("win32"):
assert len(p) == 8
assert len(p) == 9
check_generated_resource_spec_file_property(p[0])
check_resource_groups_property(p[1])
check_reqfiles_property(p[2])
check_timeout_property(p[3])
check_willfail_property(p[4])
check_workingdir_property(p[5])
check_defined_properties(p[6:7])
check_labels_property(p[1])
check_resource_groups_property(p[2])
check_reqfiles_property(p[3])
check_timeout_property(p[4])
check_willfail_property(p[5])
check_workingdir_property(p[6])
check_defined_properties(p[7:9])
else:
assert len(p) == 10
assert len(p) == 11
check_generated_resource_spec_file_property(p[0])
check_resource_groups_property(p[1])
check_reqfiles_property(p[2])
check_timeout_property(p[3])
check_timeout_signal_name_property(p[4])
check_timeout_signal_grace_property(p[5])
check_willfail_property(p[6])
check_workingdir_property(p[7])
check_defined_properties(p[8:9])
check_labels_property(p[1])
check_resource_groups_property(p[2])
check_reqfiles_property(p[3])
check_timeout_property(p[4])
check_timeout_signal_name_property(p[5])
check_timeout_signal_grace_property(p[6])
check_willfail_property(p[7])
check_workingdir_property(p[8])
check_defined_properties(p[9:11])
def check_tests(t):
assert is_list(t)