1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmAddTestCommand.h"
4
5 #include <cm/memory>
6
7 #include "cmExecutionStatus.h"
8 #include "cmMakefile.h"
9 #include "cmStringAlgorithms.h"
10 #include "cmTest.h"
11 #include "cmTestGenerator.h"
12
13 static bool cmAddTestCommandHandleNameMode(
14 std::vector<std::string> const& args, cmExecutionStatus& status);
15
cmAddTestCommand(std::vector<std::string> const & args,cmExecutionStatus & status)16 bool cmAddTestCommand(std::vector<std::string> const& args,
17 cmExecutionStatus& status)
18 {
19 if (!args.empty() && args[0] == "NAME") {
20 return cmAddTestCommandHandleNameMode(args, status);
21 }
22
23 // First argument is the name of the test Second argument is the name of
24 // the executable to run (a target or external program) Remaining arguments
25 // are the arguments to pass to the executable
26 if (args.size() < 2) {
27 status.SetError("called with incorrect number of arguments");
28 return false;
29 }
30
31 cmMakefile& mf = status.GetMakefile();
32 // Collect the command with arguments.
33 std::vector<std::string> command(args.begin() + 1, args.end());
34
35 // Create the test but add a generator only the first time it is
36 // seen. This preserves behavior from before test generators.
37 cmTest* test = mf.GetTest(args[0]);
38 if (test) {
39 // If the test was already added by a new-style signature do not
40 // allow it to be duplicated.
41 if (!test->GetOldStyle()) {
42 status.SetError(cmStrCat(" given test name \"", args[0],
43 "\" which already exists in this directory."));
44 return false;
45 }
46 } else {
47 test = mf.CreateTest(args[0]);
48 test->SetOldStyle(true);
49 mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test));
50 }
51 test->SetCommand(command);
52
53 return true;
54 }
55
cmAddTestCommandHandleNameMode(std::vector<std::string> const & args,cmExecutionStatus & status)56 bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args,
57 cmExecutionStatus& status)
58 {
59 std::string name;
60 std::vector<std::string> configurations;
61 std::string working_directory;
62 std::vector<std::string> command;
63 bool command_expand_lists = false;
64
65 // Read the arguments.
66 enum Doing
67 {
68 DoingName,
69 DoingCommand,
70 DoingConfigs,
71 DoingWorkingDirectory,
72 DoingNone
73 };
74 Doing doing = DoingName;
75 for (unsigned int i = 1; i < args.size(); ++i) {
76 if (args[i] == "COMMAND") {
77 if (!command.empty()) {
78 status.SetError(" may be given at most one COMMAND.");
79 return false;
80 }
81 doing = DoingCommand;
82 } else if (args[i] == "CONFIGURATIONS") {
83 if (!configurations.empty()) {
84 status.SetError(" may be given at most one set of CONFIGURATIONS.");
85 return false;
86 }
87 doing = DoingConfigs;
88 } else if (args[i] == "WORKING_DIRECTORY") {
89 if (!working_directory.empty()) {
90 status.SetError(" may be given at most one WORKING_DIRECTORY.");
91 return false;
92 }
93 doing = DoingWorkingDirectory;
94 } else if (args[i] == "COMMAND_EXPAND_LISTS") {
95 if (command_expand_lists) {
96 status.SetError(" may be given at most one COMMAND_EXPAND_LISTS.");
97 return false;
98 }
99 command_expand_lists = true;
100 doing = DoingNone;
101 } else if (doing == DoingName) {
102 name = args[i];
103 doing = DoingNone;
104 } else if (doing == DoingCommand) {
105 command.push_back(args[i]);
106 } else if (doing == DoingConfigs) {
107 configurations.push_back(args[i]);
108 } else if (doing == DoingWorkingDirectory) {
109 working_directory = args[i];
110 doing = DoingNone;
111 } else {
112 status.SetError(cmStrCat(" given unknown argument:\n ", args[i], "\n"));
113 return false;
114 }
115 }
116
117 // Require a test name.
118 if (name.empty()) {
119 status.SetError(" must be given non-empty NAME.");
120 return false;
121 }
122
123 // Require a command.
124 if (command.empty()) {
125 status.SetError(" must be given non-empty COMMAND.");
126 return false;
127 }
128
129 cmMakefile& mf = status.GetMakefile();
130
131 // Require a unique test name within the directory.
132 if (mf.GetTest(name)) {
133 status.SetError(cmStrCat(" given test NAME \"", name,
134 "\" which already exists in this directory."));
135 return false;
136 }
137
138 // Add the test.
139 cmTest* test = mf.CreateTest(name);
140 test->SetOldStyle(false);
141 test->SetCommand(command);
142 if (!working_directory.empty()) {
143 test->SetProperty("WORKING_DIRECTORY", working_directory);
144 }
145 test->SetCommandExpandLists(command_expand_lists);
146 mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test, configurations));
147
148 return true;
149 }
150