Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmAddTestCommand.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 "cmAddTestCommand.h"
4
5
#include <algorithm>
6
7
#include <cm/memory>
8
9
#include "cmExecutionStatus.h"
10
#include "cmMakefile.h"
11
#include "cmPolicies.h"
12
#include "cmStringAlgorithms.h"
13
#include "cmTest.h"
14
#include "cmTestGenerator.h"
15
16
static std::string const keywordCMP0178 = "__CMP0178";
17
18
static bool cmAddTestCommandHandleNameMode(
19
  std::vector<std::string> const& args, cmExecutionStatus& status);
20
21
bool cmAddTestCommand(std::vector<std::string> const& args,
22
                      cmExecutionStatus& status)
23
0
{
24
0
  if (!args.empty() && args[0] == "NAME") {
25
0
    return cmAddTestCommandHandleNameMode(args, status);
26
0
  }
27
28
  // First argument is the name of the test Second argument is the name of
29
  // the executable to run (a target or external program) Remaining arguments
30
  // are the arguments to pass to the executable
31
0
  if (args.size() < 2) {
32
0
    status.SetError("called with incorrect number of arguments");
33
0
    return false;
34
0
  }
35
36
0
  cmMakefile& mf = status.GetMakefile();
37
0
  cmPolicies::PolicyStatus cmp0178;
38
39
  // If the __CMP0178 keyword is present, it is always at the end
40
0
  auto endOfCommandIter =
41
0
    std::find(args.begin() + 2, args.end(), keywordCMP0178);
42
0
  if (endOfCommandIter != args.end()) {
43
0
    auto cmp0178Iter = endOfCommandIter + 1;
44
0
    if (cmp0178Iter == args.end()) {
45
0
      status.SetError(cmStrCat(keywordCMP0178, " keyword missing value"));
46
0
      return false;
47
0
    }
48
0
    if (*cmp0178Iter == "NEW") {
49
0
      cmp0178 = cmPolicies::PolicyStatus::NEW;
50
0
    } else if (*cmp0178Iter == "OLD") {
51
0
      cmp0178 = cmPolicies::PolicyStatus::OLD;
52
0
    } else {
53
0
      cmp0178 = cmPolicies::PolicyStatus::WARN;
54
0
    }
55
0
  } else {
56
0
    cmp0178 = mf.GetPolicyStatus(cmPolicies::CMP0178);
57
0
  }
58
59
  // Collect the command with arguments.
60
0
  std::vector<std::string> command(args.begin() + 1, endOfCommandIter);
61
62
  // Create the test but add a generator only the first time it is
63
  // seen.  This preserves behavior from before test generators.
64
0
  cmTest* test = mf.GetTest(args[0]);
65
0
  if (test) {
66
    // If the test was already added by a new-style signature do not
67
    // allow it to be duplicated.
68
0
    if (!test->GetOldStyle()) {
69
0
      status.SetError(cmStrCat(" given test name \"", args[0],
70
0
                               "\" which already exists in this directory."));
71
0
      return false;
72
0
    }
73
0
  } else {
74
0
    test = mf.CreateTest(args[0]);
75
0
    test->SetOldStyle(true);
76
0
    test->SetCMP0178(cmp0178);
77
0
    mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test));
78
0
  }
79
0
  test->SetCommand(command);
80
81
0
  return true;
82
0
}
83
84
bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
85
                                    cmExecutionStatus& status)
