blob: 278a032f49d12025a6b7fee5d490a88dbf1b76f8 [file] [log] [blame] [edit]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#include "cmDiscoverTestsCommand.h"
#include <cstddef>
#include <ostream>
#include <utility>
#include <vector>
#include <cm/memory>
#include <cmext/string_view>
#include "cmArgumentParser.h"
#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
#include "cmGeneratorExpression.h"
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmScriptGenerator.h"
#include "cmTestDiscovery.h"
#include "cmTestGenerator.h"
namespace {
struct Arguments : cmTestDiscoveryArgs
{
bool CommandExpandLists = false;
ArgumentParser::MaybeEmpty<std::vector<std::string>> Configurations;
};
class DiscoveryGenerator : public cmTestGenerator
{
public:
DiscoveryGenerator(Arguments arguments, cmListFileBacktrace backtrace)
: cmTestGenerator(nullptr, arguments.Configurations)
, Args{ std::move(arguments) }
, Backtrace{ std::move(backtrace) }
{
}
private:
void GenerateProperties(std::ostream& os, Indent indent,
std::vector<std::string> const& props,
std::string const& config, cmGeneratorExpression& ge)
{
for (std::size_t i = 0; i < props.size(); i += 2) {
os << '\n'
<< indent << Quote(props[i]) << ' '
<< Quote(ge.Parse(props[i + 1])->Evaluate(this->LG, config));
}
}
void GenerateScriptForConfig(std::ostream& os, std::string const& config,
Indent indent) override
{
// Set up generator expression evaluation context.
cmGeneratorExpression ge(*this->LG->GetMakefile()->GetCMakeInstance(),
this->Backtrace);
auto const in = indent.Next();
os << indent << "discover_tests(COMMAND ";
this->GenerateCommand(os, this->Args.Command, config,
this->Args.CommandExpandLists, ge);
os << '\n' << in << "DISCOVERY_ARGS";
for (auto const& arg : this->Args.DiscoveryArgs) {
os << ' ' << Quote(arg);
}
os << '\n' << in << "DISCOVERY_MATCH " << Quote(this->Args.DiscoveryMatch);
if (!this->Args.DiscoveryProperties.empty()) {
os << '\n' << in << "DISCOVERY_PROPERTIES";
this->GenerateProperties(os, in.Next(), this->Args.DiscoveryProperties,
config, ge);
}
os << '\n' << in << "TEST_NAME " << Quote(this->Args.TestName);
os << '\n' << in << "TEST_ARGS";
for (auto const& arg : this->Args.TestArgs) {
os << ' ' << Quote(arg);
}
os << '\n' << in << "TEST_PROPERTIES";
this->GenerateProperties(os, in.Next(), this->Args.TestProperties, config,
ge);
os << '\n' << in.Next();
this->GenerateBacktrace(os, this->Backtrace);
os << '\n' << in << ")\n";
}
Arguments Args;
cmListFileBacktrace Backtrace;
};
} // namespace
bool cmDiscoverTestsCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
static auto const parser =
cmArgumentParser<Arguments>{ cmTestDiscoveryParser<Arguments>() }
.Bind("COMMAND_EXPAND_LISTS"_s, &Arguments::CommandExpandLists)
.Bind("CONFIGURATIONS"_s, &Arguments::Configurations);
auto unparsed = std::vector<std::string>{};
Arguments arguments = parser.Parse(args, &unparsed);
if (arguments.MaybeReportError(status.GetMakefile())) {
return true;
}
if (!unparsed.empty()) {
status.SetError(" given unknown argument \"" + unparsed.front() + "\".");
return false;
}
cmMakefile& mf = status.GetMakefile();
mf.AddTestGenerator(cm::make_unique<DiscoveryGenerator>(std::move(arguments),
mf.GetBacktrace()));
return true;
}