Coverage Report

Created: 2026-04-29 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmDiscoverTestsCommand.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmDiscoverTestsCommand.h"
4
5
#include <cstddef>
6
#include <ostream>
7
#include <utility>
8
#include <vector>
9
10
#include <cm/memory>
11
#include <cmext/string_view>
12
13
#include "cmArgumentParser.h"
14
#include "cmArgumentParserTypes.h"
15
#include "cmExecutionStatus.h"
16
#include "cmGeneratorExpression.h"
17
#include "cmListFileCache.h"
18
#include "cmLocalGenerator.h"
19
#include "cmMakefile.h"
20
#include "cmScriptGenerator.h"
21
#include "cmTestDiscovery.h"
22
#include "cmTestGenerator.h"
23
24
namespace {
25
26
struct Arguments : cmTestDiscoveryArgs
27
{
28
  bool CommandExpandLists = false;
29
  ArgumentParser::MaybeEmpty<std::vector<std::string>> Configurations;
30
};
31
32
class DiscoveryGenerator : public cmTestGenerator
33
{
34
public:
35
  DiscoveryGenerator(Arguments arguments, cmListFileBacktrace backtrace)
36
0
    : cmTestGenerator(nullptr, arguments.Configurations)
37
0
    , Args{ std::move(arguments) }
38
0
    , Backtrace{ std::move(backtrace) }
39
0
  {
40
0
  }
41
42
private:
43
  void GenerateProperties(std::ostream& os, Indent indent,
44
                          std::vector<std::string> const& props,
45
                          std::string const& config, cmGeneratorExpression& ge)
46
0
  {
47
0
    for (std::size_t i = 0; i < props.size(); i += 2) {
48
0
      os << '\n'
49
0
         << indent << Quote(props[i]) << ' '
50
0
         << Quote(ge.Parse(props[i + 1])->Evaluate(this->LG, config));
51
0
    }
52
0
  }
53
54
  void GenerateScriptForConfig(std::ostream& os, std::string const& config,
55
                               Indent indent) override
56
0
  {
57
    // Set up generator expression evaluation context.
58
0
    cmGeneratorExpression ge(*this->LG->GetMakefile()->GetCMakeInstance(),
59
0
                             this->Backtrace);
60
61
0
    auto const in = indent.Next();
62
0
    os << indent << "discover_tests(COMMAND ";
63
0
    this->GenerateCommand(os, this->Args.Command, config,
64
0
                          this->Args.CommandExpandLists, ge);
65
0
    os << '\n' << in << "DISCOVERY_ARGS";
66
0
    for (auto const& arg : this->Args.DiscoveryArgs) {
67
0
      os << ' ' << Quote(arg);
68
0
    }
69
0
    os << '\n' << in << "DISCOVERY_MATCH " << Quote(this->Args.DiscoveryMatch);
70
0
    if (!this->Args.DiscoveryProperties.empty()) {
71
0
      os << '\n' << in << "DISCOVERY_PROPERTIES";
72
0
      this->GenerateProperties(os, in.Next(), this->Args.DiscoveryProperties,
73
0
                               config, ge);
74
0
    }
75
0
    os << '\n' << in << "TEST_NAME " << Quote(this->Args.TestName);
76
0
    os << '\n' << in << "TEST_ARGS";
77
0
    for (auto const& arg : this->Args.TestArgs) {
78
0
      os << ' ' << Quote(arg);
79
0
    }
80
0
    os << '\n' << in << "TEST_PROPERTIES";
81
0
    this->GenerateProperties(os, in.Next(), this->Args.TestProperties, config,
82
0
                             ge);
83
0
    os << '\n' << in.Next();
84
0
    this->GenerateBacktrace(os, this->Backtrace);
85
0
    os << '\n' << in << ")\n";
86
0
  }
87
88
  Arguments Args;
89
  cmListFileBacktrace Backtrace;
90
};
91
92
} // namespace
93
94
bool cmDiscoverTestsCommand(std::vector<std::string> const& args,
95
                            cmExecutionStatus& status)
96
0
{
97
0
  static auto const parser =
98
0
    cmArgumentParser<Arguments>{ cmTestDiscoveryParser<Arguments>() }
99
0
      .Bind("COMMAND_EXPAND_LISTS"_s, &Arguments::CommandExpandLists)
100
0
      .Bind("CONFIGURATIONS"_s, &Arguments::Configurations);
101
102
0
  auto unparsed = std::vector<std::string>{};
103
0
  Arguments arguments = parser.Parse(args, &unparsed);
104
0
  if (arguments.MaybeReportError(status.GetMakefile())) {
105
0
    return true;
106
0
  }
107
108
0
  if (!unparsed.empty()) {
109
0
    status.SetError(" given unknown argument \"" + unparsed.front() + "\".");
110
0
    return false;
111
0
  }
112
113
0
  cmMakefile& mf = status.GetMakefile();
114
0
  mf.AddTestGenerator(cm::make_unique<DiscoveryGenerator>(std::move(arguments),
115
0
                                                          mf.GetBacktrace()));
116
0
  return true;
117
0
}