86
0
{
87
0
  cmMakefile& mf = status.GetMakefile();
88
89
0
  std::string name;
90
0
  std::vector<std::string> configurations;
91
0
  std::string working_directory;
92
0
  std::vector<std::string> command;
93
0
  bool command_expand_lists = false;
94
0
  cmPolicies::PolicyStatus cmp0178 = mf.GetPolicyStatus(cmPolicies::CMP0178);
95
96
  // Read the arguments.
97
0
  enum Doing
98
0
  {
99
0
    DoingName,
100
0
    DoingCommand,
101
0
    DoingConfigs,
102
0
    DoingWorkingDirectory,
103
0
    DoingCmp0178,
104
0
    DoingNone
105
0
  };
106
0
  Doing doing = DoingName;
107
0
  for (unsigned int i = 1; i < args.size(); ++i) {
108
0
    if (args[i] == "COMMAND") {
109
0
      if (!command.empty()) {
110
0
        status.SetError(" may be given at most one COMMAND.");
111
0
        return false;
112
0
      }
113
0
      doing = DoingCommand;
114
0
    } else if (args[i] == "CONFIGURATIONS") {
115
0
      if (!configurations.empty()) {
116
0
        status.SetError(" may be given at most one set of CONFIGURATIONS.");
117
0
        return false;
118
0
      }
119
0
      doing = DoingConfigs;
120
0
    } else if (args[i] == "WORKING_DIRECTORY") {
121
0
      if (!working_directory.empty()) {
122
0
        status.SetError(" may be given at most one WORKING_DIRECTORY.");
123
0
        return false;
124
0
      }
125
0
      doing = DoingWorkingDirectory;
126
0
    } else if (args[i] == keywordCMP0178) {
127
0
      doing = DoingCmp0178;
128
0
    } else if (args[i] == "COMMAND_EXPAND_LISTS") {
129
0
      if (command_expand_lists) {
130
0
        status.SetError(" may be given at most one COMMAND_EXPAND_LISTS.");
131
0
        return false;
132
0
      }
133
0
      command_expand_lists = true;
134
0
      doing = DoingNone;
135
0
    } else if (doing == DoingName) {
136
0
      name = args[i];
137
0
      doing = DoingNone;
138
0
    } else if (doing == DoingCommand) {
139
0
      command.push_back(args[i]);
140
0
    } else if (doing == DoingConfigs) {
141
0
      configurations.push_back(args[i]);
142
0
    } else if (doing == DoingWorkingDirectory) {
143
0
      working_directory = args[i];
144
0
      doing = DoingNone;
145
0
    } else if (doing == DoingCmp0178) {
146
0
      if (args[i] == "NEW") {
147
0
        cmp0178 = cmPolicies::PolicyStatus::NEW;
148
0
      } else if (args[i] == "OLD") {
149
0
        cmp0178 = cmPolicies::PolicyStatus::OLD;
150
0
      } else {
151
0
        cmp0178 = cmPolicies::PolicyStatus::WARN;
152
0
      }
153
0
      doing = DoingNone;
154
0
    } else {
155
0
      status.SetError(cmStrCat(" given unknown argument:\n  ", args[i], '\n'));
156
0
      return false;
157
0
    }
158
0
  }
159
160
  // Require a test name.
161
0
  if (name.empty()) {
162
0
    status.SetError(" must be given non-empty NAME.");
163
0
    return false;
164
0
  }
165
166
  // Require a command.
167
0
  if (command.empty()) {
168
0
    status.SetError(" must be given non-empty COMMAND.");
169
0
    return false;
170
0
  }
171
172
  // Require a unique test name within the directory.
173
0
  if (mf.GetTest(name)) {
174
0
    status.SetError(cmStrCat(" given test NAME \"", name,
175
0
                             "\" which already exists in this directory."));
176
0
    return false;
177
0
  }
178
179
  // Add the test.
180
0
  cmTest* test = mf.CreateTest(name);
181
0
  test->SetOldStyle(false);
182
0
  test->SetCMP0178(cmp0178);
183
0
  test->SetCommand(command);
184
0
  if (!working_directory.empty()) {
185
0
    test->SetProperty("WORKING_DIRECTORY", working_directory);
186
0
  }
187
0
  test->SetCommandExpandLists(command_expand_lists);
188
0
  mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test, configurations));
189
190
0
  return true;
191
0
}