Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmCreateTestSourceList.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 "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
0
{
16
0
  if (args.size() < 3) {
17
0
    status.SetError("called with wrong number of arguments.");
18
0
    return false;
19
0
  }
20
21
0
  auto i = args.begin();
22
0
  std::string extraInclude;
23
0
  std::string function;
24
0
  std::vector<std::string> tests;
25
  // extract extra include and function
26
0
  for (; i != args.end(); i++) {
27
0
    if (*i == "EXTRA_INCLUDE") {
28
0
      ++i;
29
0
      if (i == args.end()) {
30
0
        status.SetError("incorrect arguments to EXTRA_INCLUDE");
31
0
        return false;
32
0
      }
33
0
      extraInclude = cmStrCat("#include \"", *i, "\"\n");
34
0
    } else if (*i == "FUNCTION") {
35
0
      ++i;
36
0
      if (i == args.end()) {
37
0
        status.SetError("incorrect arguments to FUNCTION");
38
0
        return false;
39
0
      }
40
0
      function = cmStrCat(*i, "(&ac, &av);\n");
41
0
    } else {
42
0
      tests.push_back(*i);
43
0
    }
44
0
  }
45
0
  i = tests.begin();
46
47
  // Name of the source list
48
49
0
  char const* sourceList = i->c_str();
50
0
  ++i;
51
52
  // Name of the test driver
53
  // make sure they specified an extension
54
0
  if (cmSystemTools::GetFilenameExtension(*i).size() < 2) {
55
0
    status.SetError(
56
0
      "You must specify a file extension for the test driver file.");
57
0
    return false;
58
0
  }
59
0
  cmMakefile& mf = status.GetMakefile();
60
0
  std::string driver = cmStrCat(mf.GetCurrentBinaryDirectory(), '/', *i);
61
0
  ++i;
62
63
0
  std::string configFile = cmSystemTools::GetCMakeRoot();
64
65
0
  configFile += "/Templates/TestDriver.cxx.in";
66
  // Create the test driver file
67
68
0
  auto testsBegin = i;
69
0
  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
0
  std::string forwardDeclareCode;
78
0
  for (i = testsBegin; i != tests.end(); ++i) {
79
0
    if (*i == "EXTRA_INCLUDE") {
80
0
      break;
81
0
    }
82
0
    std::string func_name;
83
0
    if (!cmSystemTools::GetFilenamePath(*i).empty()) {
84
0
      func_name = cmStrCat(cmSystemTools::GetFilenamePath(*i), '/',
85
0
                           cmSystemTools::GetFilenameWithoutLastExtension(*i));
86
0
    } else {
87
0
      func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
88
0
    }
89
0
    cmSystemTools::ConvertToUnixSlashes(func_name);
90
0
    func_name = cmSystemTools::MakeCidentifier(func_name);
91
0
    bool already_declared =
92
0
      std::find(tests_func_name.begin(), tests_func_name.end(), func_name) !=
93
0
      tests_func_name.end();
94
0
    tests_func_name.push_back(func_name);
95
0
    if (!already_declared) {
96
0
      forwardDeclareCode +=
97
0
        cmStrCat("extern int ", func_name, "(int, char*[]);\n");
98
0
    }
99
0
  }
100
101
0
  std::string functionMapCode;
102
0
  std::vector<std::string>::iterator j;
103
0
  for (i = testsBegin, j = tests_func_name.begin(); i != tests.end();
104
0
       ++i, ++j) {
105
0
    std::string func_name;
106
0
    if (!cmSystemTools::GetFilenamePath(*i).empty()) {
107
0
      func_name = cmStrCat(cmSystemTools::GetFilenamePath(*i), '/',
108
0
                           cmSystemTools::GetFilenameWithoutLastExtension(*i));
109
0
    } else {
110
0
      func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
111
0
    }
112
0
    functionMapCode += "  {\n"
113
0
                       "    \"";
114
0
    functionMapCode += func_name;
115
0
    functionMapCode += "\",\n"
116
0
                       "    ";
117
0
    functionMapCode += *j;
118
0
    functionMapCode += "\n"
119
0
                       "  },\n";
120
0
  }
121
0
  if (!extraInclude.empty()) {
122
0
    mf.AddDefinition("CMAKE_TESTDRIVER_EXTRA_INCLUDES", extraInclude);
123
0
  }
124
0
  if (!function.empty()) {
125
0
    mf.AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function);
126
0
  }
127
0
  mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode);
128
0
  mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTRIES", functionMapCode);
129
0
  bool res = true;
130
0
  if (!mf.ConfigureFile(configFile, driver, false, true, false)) {
131
0
    res = false;
132
0
  }
133
134
  // Construct the source list.
135
0
  std::string sourceListValue;
136
0
  {
137
0
    cmSourceFile* sf = mf.GetOrCreateSource(driver);
138
0
    sf->SetProperty("ABSTRACT", "0");
139
0
    sourceListValue = driver;
140
0
  }
141
0
  for (i = testsBegin; i != tests.end(); ++i) {
142
0
    cmSourceFile* sf = mf.GetOrCreateSource(*i);
143
0
    sf->SetProperty("ABSTRACT", "0");
144
0
    sourceListValue += ';';
145
0
    sourceListValue += *i;
146
0
  }
147
148
0
  mf.AddDefinition(sourceList, sourceListValue);
149
0
  return res;
150
0
}