mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-21 06:10:16 +08:00
GoogleTest: Add handling for square brackets in test names
If a test name contains a square bracket (due to parameters) then it breaks gtest_discovery_test() function in some not-so-predictable way. That happens due to the special meaning these brackets have in the CMake language and they can't be escaped universally. So the following treatment has been implemented: * Every occurrence of ('[' | ']') in a test name gets replaced with the corresponding placeholder ("__osb_*" | "__csb_*") before the Google Test output processing and gets replaced back before adding a new test to CTest, keeping the original test name intact in the CTest output. The placeholders are chosen that way to minimize the chance of clashing with something in the user tests but even if the default ones would clash with something then they are enhanced to not clash with anything (hence "_*" at the placeholder's end). * The GTest output gets searched for the default test name guards ("[=[" | "]=]") and if they are found a new one gets generated until the one is found which can safely encompass any test name. The search is quite simple: find the least amount of '=' which would allow escaping any test. * The resulting ${TEST_LIST} variable will contain every test but tests with square brackets as there is no way to make sure such tests won't break the list altogether. Fixes: #23039
This commit is contained in:
@@ -20,7 +20,7 @@ macro(flush_tests_buffer)
|
|||||||
set(tests_buffer "")
|
set(tests_buffer "")
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
macro(add_command NAME)
|
macro(add_command NAME TEST_NAME)
|
||||||
set(_args "")
|
set(_args "")
|
||||||
foreach(_arg ${ARGN})
|
foreach(_arg ${ARGN})
|
||||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||||
@@ -29,7 +29,7 @@ macro(add_command NAME)
|
|||||||
string(APPEND _args " ${_arg}")
|
string(APPEND _args " ${_arg}")
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
string(APPEND script "${NAME}(${_args})\n")
|
string(APPEND script "${NAME}(${TEST_NAME} ${_args})\n")
|
||||||
string(LENGTH "${script}" _script_len)
|
string(LENGTH "${script}" _script_len)
|
||||||
if(${_script_len} GREATER "50000")
|
if(${_script_len} GREATER "50000")
|
||||||
flush_script()
|
flush_script()
|
||||||
@@ -39,6 +39,32 @@ macro(add_command NAME)
|
|||||||
unset(_script_len)
|
unset(_script_len)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
function(gtest_discover_tests_impl)
|
function(gtest_discover_tests_impl)
|
||||||
|
|
||||||
cmake_parse_arguments(
|
cmake_parse_arguments(
|
||||||
@@ -94,6 +120,9 @@ function(gtest_discover_tests_impl)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
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
|
# Preserve semicolon in test-parameters
|
||||||
string(REPLACE [[;]] [[\;]] output "${output}")
|
string(REPLACE [[;]] [[\;]] output "${output}")
|
||||||
string(REPLACE "\n" ";" output "${output}")
|
string(REPLACE "\n" ";" output "${output}")
|
||||||
@@ -128,18 +157,24 @@ function(gtest_discover_tests_impl)
|
|||||||
unset(TEST_XML_OUTPUT_PARAM)
|
unset(TEST_XML_OUTPUT_PARAM)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# sanitize test name for further processing downstream
|
|
||||||
set(testname "${prefix}${pretty_suite}.${pretty_test}${suffix}")
|
set(testname "${prefix}${pretty_suite}.${pretty_test}${suffix}")
|
||||||
|
# sanitize test name for further processing downstream
|
||||||
|
# unescape []
|
||||||
|
if(open_sb)
|
||||||
|
string(REPLACE "${open_sb}" "[" testname "${testname}")
|
||||||
|
endif()
|
||||||
|
if(close_sb)
|
||||||
|
string(REPLACE "${close_sb}" "]" testname "${testname}")
|
||||||
|
endif()
|
||||||
# escape \
|
# escape \
|
||||||
string(REPLACE [[\]] [[\\]] testname "${testname}")
|
string(REPLACE [[\]] [[\\]] testname "${testname}")
|
||||||
# escape ;
|
|
||||||
string(REPLACE [[;]] [[\;]] testname "${testname}")
|
|
||||||
# escape $
|
# escape $
|
||||||
string(REPLACE [[$]] [[\$]] testname "${testname}")
|
string(REPLACE [[$]] [[\$]] testname "${testname}")
|
||||||
|
set(guarded_testname "${open_guard}${testname}${close_guard}")
|
||||||
|
|
||||||
# ...and add to script
|
# ...and add to script
|
||||||
add_command(add_test
|
add_command(add_test
|
||||||
"${testname}"
|
"${guarded_testname}"
|
||||||
${_TEST_EXECUTOR}
|
${_TEST_EXECUTOR}
|
||||||
"${_TEST_EXECUTABLE}"
|
"${_TEST_EXECUTABLE}"
|
||||||
"--gtest_filter=${suite}.${test}"
|
"--gtest_filter=${suite}.${test}"
|
||||||
@@ -149,17 +184,23 @@ function(gtest_discover_tests_impl)
|
|||||||
)
|
)
|
||||||
if(suite MATCHES "^DISABLED_" OR test MATCHES "^DISABLED_")
|
if(suite MATCHES "^DISABLED_" OR test MATCHES "^DISABLED_")
|
||||||
add_command(set_tests_properties
|
add_command(set_tests_properties
|
||||||
"${testname}"
|
"${guarded_testname}"
|
||||||
PROPERTIES DISABLED TRUE
|
PROPERTIES DISABLED TRUE
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_command(set_tests_properties
|
add_command(set_tests_properties
|
||||||
"${testname}"
|
"${guarded_testname}"
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
||||||
SKIP_REGULAR_EXPRESSION "\\\\[ SKIPPED \\\\]"
|
SKIP_REGULAR_EXPRESSION "\\\\[ SKIPPED \\\\]"
|
||||||
${properties}
|
${properties}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# possibly unbalanced square brackets render lists invalid so skip such tests in _TEST_LIST
|
||||||
|
if(NOT "${testname}" MATCHES [=[(\[|\])]=])
|
||||||
|
# escape ;
|
||||||
|
string(REPLACE [[;]] [[\;]] testname "${testname}")
|
||||||
list(APPEND tests_buffer "${testname}")
|
list(APPEND tests_buffer "${testname}")
|
||||||
list(LENGTH tests_buffer tests_buffer_length)
|
list(LENGTH tests_buffer tests_buffer_length)
|
||||||
if(${tests_buffer_length} GREATER "250")
|
if(${tests_buffer_length} GREATER "250")
|
||||||
@@ -167,13 +208,14 @@ function(gtest_discover_tests_impl)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
|
||||||
# Create a list of all discovered tests, which users may use to e.g. set
|
# Create a list of all discovered tests, which users may use to e.g. set
|
||||||
# properties on the tests
|
# properties on the tests
|
||||||
flush_tests_buffer()
|
flush_tests_buffer()
|
||||||
add_command(set ${_TEST_LIST} ${tests})
|
add_command(set "" ${_TEST_LIST} ${tests})
|
||||||
|
|
||||||
# Write CTest script
|
# Write CTest script
|
||||||
flush_script()
|
flush_script()
|
||||||
|
@@ -41,12 +41,28 @@ Test project .*
|
|||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"backslash\\"!1 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"backslash\\"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
*Start +[0-9]+: TEST:param/special\.case/"\${var}"!1
|
*Start +[0-9]+: TEST:param/special\.case/"\${var}"!1
|
||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"\${var}"!1 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"\${var}"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:param/special\.case/'\['!1
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/'\['!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:param/special\.case/"\]\]=\]"!1
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"\]\]=\]"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:param/special\.case/"__osbtext"!1
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"__osbtext"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:param/special\.case/"__csb___text"!1
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"__csb___text"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
*Start +[0-9]+: TEST:ns\.param/special\.case/"semicolon;"!1
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"semicolon;"!1
|
||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"semicolon;"!1 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"semicolon;"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
*Start +[0-9]+: TEST:ns\.param/special\.case/"backslash\\"!1
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"backslash\\"!1
|
||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"backslash\\"!1 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"backslash\\"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
*Start +[0-9]+: TEST:ns\.param/special\.case/"\${var}"!1
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"\${var}"!1
|
||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"\${var}"!1 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"\${var}"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:ns\.param/special\.case/'\['!1
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/'\['!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"\]\]=\]"!1
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"\]\]=\]"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"__osbtext"!1
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"__osbtext"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"__csb___text"!1
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"__csb___text"!1 \.+ +Passed +[0-9.]+ sec
|
||||||
|
|
||||||
100% tests passed, 0 tests failed out of [0-9]+
|
100% tests passed, 0 tests failed out of [0-9]+
|
||||||
|
|
||||||
|
@@ -41,12 +41,28 @@ Test project .*
|
|||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"backslash\\"!2 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"backslash\\"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
*Start +[0-9]+: TEST:param/special\.case/"\${var}"!2
|
*Start +[0-9]+: TEST:param/special\.case/"\${var}"!2
|
||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"\${var}"!2 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"\${var}"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:param/special\.case/'\['!2
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/'\['!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:param/special\.case/"\]\]=\]"!2
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"\]\]=\]"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:param/special\.case/"__osbtext"!2
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"__osbtext"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:param/special\.case/"__csb___text"!2
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"__csb___text"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
*Start +[0-9]+: TEST:ns\.param/special\.case/"semicolon;"!2
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"semicolon;"!2
|
||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"semicolon;"!2 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"semicolon;"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
*Start +[0-9]+: TEST:ns\.param/special\.case/"backslash\\"!2
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"backslash\\"!2
|
||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"backslash\\"!2 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"backslash\\"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
*Start +[0-9]+: TEST:ns\.param/special\.case/"\${var}"!2
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"\${var}"!2
|
||||||
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"\${var}"!2 \.+ +Passed +[0-9.]+ sec
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"\${var}"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:ns\.param/special\.case/'\['!2
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/'\['!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"\]\]=\]"!2
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"\]\]=\]"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"__osbtext"!2
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"__osbtext"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
*Start +[0-9]+: TEST:ns\.param/special\.case/"__csb___text"!2
|
||||||
|
*[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/"__csb___text"!2 \.+ +Passed +[0-9.]+ sec
|
||||||
|
|
||||||
100% tests passed, 0 tests failed out of [0-9]+
|
100% tests passed, 0 tests failed out of [0-9]+
|
||||||
|
|
||||||
|
@@ -57,6 +57,10 @@ int main(int argc, char** argv)
|
|||||||
std::cout << " case/0 # GetParam() = \"semicolon;\"" << std::endl;
|
std::cout << " case/0 # GetParam() = \"semicolon;\"" << std::endl;
|
||||||
std::cout << " case/1 # GetParam() = \"backslash\\\"" << std::endl;
|
std::cout << " case/1 # GetParam() = \"backslash\\\"" << std::endl;
|
||||||
std::cout << " case/2 # GetParam() = \"${var}\"" << std::endl;
|
std::cout << " case/2 # GetParam() = \"${var}\"" << std::endl;
|
||||||
|
std::cout << " case/3 # GetParam() = '['" << std::endl;
|
||||||
|
std::cout << " case/4 # GetParam() = \"]]=]\"" << std::endl;
|
||||||
|
std::cout << " case/5 # GetParam() = \"__osbtext\"" << std::endl;
|
||||||
|
std::cout << " case/6 # GetParam() = \"__csb___text\"" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user