Coverage Report

Created: 2026-10-28 06:38

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