mirror of
https://github.com/Kitware/CMake.git
synced 2026-08-13 17:07:57 +00:00
It is possible to have trailing ( and maybe leading ) newlines in a test name. This causes problems with ctest features like `tests-from-file` since they will never be an exact match. So now we sanitize names by removing these newlines
149 lines
5.1 KiB
CMake
149 lines
5.1 KiB
CMake
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
# file LICENSE.rst or https://cmake.org/licensing for details.
|
|
|
|
include_guard(GLOBAL)
|
|
|
|
function(generate_testname_guards output open_guard_var close_guard_var)
|
|
set(open_guard "[=[")
|
|
set(close_guard "]=]")
|
|
set(counter 1)
|
|
while("${output}" MATCHES "${close_guard}")
|
|
math(EXPR counter "${counter} + 1")
|
|
string(REPEAT "=" ${counter} equals)
|
|
set(open_guard "[${equals}[")
|
|
set(close_guard "]${equals}]")
|
|
endwhile()
|
|
set(${open_guard_var} "${open_guard}" PARENT_SCOPE)
|
|
set(${close_guard_var} "${close_guard}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(escape_square_brackets output bracket placeholder placeholder_var output_var)
|
|
if("${output}" MATCHES "\\${bracket}")
|
|
set(placeholder "${placeholder}")
|
|
while("${output}" MATCHES "${placeholder}")
|
|
set(placeholder "${placeholder}_")
|
|
endwhile()
|
|
string(REPLACE "${bracket}" "${placeholder}" output "${output}")
|
|
set(${placeholder_var} "${placeholder}" PARENT_SCOPE)
|
|
set(${output_var} "${output}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
macro(parse_tests_from_output per_test_callback)
|
|
generate_testname_guards("${output}" open_guard close_guard)
|
|
escape_square_brackets("${output}" "[" "__osb" open_sb output)
|
|
escape_square_brackets("${output}" "]" "__csb" close_sb output)
|
|
|
|
# Preserve semicolon in test-parameters
|
|
string(REPLACE [[;]] [[\;]] output "${output}")
|
|
string(REPLACE "\n" ";" output "${output}")
|
|
|
|
# Command line output doesn't contain information about the file and line number of the tests
|
|
set(current_test_file "")
|
|
set(current_test_line "")
|
|
|
|
# Parse output
|
|
foreach(line ${output})
|
|
# Skip header
|
|
if(line MATCHES "gtest_main\\.cc")
|
|
continue()
|
|
endif()
|
|
|
|
if(line STREQUAL "")
|
|
continue()
|
|
endif()
|
|
|
|
# Do we have a module name or a test name?
|
|
if(NOT line MATCHES "^ ")
|
|
set(current_test_type_param "")
|
|
|
|
# Module; remove trailing '.' to get just the name...
|
|
string(REGEX REPLACE "\\.( *#.*)?$" "" current_test_suite "${line}")
|
|
if(line MATCHES "# *TypeParam = (.*)$")
|
|
set(current_test_type_param "${CMAKE_MATCH_1}")
|
|
endif()
|
|
else()
|
|
string(STRIP "${line}" test)
|
|
string(REGEX REPLACE " ( *#.*)?$" "" current_test_name "${test}")
|
|
|
|
set(current_test_value_param "")
|
|
if(line MATCHES "# *GetParam\\(\\) = (.*)$")
|
|
set(current_test_value_param "${CMAKE_MATCH_1}")
|
|
endif()
|
|
|
|
cmake_language(CALL ${per_test_callback})
|
|
endif()
|
|
endforeach()
|
|
endmacro()
|
|
|
|
macro(get_json_member_with_default json_variable member_name out_variable)
|
|
string(JSON ${out_variable}
|
|
ERROR_VARIABLE error_param
|
|
GET "${${json_variable}}" "${member_name}"
|
|
)
|
|
if(error_param)
|
|
# Member not present
|
|
set(${out_variable} "")
|
|
else()
|
|
string(STRIP "${${out_variable}}" "${out_variable}")
|
|
endif()
|
|
endmacro()
|
|
|
|
macro(parse_tests_from_json json_file per_test_callback)
|
|
if(NOT EXISTS "${json_file}")
|
|
message(FATAL_ERROR "Missing expected JSON file with test list: ${json_file}")
|
|
endif()
|
|
|
|
file(READ "${json_file}" test_json)
|
|
string(JSON test_suites_json GET "${test_json}" "testsuites")
|
|
|
|
# Return if there are no testsuites
|
|
string(JSON len_test_suites LENGTH "${test_suites_json}")
|
|
if(len_test_suites GREATER 0)
|
|
set(open_sb)
|
|
set(close_sb)
|
|
|
|
math(EXPR upper_limit_test_suite_range "${len_test_suites} - 1")
|
|
|
|
foreach(index_test_suite RANGE ${upper_limit_test_suite_range})
|
|
string(JSON test_suite_json GET "${test_suites_json}" ${index_test_suite})
|
|
|
|
# "suite" is expected to be set in write_test_to_file(). When parsing the
|
|
# plain text output, "suite" is expected to be the original suite name
|
|
# before accounting for pretty names. This may be used to construct the
|
|
# name of XML output results files.
|
|
string(JSON current_test_suite GET "${test_suite_json}" "name")
|
|
string(STRIP "${current_test_suite}" current_test_suite)
|
|
string(JSON tests_json GET "${test_suite_json}" "testsuite")
|
|
|
|
# Skip test suites without tests
|
|
string(JSON len_tests LENGTH "${tests_json}")
|
|
if(len_tests LESS_EQUAL 0)
|
|
continue()
|
|
endif()
|
|
|
|
math(EXPR upper_limit_test_range "${len_tests} - 1")
|
|
foreach(index_test RANGE ${upper_limit_test_range})
|
|
string(JSON test_json GET "${tests_json}" ${index_test})
|
|
|
|
string(JSON len_test_parameters LENGTH "${test_json}")
|
|
if(len_test_parameters LESS_EQUAL 0)
|
|
continue()
|
|
endif()
|
|
|
|
get_json_member_with_default(test_json "name" current_test_name)
|
|
get_json_member_with_default(test_json "file" current_test_file)
|
|
get_json_member_with_default(test_json "line" current_test_line)
|
|
get_json_member_with_default(test_json "value_param" current_test_value_param)
|
|
get_json_member_with_default(test_json "type_param" current_test_type_param)
|
|
|
|
generate_testname_guards(
|
|
"${current_test_suite}${current_test_name}${current_test_value_param}${current_test_type_param}"
|
|
open_guard close_guard
|
|
)
|
|
cmake_language(CALL ${per_test_callback})
|
|
endforeach()
|
|
endforeach()
|
|
endif()
|
|
endmacro()
|