1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4cmake_minimum_required(VERSION ${CMAKE_VERSION})
5
6# Overwrite possibly existing ${_CTEST_FILE} with empty file
7set(flush_tests_MODE WRITE)
8
9# Flushes script to ${_CTEST_FILE}
10macro(flush_script)
11  file(${flush_tests_MODE} "${_CTEST_FILE}" "${script}")
12  set(flush_tests_MODE APPEND)
13
14  set(script "")
15endmacro()
16
17# Flushes tests_buffer to tests
18macro(flush_tests_buffer)
19  list(APPEND tests "${tests_buffer}")
20  set(tests_buffer "")
21endmacro()
22
23macro(add_command NAME)
24  set(_args "")
25  foreach(_arg ${ARGN})
26    if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
27      string(APPEND _args " [==[${_arg}]==]")
28    else()
29      string(APPEND _args " ${_arg}")
30    endif()
31  endforeach()
32  string(APPEND script "${NAME}(${_args})\n")
33  string(LENGTH "${script}" _script_len)
34  if(${_script_len} GREATER "50000")
35    flush_script()
36  endif()
37  # Unsets macro local variables to prevent leakage outside of this macro.
38  unset(_args)
39  unset(_script_len)
40endmacro()
41
42function(gtest_discover_tests_impl)
43
44  cmake_parse_arguments(
45    ""
46    ""
47    "NO_PRETTY_TYPES;NO_PRETTY_VALUES;TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_PREFIX;TEST_SUFFIX;TEST_LIST;CTEST_FILE;TEST_DISCOVERY_TIMEOUT;TEST_XML_OUTPUT_DIR;TEST_FILTER"
48    "TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR"
49    ${ARGN}
50  )
51
52  set(prefix "${_TEST_PREFIX}")
53  set(suffix "${_TEST_SUFFIX}")
54  set(extra_args ${_TEST_EXTRA_ARGS})
55  set(properties ${_TEST_PROPERTIES})
56  set(script)
57  set(suite)
58  set(tests)
59  set(tests_buffer)
60
61  if(_TEST_FILTER)
62    set(filter "--gtest_filter=${_TEST_FILTER}")
63  else()
64    set(filter)
65  endif()
66
67  # Run test executable to get list of available tests
68  if(NOT EXISTS "${_TEST_EXECUTABLE}")
69    message(FATAL_ERROR
70      "Specified test executable does not exist.\n"
71      "  Path: '${_TEST_EXECUTABLE}'"
72    )
73  endif()
74  execute_process(
75    COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" --gtest_list_tests ${filter}
76    WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
77    TIMEOUT ${_TEST_DISCOVERY_TIMEOUT}
78    OUTPUT_VARIABLE output
79    RESULT_VARIABLE result
80  )
81  if(NOT ${result} EQUAL 0)
82    string(REPLACE "\n" "\n    " output "${output}")
83    message(FATAL_ERROR
84      "Error running test executable.\n"
85      "  Path: '${_TEST_EXECUTABLE}'\n"
86      "  Result: ${result}\n"
87      "  Output:\n"
88      "    ${output}\n"
89    )
90  endif()
91
92  # Preserve semicolon in test-parameters
93  string(REPLACE [[;]] [[\;]] output "${output}")
94  string(REPLACE "\n" ";" output "${output}")
95
96  # Parse output
97  foreach(line ${output})
98    # Skip header
99    if(NOT line MATCHES "gtest_main\\.cc")
100      # Do we have a module name or a test name?
101      if(NOT line MATCHES "^  ")
102        # Module; remove trailing '.' to get just the name...
103        string(REGEX REPLACE "\\.( *#.*)?" "" suite "${line}")
104        if(line MATCHES "#" AND NOT _NO_PRETTY_TYPES)
105          string(REGEX REPLACE "/[0-9]\\.+ +#.*= +" "/" pretty_suite "${line}")
106        else()
107          set(pretty_suite "${suite}")
108        endif()
109        string(REGEX REPLACE "^DISABLED_" "" pretty_suite "${pretty_suite}")
110      else()
111        # Test name; strip spaces and comments to get just the name...
112        string(REGEX REPLACE " +" "" test "${line}")
113        if(test MATCHES "#" AND NOT _NO_PRETTY_VALUES)
114          string(REGEX REPLACE "/[0-9]+#GetParam..=" "/" pretty_test "${test}")
115        else()
116          string(REGEX REPLACE "#.*" "" pretty_test "${test}")
117        endif()
118        string(REGEX REPLACE "^DISABLED_" "" pretty_test "${pretty_test}")
119        string(REGEX REPLACE "#.*" "" test "${test}")
120        if(NOT "${_TEST_XML_OUTPUT_DIR}" STREQUAL "")
121          set(TEST_XML_OUTPUT_PARAM "--gtest_output=xml:${_TEST_XML_OUTPUT_DIR}/${prefix}${suite}.${test}${suffix}.xml")
122        else()
123          unset(TEST_XML_OUTPUT_PARAM)
124        endif()
125
126        # sanitize test name for further processing downstream
127        set(testname "${prefix}${pretty_suite}.${pretty_test}${suffix}")
128        # escape \
129        string(REPLACE [[\]] [[\\]] testname "${testname}")
130        # escape ;
131        string(REPLACE [[;]] [[\;]] testname "${testname}")
132        # escape $
133        string(REPLACE [[$]] [[\$]] testname "${testname}")
134
135        # ...and add to script
136        add_command(add_test
137          "${testname}"
138          ${_TEST_EXECUTOR}
139          "${_TEST_EXECUTABLE}"
140          "--gtest_filter=${suite}.${test}"
141          "--gtest_also_run_disabled_tests"
142          ${TEST_XML_OUTPUT_PARAM}
143          ${extra_args}
144        )
145        if(suite MATCHES "^DISABLED_" OR test MATCHES "^DISABLED_")
146          add_command(set_tests_properties
147            "${testname}"
148            PROPERTIES DISABLED TRUE
149          )
150        endif()
151        add_command(set_tests_properties
152          "${testname}"
153          PROPERTIES
154          WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
155          SKIP_REGULAR_EXPRESSION "\\\\[  SKIPPED \\\\]"
156          ${properties}
157        )
158        list(APPEND tests_buffer "${testname}")
159        list(LENGTH tests_buffer tests_buffer_length)
160        if(${tests_buffer_length} GREATER "250")
161          flush_tests_buffer()
162        endif()
163      endif()
164    endif()
165  endforeach()
166
167
168  # Create a list of all discovered tests, which users may use to e.g. set
169  # properties on the tests
170  flush_tests_buffer()
171  add_command(set ${_TEST_LIST} ${tests})
172
173  # Write CTest script
174  flush_script()
175
176endfunction()
177
178if(CMAKE_SCRIPT_MODE_FILE)
179  gtest_discover_tests_impl(
180    NO_PRETTY_TYPES ${NO_PRETTY_TYPES}
181    NO_PRETTY_VALUES ${NO_PRETTY_VALUES}
182    TEST_EXECUTABLE ${TEST_EXECUTABLE}
183    TEST_EXECUTOR ${TEST_EXECUTOR}
184    TEST_WORKING_DIR ${TEST_WORKING_DIR}
185    TEST_PREFIX ${TEST_PREFIX}
186    TEST_SUFFIX ${TEST_SUFFIX}
187    TEST_FILTER ${TEST_FILTER}
188    TEST_LIST ${TEST_LIST}
189    CTEST_FILE ${CTEST_FILE}
190    TEST_DISCOVERY_TIMEOUT ${TEST_DISCOVERY_TIMEOUT}
191    TEST_XML_OUTPUT_DIR ${TEST_XML_OUTPUT_DIR}
192    TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS}
193    TEST_PROPERTIES ${TEST_PROPERTIES}
194  )
195endif()
196