mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-10-08 23:44:00 +03:00
discover_tests: Add CTest command implementation
This commit is contained in:
1 parent
d718a979b7
commit
3f1fce6b48
5 files changed
+245
No files matched your search
@@ -1143,6 +1143,7 @@ add_library(
|
||||
CTest/cmCTestCoverageCommand.cxx
|
||||
CTest/cmCTestCoverageHandler.cxx
|
||||
CTest/cmCTestCurl.cxx
|
||||
CTest/cmCTestDiscoverTests.cxx
|
||||
CTest/cmParseMumpsCoverage.cxx
|
||||
CTest/cmParseCacheCoverage.cxx
|
||||
CTest/cmParseGTMCoverage.cxx
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include "cmCTestDiscoverTests.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cmsys/RegularExpression.hxx>
|
||||
|
||||
#include "cmArgumentParserTypes.h"
|
||||
#include "cmCTestTestHandler.h"
|
||||
#include "cmDuration.h"
|
||||
#include "cmEnvironment.h"
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmList.h"
|
||||
#include "cmProcessOutput.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmTestDiscovery.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct DiscoveryProperties
|
||||
{
|
||||
DiscoveryProperties(std::vector<std::string> const& props);
|
||||
|
||||
std::vector<std::string> Environment;
|
||||
std::vector<std::string> EnvironmentModification;
|
||||
cmDuration Timeout = cmDuration(5.0);
|
||||
std::string WorkingDirectory;
|
||||
};
|
||||
|
||||
DiscoveryProperties::DiscoveryProperties(std::vector<std::string> const& props)
|
||||
{
|
||||
for (std::size_t i = 0; i < props.size(); i += 2) {
|
||||
auto const& key = props[i];
|
||||
auto const& val = props[i + 1];
|
||||
if (key == "ENVIRONMENT") {
|
||||
cmExpandList(val, this->Environment);
|
||||
} else if (key == "ENVIRONMENT_MODIFICATION") {
|
||||
cmExpandList(val, this->EnvironmentModification);
|
||||
} else if (key == "TIMEOUT") {
|
||||
this->Timeout = cmDuration(atof(val.c_str()));
|
||||
} else if (key == "WORKING_DIRECTORY") {
|
||||
this->WorkingDirectory = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string AddAnchors(std::string str)
|
||||
{
|
||||
if (str.empty() || str.front() != '^') {
|
||||
str.insert(str.begin(), '^');
|
||||
}
|
||||
if (str.size() < 2 || str.back() != '$') {
|
||||
str.push_back('$');
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
class RegexReplacer
|
||||
{
|
||||
public:
|
||||
RegexReplacer(cmsys::RegularExpression& regex)
|
||||
: RegEx(regex)
|
||||
{
|
||||
}
|
||||
|
||||
std::string operator()(std::string str)
|
||||
{
|
||||
for (int i = 0; i <= this->RegEx.num_groups(); ++i) {
|
||||
cmsys::SystemTools::ReplaceString(str, cmStrCat('\\', i),
|
||||
this->RegEx.match(i));
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private:
|
||||
cmsys::RegularExpression& RegEx;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool cmCTestDiscoverTests(cmTestDiscoveryArgs const& args,
|
||||
cmCTestTestHandler* handler,
|
||||
cmExecutionStatus& status)
|
||||
{
|
||||
cmsys::RegularExpression re;
|
||||
if (!re.compile(AddAnchors(args.DiscoveryMatch))) {
|
||||
std::string e = "DISCOVERY_MATCH failed to compile regex \"" +
|
||||
args.DiscoveryMatch + "\".";
|
||||
status.SetError(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const props = DiscoveryProperties{ args.DiscoveryProperties };
|
||||
|
||||
auto env = cmEnvironment{ cmSystemTools::GetEnvironmentVariables() };
|
||||
env.Update(props.Environment);
|
||||
if (!props.EnvironmentModification.empty()) {
|
||||
auto diff = cmEnvironmentModification{};
|
||||
if (!diff.Add(props.EnvironmentModification)) {
|
||||
return false;
|
||||
}
|
||||
diff.ApplyTo(env);
|
||||
}
|
||||
|
||||
auto runCommand = std::vector<std::string>(args.Command);
|
||||
runCommand.reserve(runCommand.size() + args.DiscoveryArgs.size());
|
||||
std::copy(args.DiscoveryArgs.begin(), args.DiscoveryArgs.end(),
|
||||
std::back_inserter(runCommand));
|
||||
|
||||
std::string stdOut;
|
||||
std::string stdErr;
|
||||
bool const res = cmSystemTools::RunSingleCommand(
|
||||
runCommand, &stdOut, &stdErr, nullptr, props.WorkingDirectory.c_str(),
|
||||
cmSystemTools::OUTPUT_NONE, props.Timeout, cmProcessOutput::Auto,
|
||||
env.GetVariables());
|
||||
if (!res) {
|
||||
status.SetError(cmStrCat(" failed to run command: ",
|
||||
cmSystemTools::PrintSingleCommand(runCommand),
|
||||
"\n", stdErr));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto replace = RegexReplacer{ re };
|
||||
|
||||
std::vector<std::string> lines;
|
||||
cmSystemTools::Split(stdOut, lines);
|
||||
for (auto const& line : lines) {
|
||||
if (!re.find(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const testName = replace(args.TestName);
|
||||
auto testArgs = std::vector<std::string>{ testName };
|
||||
testArgs.reserve(1 + args.Command.size() + args.TestArgs.size());
|
||||
std::copy(args.Command.begin(), args.Command.end(),
|
||||
std::back_inserter(testArgs));
|
||||
std::transform(args.TestArgs.begin(), args.TestArgs.end(),
|
||||
std::back_inserter(testArgs), replace);
|
||||
|
||||
if (!handler->AddTest(testArgs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto testProperties = std::vector<std::string>{ testName, "PROPERTIES" };
|
||||
testProperties.reserve(2 + args.TestProperties.size());
|
||||
for (std::size_t i = 0; i < args.TestProperties.size(); i += 2) {
|
||||
testProperties.push_back(args.TestProperties[i]);
|
||||
testProperties.push_back(replace(args.TestProperties[i + 1]));
|
||||
}
|
||||
if (!handler->SetTestsProperties(testProperties)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
struct cmTestDiscoveryArgs;
|
||||
class cmCTestTestHandler;
|
||||
class cmExecutionStatus;
|
||||
|
||||
bool cmCTestDiscoverTests(cmTestDiscoveryArgs const& args,
|
||||
cmCTestTestHandler* handler,
|
||||
cmExecutionStatus& status);
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <ratio>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -33,7 +34,9 @@
|
||||
|
||||
#include "cm_utf8.h"
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
#include "cmCTest.h"
|
||||
#include "cmCTestDiscoverTests.h"
|
||||
#include "cmCTestMultiProcessHandler.h"
|
||||
#include "cmCTestResourceGroupsLexerHelper.h"
|
||||
#include "cmCTestTestMeasurementXMLParser.h"
|
||||
@@ -49,6 +52,7 @@
|
||||
#include "cmStateSnapshot.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmTestDiscovery.h"
|
||||
#include "cmTimestamp.h"
|
||||
#include "cmValue.h"
|
||||
#include "cmWorkingDirectory.h"
|
||||
@@ -184,6 +188,34 @@ bool cmCTestAddTestCommand::InitialPass(std::vector<std::string> const& args,
|
||||
return this->TestHandler->AddTest(args);
|
||||
}
|
||||
|
||||
class cmCTestDiscoverTestsCommand : public cmCTestCommand
|
||||
{
|
||||
public:
|
||||
using cmCTestCommand::cmCTestCommand;
|
||||
bool InitialPass(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status) override;
|
||||
};
|
||||
|
||||
bool cmCTestDiscoverTestsCommand::InitialPass(
|
||||
std::vector<std::string> const& args, cmExecutionStatus& status)
|
||||
{
|
||||
using Arguments = cmTestDiscoveryArgs;
|
||||
static auto const parser = cmTestDiscoveryParser<Arguments>();
|
||||
|
||||
auto unparsed = std::vector<std::string>{};
|
||||
Arguments const arguments = parser.Parse(args, &unparsed);
|
||||
if (arguments.MaybeReportError(status.GetMakefile())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!unparsed.empty()) {
|
||||
status.SetError(" given unknown argument \"" + unparsed.front() + "\".");
|
||||
return false;
|
||||
}
|
||||
|
||||
return cmCTestDiscoverTests(arguments, this->TestHandler, status);
|
||||
}
|
||||
|
||||
class cmCTestSetTestsPropertiesCommand : public cmCTestCommand
|
||||
{
|
||||
public:
|
||||
@@ -1772,6 +1804,10 @@ bool cmCTestTestHandler::GetListOfTests()
|
||||
// Add handler for ADD_TEST
|
||||
cm.GetState()->AddBuiltinCommand("add_test", cmCTestAddTestCommand(this));
|
||||
|
||||
// Add handler for DISCOVER_TESTS
|
||||
cm.GetState()->AddBuiltinCommand("discover_tests",
|
||||
cmCTestDiscoverTestsCommand(this));
|
||||
|
||||
// Add handler for SUBDIRS
|
||||
cm.GetState()->AddBuiltinCommand("subdirs", cmCTestSubdirCommand);
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
|
||||
struct cmTestDiscoveryArgs : ArgumentParser::ParseResult
|
||||
{
|
||||
ArgumentParser::NonEmpty<std::vector<std::string>> Command;
|
||||
ArgumentParser::NonEmpty<std::vector<std::string>> DiscoveryArgs;
|
||||
ArgumentParser::NonEmpty<std::string> DiscoveryMatch;
|
||||
ArgumentParser::MaybeEmpty<std::vector<std::string>> DiscoveryProperties;
|
||||
ArgumentParser::NonEmpty<std::string> TestName;
|
||||
ArgumentParser::NonEmpty<std::vector<std::string>> TestArgs;
|
||||
ArgumentParser::MaybeEmpty<std::vector<std::string>> TestProperties;
|
||||
};
|
||||
|
||||
template <typename Args>
|
||||
auto cmTestDiscoveryParser() -> cmArgumentParser<Args>
|
||||
{
|
||||
static_assert(std::is_base_of<cmTestDiscoveryArgs, Args>::value, "");
|
||||
return cmArgumentParser<Args>{}
|
||||
.Bind("COMMAND"_s, &Args::Command)
|
||||
.Bind("DISCOVERY_ARGS"_s, &Args::DiscoveryArgs)
|
||||
.Bind("DISCOVERY_MATCH"_s, &Args::DiscoveryMatch)
|
||||
.Bind("DISCOVERY_PROPERTIES"_s, &Args::DiscoveryProperties)
|
||||
.Bind("TEST_NAME"_s, &Args::TestName)
|
||||
.Bind("TEST_ARGS"_s, &Args::TestArgs)
|
||||
.Bind("TEST_PROPERTIES"_s, &Args::TestProperties);
|
||||
}
|
||||
Reference in new issue
Block a user