2a52d1abd09bb819f3afca5eb4cad1c12bdb7623
[platform/upstream/cmake.git] / Source / cmCreateTestSourceList.cxx
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 "cmCreateTestSourceList.h"
4
5 #include <algorithm>
6
7 #include "cmExecutionStatus.h"
8 #include "cmMakefile.h"
9 #include "cmSourceFile.h"
10 #include "cmStringAlgorithms.h"
11 #include "cmSystemTools.h"
12
13 bool cmCreateTestSourceList(std::vector<std::string> const& args,
14                             cmExecutionStatus& status)
15 {
16   if (args.size() < 3) {
17     status.SetError("called with wrong number of arguments.");
18     return false;
19   }
20
21   auto i = args.begin();
22   std::string extraInclude;
23   std::string function;
24   std::vector<std::string> tests;
25   // extract extra include and function ot
26   for (; i != args.end(); i++) {
27     if (*i == "EXTRA_INCLUDE") {
28       ++i;
29       if (i == args.end()) {
30         status.SetError("incorrect arguments to EXTRA_INCLUDE");
31         return false;
32       }
33       extraInclude = cmStrCat("#include \"", *i, "\"\n");
34     } else if (*i == "FUNCTION") {
35       ++i;
36       if (i == args.end()) {
37         status.SetError("incorrect arguments to FUNCTION");
38         return false;
39       }
40       function = cmStrCat(*i, "(&ac, &av);\n");
41     } else {
42       tests.push_back(*i);
43     }
44   }
45   i = tests.begin();
46
47   // Name of the source list
48
49   const char* sourceList = i->c_str();
50   ++i;
51
52   // Name of the test driver
53   // make sure they specified an extension
54   if (cmSystemTools::GetFilenameExtension(*i).size() < 2) {
55     status.SetError(
56       "You must specify a file extension for the test driver file.");
57     return false;
58   }
59   cmMakefile& mf = status.GetMakefile();
60   std::string driver = cmStrCat(mf.GetCurrentBinaryDirectory(), '/', *i);
61   ++i;
62
63   std::string configFile = cmSystemTools::GetCMakeRoot();
64
65   configFile += "/Templates/TestDriver.cxx.in";
66   // Create the test driver file
67
68   auto testsBegin = i;
69   std::vector<std::string> tests_func_name;
70
71   // The rest of the arguments consist of a list of test source files.
72   // Sadly, they can be in directories. Let's find a unique function
73   // name for the corresponding test, and push it to the tests_func_name
74   // list.
75   // For the moment:
76   //   - replace spaces ' ', ':' and '/' with underscores '_'
77   std::string forwardDeclareCode;
78   for (i = testsBegin; i != tests.end(); ++i) {
79     if (*i == "EXTRA_INCLUDE") {
80       break;
81     }
82     std::string func_name;
83     if (!cmSystemTools::GetFilenamePath(*i).empty()) {
84       func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
85         cmSystemTools::GetFilenameWithoutLastExtension(*i);
86     } else {
87       func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
88     }
89     cmSystemTools::ConvertToUnixSlashes(func_name);
90     std::replace(func_name.begin(), func_name.end(), ' ', '_');
91     std::replace(func_name.begin(), func_name.end(), '/', '_');
92     std::replace(func_name.begin(), func_name.end(), ':', '_');
93     bool already_declared =
94       std::find(tests_func_name.begin(), tests_func_name.end(), func_name) !=
95       tests_func_name.end();
96     tests_func_name.push_back(func_name);
97     if (!already_declared) {
98       forwardDeclareCode += "int ";
99       forwardDeclareCode += func_name;
100       forwardDeclareCode += "(int, char*[]);\n";
101     }
102   }
103
104   std::string functionMapCode;
105   std::vector<std::string>::iterator j;
106   for (i = testsBegin, j = tests_func_name.begin(); i != tests.end();
107        ++i, ++j) {
108     std::string func_name;
109     if (!cmSystemTools::GetFilenamePath(*i).empty()) {
110       func_name = cmSystemTools::GetFilenamePath(*i) + "/" +
111         cmSystemTools::GetFilenameWithoutLastExtension(*i);
112     } else {
113       func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
114     }
115     functionMapCode += "  {\n"
116                        "    \"";
117     functionMapCode += func_name;
118     functionMapCode += "\",\n"
119                        "    ";
120     functionMapCode += *j;
121     functionMapCode += "\n"
122                        "  },\n";
123   }
124   if (!extraInclude.empty()) {
125     mf.AddDefinition("CMAKE_TESTDRIVER_EXTRA_INCLUDES", extraInclude);
126   }
127   if (!function.empty()) {
128     mf.AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function);
129   }
130   mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode);
131   mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTRIES", functionMapCode);
132   bool res = true;
133   if (!mf.ConfigureFile(configFile, driver, false, true, false)) {
134     res = false;
135   }
136
137   // Construct the source list.
138   std::string sourceListValue;
139   {
140     cmSourceFile* sf = mf.GetOrCreateSource(driver);
141     sf->SetProperty("ABSTRACT", "0");
142     sourceListValue = args[1];
143   }
144   for (i = testsBegin; i != tests.end(); ++i) {
145     cmSourceFile* sf = mf.GetOrCreateSource(*i);
146     sf->SetProperty("ABSTRACT", "0");
147     sourceListValue += ";";
148     sourceListValue += *i;
149   }
150
151   mf.AddDefinition(sourceList, sourceListValue);
152   return res;
153 }