GoogleTestAddTests.cmake 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. cmake_minimum_required(VERSION 3.30)
  4. cmake_policy(SET CMP0174 NEW) # TODO: Remove this when we can update the above to 3.31
  5. # Overwrite possibly existing ${arg_CTEST_FILE} with empty file
  6. set(flush_tests_MODE WRITE)
  7. # Flushes script to ${arg_CTEST_FILE}
  8. macro(flush_script)
  9. file(${flush_tests_MODE} "${arg_CTEST_FILE}" "${script}")
  10. set(flush_tests_MODE APPEND PARENT_SCOPE)
  11. set(script "")
  12. endmacro()
  13. # Flushes tests_buffer to tests
  14. macro(flush_tests_buffer)
  15. list(APPEND tests "${tests_buffer}")
  16. set(tests_buffer "")
  17. endmacro()
  18. function(add_command name test_name)
  19. set(args "")
  20. foreach(arg ${ARGN})
  21. if(arg MATCHES "[^-./:a-zA-Z0-9_]")
  22. string(APPEND args " [==[${arg}]==]")
  23. else()
  24. string(APPEND args " ${arg}")
  25. endif()
  26. endforeach()
  27. string(APPEND script "${name}(${test_name} ${args})\n")
  28. string(LENGTH "${script}" script_len)
  29. if(${script_len} GREATER "50000")
  30. flush_script()
  31. endif()
  32. set(script "${script}" PARENT_SCOPE)
  33. endfunction()
  34. function(generate_testname_guards output open_guard_var close_guard_var)
  35. set(open_guard "[=[")
  36. set(close_guard "]=]")
  37. set(counter 1)
  38. while("${output}" MATCHES "${close_guard}")
  39. math(EXPR counter "${counter} + 1")
  40. string(REPEAT "=" ${counter} equals)
  41. set(open_guard "[${equals}[")
  42. set(close_guard "]${equals}]")
  43. endwhile()
  44. set(${open_guard_var} "${open_guard}" PARENT_SCOPE)
  45. set(${close_guard_var} "${close_guard}" PARENT_SCOPE)
  46. endfunction()
  47. function(escape_square_brackets output bracket placeholder placeholder_var output_var)
  48. if("${output}" MATCHES "\\${bracket}")
  49. set(placeholder "${placeholder}")
  50. while("${output}" MATCHES "${placeholder}")
  51. set(placeholder "${placeholder}_")
  52. endwhile()
  53. string(REPLACE "${bracket}" "${placeholder}" output "${output}")
  54. set(${placeholder_var} "${placeholder}" PARENT_SCOPE)
  55. set(${output_var} "${output}" PARENT_SCOPE)
  56. endif()
  57. endfunction()
  58. function(gtest_discover_tests_impl)
  59. set(options "")
  60. set(oneValueArgs
  61. NO_PRETTY_TYPES # These two take a value, unlike gtest_discover_tests()
  62. NO_PRETTY_VALUES #
  63. TEST_EXECUTABLE
  64. TEST_WORKING_DIR
  65. TEST_PREFIX
  66. TEST_SUFFIX
  67. TEST_LIST
  68. CTEST_FILE
  69. TEST_DISCOVERY_TIMEOUT
  70. TEST_XML_OUTPUT_DIR
  71. # The following are all multi-value arguments in gtest_discover_tests(),
  72. # but they are each given to us as a single argument. We parse them that
  73. # way to avoid problems with preserving empty list values and escaping.
  74. TEST_FILTER
  75. TEST_EXTRA_ARGS
  76. TEST_DISCOVERY_EXTRA_ARGS
  77. TEST_PROPERTIES
  78. TEST_EXECUTOR
  79. )
  80. set(multiValueArgs "")
  81. cmake_parse_arguments(PARSE_ARGV 0 arg
  82. "${options}" "${oneValueArgs}" "${multiValueArgs}"
  83. )
  84. set(prefix "${arg_TEST_PREFIX}")
  85. set(suffix "${arg_TEST_SUFFIX}")
  86. set(script)
  87. set(suite)
  88. set(tests)
  89. set(tests_buffer)
  90. if(arg_TEST_FILTER)
  91. set(filter "--gtest_filter=${arg_TEST_FILTER}")
  92. else()
  93. set(filter)
  94. endif()
  95. # CMP0178 has already been handled in gtest_discover_tests(), so we only need
  96. # to implement NEW behavior here. This means preserving empty arguments for
  97. # TEST_EXECUTOR. For OLD or WARN, gtest_discover_tests() already removed any
  98. # empty arguments.
  99. set(launcherArgs "")
  100. if(NOT "${arg_TEST_EXECUTOR}" STREQUAL "")
  101. list(JOIN arg_TEST_EXECUTOR "]==] [==[" launcherArgs)
  102. set(launcherArgs "[==[${launcherArgs}]==]")
  103. endif()
  104. # Run test executable to get list of available tests
  105. if(NOT EXISTS "${arg_TEST_EXECUTABLE}")
  106. message(FATAL_ERROR
  107. "Specified test executable does not exist.\n"
  108. " Path: '${arg_TEST_EXECUTABLE}'"
  109. )
  110. endif()
  111. set(discovery_extra_args "")
  112. if(NOT "${arg_TEST_DISCOVERY_EXTRA_ARGS}" STREQUAL "")
  113. list(JOIN arg_TEST_DISCOVERY_EXTRA_ARGS "]==] [==[" discovery_extra_args)
  114. set(discovery_extra_args "[==[${discovery_extra_args}]==]")
  115. endif()
  116. cmake_language(EVAL CODE
  117. "execute_process(
  118. COMMAND ${launcherArgs} [==[${arg_TEST_EXECUTABLE}]==] --gtest_list_tests ${filter} ${discovery_extra_args}
  119. WORKING_DIRECTORY [==[${arg_TEST_WORKING_DIR}]==]
  120. TIMEOUT ${arg_TEST_DISCOVERY_TIMEOUT}
  121. OUTPUT_VARIABLE output
  122. RESULT_VARIABLE result
  123. )"
  124. )
  125. if(NOT ${result} EQUAL 0)
  126. string(REPLACE "\n" "\n " output "${output}")
  127. if(arg_TEST_EXECUTOR)
  128. set(path "${arg_TEST_EXECUTOR} ${arg_TEST_EXECUTABLE}")
  129. else()
  130. set(path "${arg_TEST_EXECUTABLE}")
  131. endif()
  132. message(FATAL_ERROR
  133. "Error running test executable.\n"
  134. " Path: '${path}'\n"
  135. " Working directory: '${arg_TEST_WORKING_DIR}'\n"
  136. " Result: ${result}\n"
  137. " Output:\n"
  138. " ${output}\n"
  139. )
  140. endif()
  141. generate_testname_guards("${output}" open_guard close_guard)
  142. escape_square_brackets("${output}" "[" "__osb" open_sb output)
  143. escape_square_brackets("${output}" "]" "__csb" close_sb output)
  144. # Preserve semicolon in test-parameters
  145. string(REPLACE [[;]] [[\;]] output "${output}")
  146. string(REPLACE "\n" ";" output "${output}")
  147. # Parse output
  148. foreach(line ${output})
  149. # Skip header
  150. if(NOT line MATCHES "gtest_main\\.cc")
  151. # Do we have a module name or a test name?
  152. if(NOT line MATCHES "^ ")
  153. # Module; remove trailing '.' to get just the name...
  154. string(REGEX REPLACE "\\.( *#.*)?$" "" suite "${line}")
  155. if(line MATCHES "#")
  156. string(REGEX REPLACE "/[0-9].*" "" pretty_suite "${line}")
  157. if(NOT arg_NO_PRETTY_TYPES)
  158. string(REGEX REPLACE ".*/[0-9]+[ .#]+TypeParam = (.*)" "\\1" type_parameter "${line}")
  159. else()
  160. string(REGEX REPLACE ".*/([0-9]+)[ .#]+TypeParam = .*" "\\1" type_parameter "${line}")
  161. endif()
  162. set(test_name_template "@prefix@@pretty_suite@.@pretty_test@<@type_parameter@>@suffix@")
  163. else()
  164. set(pretty_suite "${suite}")
  165. set(test_name_template "@prefix@@pretty_suite@.@pretty_test@@suffix@")
  166. endif()
  167. string(REGEX REPLACE "^DISABLED_" "" pretty_suite "${pretty_suite}")
  168. else()
  169. string(STRIP "${line}" test)
  170. if(test MATCHES "#" AND NOT arg_NO_PRETTY_VALUES)
  171. string(REGEX REPLACE "/[0-9]+[ #]+GetParam\\(\\) = " "/" pretty_test "${test}")
  172. else()
  173. string(REGEX REPLACE " +#.*" "" pretty_test "${test}")
  174. endif()
  175. string(REGEX REPLACE "^DISABLED_" "" pretty_test "${pretty_test}")
  176. string(REGEX REPLACE " +#.*" "" test "${test}")
  177. if(NOT "${arg_TEST_XML_OUTPUT_DIR}" STREQUAL "")
  178. set(TEST_XML_OUTPUT_PARAM "--gtest_output=xml:${arg_TEST_XML_OUTPUT_DIR}/${prefix}${suite}.${test}${suffix}.xml")
  179. else()
  180. unset(TEST_XML_OUTPUT_PARAM)
  181. endif()
  182. string(CONFIGURE "${test_name_template}" testname)
  183. # unescape []
  184. if(open_sb)
  185. string(REPLACE "${open_sb}" "[" testname "${testname}")
  186. endif()
  187. if(close_sb)
  188. string(REPLACE "${close_sb}" "]" testname "${testname}")
  189. endif()
  190. set(guarded_testname "${open_guard}${testname}${close_guard}")
  191. # Add to script. Do not use add_command() here because it messes up the
  192. # handling of empty values when forwarding arguments, and we need to
  193. # preserve those carefully for arg_TEST_EXECUTOR and arg_EXTRA_ARGS.
  194. string(APPEND script "add_test(${guarded_testname} ${launcherArgs}")
  195. foreach(arg IN ITEMS
  196. "${arg_TEST_EXECUTABLE}"
  197. "--gtest_filter=${suite}.${test}"
  198. "--gtest_also_run_disabled_tests"
  199. ${TEST_XML_OUTPUT_PARAM}
  200. )
  201. if(arg MATCHES "[^-./:a-zA-Z0-9_]")
  202. string(APPEND script " [==[${arg}]==]")
  203. else()
  204. string(APPEND script " ${arg}")
  205. endif()
  206. endforeach()
  207. if(arg_TEST_EXTRA_ARGS)
  208. list(JOIN arg_TEST_EXTRA_ARGS "]==] [==[" extra_args)
  209. string(APPEND script " [==[${extra_args}]==]")
  210. endif()
  211. string(APPEND script ")\n")
  212. string(LENGTH "${script}" script_len)
  213. if(${script_len} GREATER "50000")
  214. # flush_script() expects to set variables in the parent scope, so we
  215. # need to create one since we actually want the changes in our scope
  216. block(SCOPE_FOR VARIABLES)
  217. flush_script()
  218. endblock()
  219. endif()
  220. if(suite MATCHES "^DISABLED_" OR test MATCHES "^DISABLED_")
  221. add_command(set_tests_properties
  222. "${guarded_testname}"
  223. PROPERTIES DISABLED TRUE
  224. )
  225. endif()
  226. add_command(set_tests_properties
  227. "${guarded_testname}"
  228. PROPERTIES
  229. WORKING_DIRECTORY "${arg_TEST_WORKING_DIR}"
  230. SKIP_REGULAR_EXPRESSION "\\[ SKIPPED \\]"
  231. ${arg_TEST_PROPERTIES}
  232. )
  233. # possibly unbalanced square brackets render lists invalid so skip such
  234. # tests in ${arg_TEST_LIST}
  235. if(NOT "${testname}" MATCHES [=[(\[|\])]=])
  236. # escape ;
  237. string(REPLACE [[;]] [[\\;]] testname "${testname}")
  238. list(APPEND tests_buffer "${testname}")
  239. list(LENGTH tests_buffer tests_buffer_length)
  240. if(${tests_buffer_length} GREATER "250")
  241. flush_tests_buffer()
  242. endif()
  243. endif()
  244. endif()
  245. endif()
  246. endforeach()
  247. # Create a list of all discovered tests, which users may use to e.g. set
  248. # properties on the tests
  249. flush_tests_buffer()
  250. add_command(set "" ${arg_TEST_LIST} "${tests}")
  251. # Write CTest script
  252. flush_script()
  253. endfunction()
  254. if(CMAKE_SCRIPT_MODE_FILE)
  255. gtest_discover_tests_impl(
  256. NO_PRETTY_TYPES ${NO_PRETTY_TYPES}
  257. NO_PRETTY_VALUES ${NO_PRETTY_VALUES}
  258. TEST_EXECUTABLE ${TEST_EXECUTABLE}
  259. TEST_EXECUTOR "${TEST_EXECUTOR}"
  260. TEST_WORKING_DIR ${TEST_WORKING_DIR}
  261. TEST_PREFIX ${TEST_PREFIX}
  262. TEST_SUFFIX ${TEST_SUFFIX}
  263. TEST_FILTER ${TEST_FILTER}
  264. TEST_LIST ${TEST_LIST}
  265. CTEST_FILE ${CTEST_FILE}
  266. TEST_DISCOVERY_TIMEOUT ${TEST_DISCOVERY_TIMEOUT}
  267. TEST_XML_OUTPUT_DIR ${TEST_XML_OUTPUT_DIR}
  268. TEST_EXTRA_ARGS "${TEST_EXTRA_ARGS}"
  269. TEST_DISCOVERY_EXTRA_ARGS "${TEST_DISCOVERY_EXTRA_ARGS}"
  270. TEST_PROPERTIES "${TEST_PROPERTIES}"
  271. )
  272. endif()