tests: Preserve empty arguments in test command lines

This will now preserve empty values in the TEST_LAUNCHER and
CROSSCOMPILING_EMULATOR target properties for tests added by:

- The add_test() command.
- The ExternalData_Add_Test() command from the ExternalData module.
- The gtest_add_tests() or gtest_discover_tests() commands from the
  GoogleTest module.

For the gtest_add_tests() and gtest_discover_tests() commands,
empty elements in the values passed after the EXTRA_ARGS keyword
are also now preserved.

Policy CMP0178 is added to provide backward compatibility with the
old behavior where empty values were silently discarded from the
above cases.

Fixes: #26337
This commit is contained in:
Craig Scott
2024-09-30 21:13:13 +10:00
parent 9f1703530b
commit fc7aa3cd69
27 changed files with 512 additions and 80 deletions
+112 -18
View File
@@ -42,7 +42,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
gtest_add_tests(TARGET target
[SOURCES src1...]
[EXTRA_ARGS arg1...]
[EXTRA_ARGS args...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
@@ -72,9 +72,12 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
this option is not given, the :prop_tgt:`SOURCES` property of the
specified ``target`` will be used to obtain the list of sources.
``EXTRA_ARGS arg1...``
``EXTRA_ARGS args...``
Any extra arguments to pass on the command line to each test case.
.. versionchanged:: 3.31
Empty values in ``args...`` are preserved, see :policy:`CMP0178`.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
@@ -101,6 +104,11 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
with the list of discovered test cases. This allows the caller to do
things like manipulate test properties of the discovered tests.
.. versionchanged:: 3.31
Empty values in the :prop_tgt:`TEST_LAUNCHER` and
:prop_tgt:`CROSSCOMPILING_EMULATOR` target properties are preserved,
see policy :policy:`CMP0178`.
Usage example:
.. code-block:: cmake
@@ -147,7 +155,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
for available tests::
gtest_discover_tests(target
[EXTRA_ARGS arg1...]
[EXTRA_ARGS args...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
@@ -187,9 +195,12 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
executable target. CMake will substitute the location of the built
executable when running the test.
``EXTRA_ARGS arg1...``
``EXTRA_ARGS args...``
Any extra arguments to pass on the command line to each test case.
.. versionchanged:: 3.31
Empty values in ``args...`` are preserved, see :policy:`CMP0178`.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
@@ -283,6 +294,15 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
for globally selecting a preferred test discovery behavior without having
to modify each call site.
.. versionadded:: 3.29
The :prop_tgt:`TEST_LAUNCHER` target property is honored during test
discovery and test execution.
.. versionchanged:: 3.31
Empty values in the :prop_tgt:`TEST_LAUNCHER` and
:prop_tgt:`CROSSCOMPILING_EMULATOR` target properties are preserved,
see policy :policy:`CMP0178`.
#]=======================================================================]
# Save project's policies
@@ -312,9 +332,41 @@ function(gtest_add_tests)
)
set(allKeywords ${options} ${oneValueArgs} ${multiValueArgs})
cmake_policy(GET CMP0178 cmp0178
PARENT_SCOPE # undocumented, do not use outside of CMake
)
unset(sources)
if("${ARGV0}" IN_LIST allKeywords)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(cmp0178 STREQUAL "NEW")
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}" "${oneValueArgs}" "${multiValueArgs}"
)
else()
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT cmp0178 STREQUAL "OLD")
block(SCOPE_FOR VARIABLES)
cmake_parse_arguments(PARSE_ARGV 0 arg_new
"${options}" "${oneValueArgs}" "${multiValueArgs}"
)
# Due to a quirk of cmake_parse_arguments(PARSE_ARGV),
# arg_new_EXTRA_ARGS will have semicolons already escaped, but
# arg_EXTRA_ARGS won't. We need to pass the former through one round
# of command argument parsing to de-escape them for comparison with
# the latter.
set(__newArgs ${arg_new_EXTRA_ARGS})
if(NOT "${arg_EXTRA_ARGS}" STREQUAL "${__newArgs}")
cmake_policy(GET_WARNING CMP0178 cmp0178_warning)
message(AUTHOR_WARNING
"The EXTRA_ARGS contain one or more empty values. Those empty "
"values are being silently discarded to preserve backward "
"compatibility.\n"
"${cmp0178_warning}"
)
endif()
endblock()
endif()
endif()
set(autoAddSources YES)
else()
# Non-keyword syntax, convert to keyword form
@@ -408,6 +460,11 @@ function(gtest_add_tests)
continue()
endif()
set(extra_args "")
foreach(arg IN LISTS arg_EXTRA_ARGS)
string(APPEND extra_args " [==[${arg}]==]")
endforeach()
# Make sure tests disabled in GTest get disabled in CTest
if(gtest_test_name MATCHES "(^|\\.)DISABLED_")
# Add the disabled test if CMake is new enough
@@ -422,12 +479,15 @@ function(gtest_add_tests)
set(ctest_test_name
${arg_TEST_PREFIX}${orig_test_name}${arg_TEST_SUFFIX}
)
add_test(NAME ${ctest_test_name}
${workDir}
COMMAND ${arg_TARGET}
--gtest_also_run_disabled_tests
--gtest_filter=${gtest_test_name}
${arg_EXTRA_ARGS}
cmake_language(EVAL CODE "
add_test(NAME ${ctest_test_name}
${workDir}
COMMAND ${arg_TARGET}
--gtest_also_run_disabled_tests
--gtest_filter=${gtest_test_name}
${extra_args}
__CMP0178 [==[${cmp0178}]==]
)"
)
set_tests_properties(${ctest_test_name} PROPERTIES DISABLED TRUE
DEF_SOURCE_LINE "${source}:${accumulate_line}")
@@ -435,11 +495,14 @@ function(gtest_add_tests)
endif()
else()
set(ctest_test_name ${arg_TEST_PREFIX}${gtest_test_name}${arg_TEST_SUFFIX})
add_test(NAME ${ctest_test_name}
${workDir}
COMMAND ${arg_TARGET}
--gtest_filter=${gtest_test_name}
${arg_EXTRA_ARGS}
cmake_language(EVAL CODE "
add_test(NAME ${ctest_test_name}
${workDir}
COMMAND ${arg_TARGET}
--gtest_filter=${gtest_test_name}
${extra_args}
__CMP0178 [==[${cmp0178}]==]
)"
)
# Makes sure a skipped GTest is reported as so by CTest
set_tests_properties(
@@ -480,9 +543,8 @@ function(gtest_discover_tests target)
PROPERTIES
TEST_FILTER
)
cmake_parse_arguments(arg
cmake_parse_arguments(PARSE_ARGV 1 arg
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
if(NOT arg_WORKING_DIRECTORY)
@@ -551,6 +613,38 @@ function(gtest_discover_tests target)
set(test_executor "")
endif()
cmake_policy(GET CMP0178 cmp0178
PARENT_SCOPE # undocumented, do not use outside of CMake
)
if(NOT cmp0178 STREQUAL "NEW")
# Preserve old behavior where empty list items are silently discarded
set(test_executor_orig "${test_executor}")
set(test_executor ${test_executor})
set(arg_EXTRA_ARGS_orig "${arg_EXTRA_ARGS}")
set(arg_EXTRA_ARGS ${arg_EXTRA_ARGS})
if(NOT cmp0178 STREQUAL "OLD")
if(NOT "${test_executor}" STREQUAL "${test_executor_orig}")
cmake_policy(GET_WARNING CMP0178 cmp0178_warning)
message(AUTHOR_WARNING
"The '${target}' target's TEST_LAUNCHER or CROSSCOMPILING_EMULATOR "
"test properties contain one or more empty values. Those empty "
"values are being silently discarded to preserve backward "
"compatibility.\n"
"${cmp0178_warning}"
)
endif()
if(NOT "${arg_EXTRA_ARGS}" STREQUAL "${arg_EXTRA_ARGS_orig}")
cmake_policy(GET_WARNING CMP0178 cmp0178_warning)
message(AUTHOR_WARNING
"The EXTRA_ARGS value contains one or more empty values. "
"Those empty values are being silently discarded to preserve "
"backward compatibility.\n"
"${cmp0178_warning}"
)
endif()
endif()
endif()
if(arg_DISCOVERY_MODE STREQUAL "POST_BUILD")
add_custom_command(
TARGET ${target} POST_BUILD