diff options
author | Brad King <brad.king@kitware.com> | 2024-10-02 12:11:37 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2024-10-02 12:11:57 (GMT) |
commit | 823e0a3a6187f02c06b86c32d6966eff25b9abc8 (patch) | |
tree | 8215f0d010f3bcc7fb50bef49c29a937b80f4884 | |
parent | d8bdc9f3af34173c240e7209f2a0c0303f832e8e (diff) | |
parent | fc7aa3cd69eee1cdb001e6a28f36ddd01cefe720 (diff) | |
download | CMake-823e0a3a6187f02c06b86c32d6966eff25b9abc8.zip CMake-823e0a3a6187f02c06b86c32d6966eff25b9abc8.tar.gz CMake-823e0a3a6187f02c06b86c32d6966eff25b9abc8.tar.bz2 |
Merge topic 'preserve-empty-args-test-command-lines'
fc7aa3cd69 tests: Preserve empty arguments in test command lines
9f1703530b Help: Add pre-test to prose for gtest_discover_tests()
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !9575
27 files changed, 521 insertions, 89 deletions
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 3b97848..796ce8b 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -57,6 +57,7 @@ Policies Introduced by CMake 3.31 .. toctree:: :maxdepth: 1 + CMP0178: Test command lines preserve empty arguments. </policy/CMP0178> CMP0177: install() DESTINATION paths are normalized. </policy/CMP0177> CMP0176: execute_process() ENCODING is UTF-8 by default. </policy/CMP0176> CMP0175: add_custom_command() rejects invalid arguments. </policy/CMP0175> diff --git a/Help/policy/CMP0178.rst b/Help/policy/CMP0178.rst new file mode 100644 index 0000000..f6152eb --- /dev/null +++ b/Help/policy/CMP0178.rst @@ -0,0 +1,37 @@ +CMP0178 +------- + +.. versionadded:: 3.31 + +Test command lines preserve empty arguments. + +Empty values in the :prop_tgt:`TEST_LAUNCHER` and +:prop_tgt:`CROSSCOMPILING_EMULATOR` target properties are now preserved +for tests added by the following: + +* The :command:`add_test` command. +* The :command:`ExternalData_Add_Test` command from the :module:`ExternalData` + module. +* The :command:`gtest_add_tests` or :command:`gtest_discover_tests` commands + from the :module:`GoogleTest` module. + +For the :command:`gtest_add_tests` and :command:`gtest_discover_tests` +commands, empty elements in the values passed after the ``EXTRA_ARGS`` +keyword are also now preserved. + +The ``OLD`` behavior of this policy silently discards empty list items +from the :prop_tgt:`TEST_LAUNCHER` and :prop_tgt:`CROSSCOMPILING_EMULATOR` +target properties in the above-mentioned cases. It also silently discards +empty items from the values given after ``EXTRA_ARGS`` for the +:command:`gtest_add_tests` and :command:`gtest_discover_tests` commands. + +The ``NEW`` behavior of this policy preserves empty list items in the +:prop_tgt:`TEST_LAUNCHER` and :prop_tgt:`CROSSCOMPILING_EMULATOR` target +properties, and in values given after ``EXTRA_ARGS`` for +:command:`gtest_add_tests` and :command:`gtest_discover_tests`. + +.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.31 +.. |WARNS_OR_DOES_NOT_WARN| replace:: warns +.. include:: STANDARD_ADVICE.txt + +.. include:: DEPRECATED.txt diff --git a/Help/release/dev/preserve-empty-args-test-command-lines.rst b/Help/release/dev/preserve-empty-args-test-command-lines.rst new file mode 100644 index 0000000..a533ac8 --- /dev/null +++ b/Help/release/dev/preserve-empty-args-test-command-lines.rst @@ -0,0 +1,19 @@ +preserve-empty-args-test-command-lines +-------------------------------------- + +* Empty list elements in the :prop_tgt:`TEST_LAUNCHER` and + :prop_tgt:`CROSSCOMPILING_EMULATOR` target properties are now preserved + when the executable for a command given to :command:`add_test` is a CMake + target. See policy :policy:`CMP0178`. + +* Empty list elements in the :prop_tgt:`TEST_LAUNCHER` and + :prop_tgt:`CROSSCOMPILING_EMULATOR` target properties are now preserved + for the test created by :command:`ExternalData_Add_Test` from the + :module:`ExternalData` module. See policy :policy:`CMP0178`. + +* Empty list elements in the :prop_tgt:`TEST_LAUNCHER` and + :prop_tgt:`CROSSCOMPILING_EMULATOR` target properties are now preserved + for tests created by :command:`gtest_add_tests` and + :command:`gtest_discover_tests` from the :module:`GoogleTest` module. + Empty list elements after the ``EXTRA_ARGS`` keyword of these two commands + are also now preserved. See policy :policy:`CMP0178`. diff --git a/Modules/AndroidTestUtilities.cmake b/Modules/AndroidTestUtilities.cmake index 55efb36..319710b 100644 --- a/Modules/AndroidTestUtilities.cmake +++ b/Modules/AndroidTestUtilities.cmake @@ -147,6 +147,8 @@ function(android_add_test_data test_name) if(ANDROID) string(REGEX REPLACE "DATA{([^ ;]+)}" "\\1" processed_FILES "${AST_FILES}") + # There's no target used for this command, so we don't need to do anything + # here for CMP0178. add_test( NAME ${test_name} COMMAND ${CMAKE_COMMAND} diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake index 6826c7b..055a0ee 100644 --- a/Modules/ExternalData.cmake +++ b/Modules/ExternalData.cmake @@ -72,6 +72,12 @@ Module Functions It passes its arguments through ``ExternalData_Expand_Arguments`` and then invokes the :command:`add_test` command using the results. + .. versionchanged:: 3.31 + If the arguments after ``<target>`` define a test with an executable + that is a CMake target, empty values in the :prop_tgt:`TEST_LAUNCHER` + and :prop_tgt:`CROSSCOMPILING_EMULATOR` properties of that target are + preserved. See policy :policy:`CMP0178`. + .. command:: ExternalData_Add_Target The ``ExternalData_Add_Target`` function creates a custom target to @@ -353,7 +359,17 @@ file or set a variable: function(ExternalData_add_test target) # Expand all arguments as a single string to preserve escaped semicolons. ExternalData_expand_arguments("${target}" testArgs "${ARGN}") - add_test(${testArgs}) + + # We need the caller's CMP0178 policy setting to apply here + cmake_policy(GET CMP0178 cmp0178 + PARENT_SCOPE # undocumented, do not use outside of CMake + ) + + # ExternalData_expand_arguments() escapes semicolons, so we should still be + # preserving empty elements from ARGN here. But CMP0178 is still important + # for correctly handling TEST_LAUNCHER and CROSSCOMPILING_EMULATOR target + # properties that contain empty elements. + add_test(${testArgs} __CMP0178 "${cmp0178}") endfunction() function(ExternalData_add_target target) diff --git a/Modules/FindCxxTest.cmake b/Modules/FindCxxTest.cmake index a3283fa..ceb6e29 100644 --- a/Modules/FindCxxTest.cmake +++ b/Modules/FindCxxTest.cmake @@ -163,6 +163,8 @@ macro(CXXTEST_ADD_TEST _cxxtest_testname _cxxtest_outfname) set_source_files_properties(${_cxxtest_real_outfname} PROPERTIES GENERATED true) add_executable(${_cxxtest_testname} ${_cxxtest_real_outfname} ${ARGN}) + # There's no target used for these commands, so we don't need to do + # anything here for CMP0178. if(CMAKE_RUNTIME_OUTPUT_DIRECTORY) add_test(${_cxxtest_testname} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_cxxtest_testname}) elseif(EXECUTABLE_OUTPUT_PATH) diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake index 91aee5e..c94ef72 100644 --- a/Modules/FindMatlab.cmake +++ b/Modules/FindMatlab.cmake @@ -1012,6 +1012,10 @@ function(matlab_add_unit_test) endif() endif() + # The ${${prefix}_TEST_ARGS} and ${${prefix}_UNPARSED_ARGUMENTS} used below + # should have semicolons escaped, so empty arguments should be preserved. + # There's also no target used for the command, so we don't need to do + # anything here for CMP0178. add_test(NAME ${${prefix}_NAME} COMMAND ${CMAKE_COMMAND} "-Dtest_name=${${prefix}_NAME}" diff --git a/Modules/FindSquish.cmake b/Modules/FindSquish.cmake index 9a17fdb..bb4caa1 100644 --- a/Modules/FindSquish.cmake +++ b/Modules/FindSquish.cmake @@ -200,6 +200,8 @@ macro(squish_v3_add_test testName testAUT testCase envVars testWraper) message(STATUS "Using squish_v3_add_test(), but SQUISH_VERSION_MAJOR is ${SQUISH_VERSION_MAJOR}.\nThis may not work.") endif() + # There's no target used for this command, so we don't need to do anything + # here for CMP0178. add_test(${testName} ${CMAKE_COMMAND} -V -VV "-Dsquish_version:STRING=3" @@ -258,6 +260,8 @@ function(squish_v4_add_test testName) message("SETTINGSGROUP is deprecated and will be ignored.") endif() + # There's no target used for this command, so we don't need to do anything + # here for CMP0178. add_test(NAME ${testName} COMMAND ${CMAKE_COMMAND} -V -VV "-Dsquish_version:STRING=4" diff --git a/Modules/FindXCTest.cmake b/Modules/FindXCTest.cmake index a01c010..92ee25d 100644 --- a/Modules/FindXCTest.cmake +++ b/Modules/FindXCTest.cmake @@ -210,6 +210,8 @@ function(xctest_add_test name bundle) # register test + # There's no target used for this command, so we don't need to do anything + # here for CMP0178. add_test( NAME ${name} COMMAND ${XCTest_EXECUTABLE} $<TARGET_BUNDLE_DIR:${bundle}>) diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake index b959c53..1c45161 100644 --- a/Modules/GoogleTest.cmake +++ b/Modules/GoogleTest.cmake @@ -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] @@ -162,15 +170,15 @@ same as the Google Test name (i.e. ``suite.testcase``); see also .. versionadded:: 3.10 - ``gtest_discover_tests()`` sets up a post-build command on the test executable - that generates the list of tests by parsing the output from running the test - with the ``--gtest_list_tests`` argument. Compared to the source parsing - approach of :command:`gtest_add_tests`, this ensures that the full list of - tests, including instantiations of parameterized tests, is obtained. Since - test discovery occurs at build time, it is not necessary to re-run CMake when - the list of tests changes. - However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set - in order to function in a cross-compiling environment. + ``gtest_discover_tests()`` sets up a post-build or pre-test command on the + test executable that generates the list of tests by parsing the output from + running the test executable with the ``--gtest_list_tests`` argument. + Compared to the source parsing approach of :command:`gtest_add_tests`, + this ensures that the full list of tests, including instantiations of + parameterized tests, is obtained. Since test discovery occurs at build + or test time, it is not necessary to re-run CMake when the list of tests + changes. However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` + is properly set in order to function in a cross-compiling environment. Additionally, setting properties on tests is somewhat less convenient, since the tests are not available at CMake time. Additional test properties may be @@ -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 diff --git a/Modules/GoogleTestAddTests.cmake b/Modules/GoogleTestAddTests.cmake index b654bb0..b8ca3fc 100644 --- a/Modules/GoogleTestAddTests.cmake +++ b/Modules/GoogleTestAddTests.cmake @@ -2,6 +2,7 @@ # file Copyright.txt or https://cmake.org/licensing for details. cmake_minimum_required(VERSION 3.30) +cmake_policy(SET CMP0174 NEW) # TODO: Remove this when we can update the above to 3.31 # Overwrite possibly existing ${arg_CTEST_FILE} with empty file set(flush_tests_MODE WRITE) @@ -65,9 +66,9 @@ endfunction() function(gtest_discover_tests_impl) - set(options ) + set(options "") set(oneValueArgs - NO_PRETTY_TYPES # These two take a value, unlike gtest_discover_tests + NO_PRETTY_TYPES # These two take a value, unlike gtest_discover_tests() NO_PRETTY_VALUES # TEST_EXECUTABLE TEST_WORKING_DIR @@ -77,22 +78,21 @@ function(gtest_discover_tests_impl) CTEST_FILE TEST_DISCOVERY_TIMEOUT TEST_XML_OUTPUT_DIR - TEST_FILTER # This is a multi-value argument in gtest_discover_tests - ) - set(multiValueArgs + # The following are all multi-value arguments in gtest_discover_tests(), + # but they are each given to us as a single argument. We parse them that + # way to avoid problems with preserving empty list values and escaping. + TEST_FILTER TEST_EXTRA_ARGS TEST_PROPERTIES TEST_EXECUTOR ) - cmake_parse_arguments(arg + set(multiValueArgs "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${options}" "${oneValueArgs}" "${multiValueArgs}" - ${ARGN} ) set(prefix "${arg_TEST_PREFIX}") set(suffix "${arg_TEST_SUFFIX}") - set(extra_args ${arg_TEST_EXTRA_ARGS}) - set(properties ${arg_TEST_PROPERTIES}) set(script) set(suite) set(tests) @@ -104,6 +104,16 @@ function(gtest_discover_tests_impl) set(filter) endif() + # CMP0178 has already been handled in gtest_discover_tests(), so we only need + # to implement NEW behavior here. This means preserving empty arguments for + # TEST_EXECUTOR. For OLD or WARN, gtest_discover_tests() already removed any + # empty arguments. + set(launcherArgs "") + if(NOT "${arg_TEST_EXECUTOR}" STREQUAL "") + list(JOIN arg_TEST_EXECUTOR "]==] [==[" launcherArgs) + set(launcherArgs "[==[${launcherArgs}]==]") + endif() + # Run test executable to get list of available tests if(NOT EXISTS "${arg_TEST_EXECUTABLE}") message(FATAL_ERROR @@ -111,12 +121,14 @@ function(gtest_discover_tests_impl) " Path: '${arg_TEST_EXECUTABLE}'" ) endif() - execute_process( - COMMAND ${arg_TEST_EXECUTOR} "${arg_TEST_EXECUTABLE}" --gtest_list_tests ${filter} - WORKING_DIRECTORY "${arg_TEST_WORKING_DIR}" - TIMEOUT ${arg_TEST_DISCOVERY_TIMEOUT} - OUTPUT_VARIABLE output - RESULT_VARIABLE result + cmake_language(EVAL CODE + "execute_process( + COMMAND ${launcherArgs} [==[${arg_TEST_EXECUTABLE}]==] --gtest_list_tests ${filter} + WORKING_DIRECTORY [==[${arg_TEST_WORKING_DIR}]==] + TIMEOUT ${arg_TEST_DISCOVERY_TIMEOUT} + OUTPUT_VARIABLE output + RESULT_VARIABLE result + )" ) if(NOT ${result} EQUAL 0) string(REPLACE "\n" "\n " output "${output}") @@ -188,16 +200,36 @@ function(gtest_discover_tests_impl) endif() set(guarded_testname "${open_guard}${testname}${close_guard}") - # add to script - add_command(add_test - "${guarded_testname}" - ${arg_TEST_EXECUTOR} + # Add to script. Do not use add_command() here because it messes up the + # handling of empty values when forwarding arguments, and we need to + # preserve those carefully for arg_TEST_EXECUTOR and arg_EXTRA_ARGS. + string(APPEND script "add_test(${guarded_testname} ${launcherArgs}") + foreach(arg IN ITEMS "${arg_TEST_EXECUTABLE}" "--gtest_filter=${suite}.${test}" "--gtest_also_run_disabled_tests" ${TEST_XML_OUTPUT_PARAM} - ${extra_args} - ) + ) + if(arg MATCHES "[^-./:a-zA-Z0-9_]") + string(APPEND script " [==[${arg}]==]") + else() + string(APPEND script " ${arg}") + endif() + endforeach() + if(arg_TEST_EXTRA_ARGS) + list(JOIN arg_TEST_EXTRA_ARGS "]==] [==[" extra_args) + string(APPEND script " [==[${extra_args}]==]") + endif() + string(APPEND script ")\n") + string(LENGTH "${script}" script_len) + if(${script_len} GREATER "50000") + # flush_script() expects to set variables in the parent scope, so we + # need to create one since we actually want the changes in our scope + block(SCOPE_FOR VARIABLES) + flush_script() + endblock() + endif() + if(suite MATCHES "^DISABLED_" OR test MATCHES "^DISABLED_") add_command(set_tests_properties "${guarded_testname}" @@ -210,7 +242,7 @@ function(gtest_discover_tests_impl) PROPERTIES WORKING_DIRECTORY "${arg_TEST_WORKING_DIR}" SKIP_REGULAR_EXPRESSION "\\[ SKIPPED \\]" - ${properties} + ${arg_TEST_PROPERTIES} ) # possibly unbalanced square brackets render lists invalid so skip such @@ -244,7 +276,7 @@ if(CMAKE_SCRIPT_MODE_FILE) NO_PRETTY_TYPES ${NO_PRETTY_TYPES} NO_PRETTY_VALUES ${NO_PRETTY_VALUES} TEST_EXECUTABLE ${TEST_EXECUTABLE} - TEST_EXECUTOR ${TEST_EXECUTOR} + TEST_EXECUTOR "${TEST_EXECUTOR}" TEST_WORKING_DIR ${TEST_WORKING_DIR} TEST_PREFIX ${TEST_PREFIX} TEST_SUFFIX ${TEST_SUFFIX} @@ -253,7 +285,7 @@ if(CMAKE_SCRIPT_MODE_FILE) CTEST_FILE ${CTEST_FILE} TEST_DISCOVERY_TIMEOUT ${TEST_DISCOVERY_TIMEOUT} TEST_XML_OUTPUT_DIR ${TEST_XML_OUTPUT_DIR} - TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS} - TEST_PROPERTIES ${TEST_PROPERTIES} + TEST_EXTRA_ARGS "${TEST_EXTRA_ARGS}" + TEST_PROPERTIES "${TEST_PROPERTIES}" ) endif() diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx index a0d5732..ff17e87 100644 --- a/Source/cmAddTestCommand.cxx +++ b/Source/cmAddTestCommand.cxx @@ -2,14 +2,19 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmAddTestCommand.h" +#include <algorithm> + #include <cm/memory> #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmPolicies.h" #include "cmStringAlgorithms.h" #include "cmTest.h" #include "cmTestGenerator.h" +static std::string const keywordCMP0178 = "__CMP0178"; + static bool cmAddTestCommandHandleNameMode( std::vector<std::string> const& args, cmExecutionStatus& status); @@ -29,8 +34,30 @@ bool cmAddTestCommand(std::vector<std::string> const& args, } cmMakefile& mf = status.GetMakefile(); + cmPolicies::PolicyStatus cmp0178; + + // If the __CMP0178 keyword is present, it is always at the end + auto endOfCommandIter = + std::find(args.begin() + 2, args.end(), keywordCMP0178); + if (endOfCommandIter != args.end()) { + auto cmp0178Iter = endOfCommandIter + 1; + if (cmp0178Iter == args.end()) { + status.SetError(cmStrCat(keywordCMP0178, " keyword missing value")); + return false; + } + if (*cmp0178Iter == "NEW") { + cmp0178 = cmPolicies::PolicyStatus::NEW; + } else if (*cmp0178Iter == "OLD") { + cmp0178 = cmPolicies::PolicyStatus::OLD; + } else { + cmp0178 = cmPolicies::PolicyStatus::WARN; + } + } else { + cmp0178 = mf.GetPolicyStatus(cmPolicies::CMP0178); + } + // Collect the command with arguments. - std::vector<std::string> command(args.begin() + 1, args.end()); + std::vector<std::string> command(args.begin() + 1, endOfCommandIter); // Create the test but add a generator only the first time it is // seen. This preserves behavior from before test generators. @@ -46,6 +73,7 @@ bool cmAddTestCommand(std::vector<std::string> const& args, } else { test = mf.CreateTest(args[0]); test->SetOldStyle(true); + test->SetCMP0178(cmp0178); mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test)); } test->SetCommand(command); @@ -56,11 +84,14 @@ bool cmAddTestCommand(std::vector<std::string> const& args, bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args, cmExecutionStatus& status) { + cmMakefile& mf = status.GetMakefile(); + std::string name; std::vector<std::string> configurations; std::string working_directory; std::vector<std::string> command; bool command_expand_lists = false; + cmPolicies::PolicyStatus cmp0178 = mf.GetPolicyStatus(cmPolicies::CMP0178); // Read the arguments. enum Doing @@ -69,6 +100,7 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args, DoingCommand, DoingConfigs, DoingWorkingDirectory, + DoingCmp0178, DoingNone }; Doing doing = DoingName; @@ -91,6 +123,8 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args, return false; } doing = DoingWorkingDirectory; + } else if (args[i] == keywordCMP0178) { + doing = DoingCmp0178; } else if (args[i] == "COMMAND_EXPAND_LISTS") { if (command_expand_lists) { status.SetError(" may be given at most one COMMAND_EXPAND_LISTS."); @@ -108,6 +142,15 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args, } else if (doing == DoingWorkingDirectory) { working_directory = args[i]; doing = DoingNone; + } else if (doing == DoingCmp0178) { + if (args[i] == "NEW") { + cmp0178 = cmPolicies::PolicyStatus::NEW; + } else if (args[i] == "OLD") { + cmp0178 = cmPolicies::PolicyStatus::OLD; + } else { + cmp0178 = cmPolicies::PolicyStatus::WARN; + } + doing = DoingNone; } else { status.SetError(cmStrCat(" given unknown argument:\n ", args[i], "\n")); return false; @@ -126,8 +169,6 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args, return false; } - cmMakefile& mf = status.GetMakefile(); - // Require a unique test name within the directory. if (mf.GetTest(name)) { status.SetError(cmStrCat(" given test NAME \"", name, @@ -138,6 +179,7 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args, // Add the test. cmTest* test = mf.CreateTest(name); test->SetOldStyle(false); + test->SetCMP0178(cmp0178); test->SetCommand(command); if (!working_directory.empty()) { test->SetProperty("WORKING_DIRECTORY", working_directory); diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 88ced3f..e2254fe 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -543,6 +543,8 @@ class cmMakefile; SELECT(POLICY, CMP0176, "execute_process() ENCODING is UTF-8 by default.", \ 3, 31, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0177, "install() DESTINATION paths are normalized.", 3, \ + 31, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0178, "Test command lines preserve empty arguments.", 3, \ 31, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index 8a39144..c72e020 100644 --- a/Source/cmTest.cxx +++ b/Source/cmTest.cxx @@ -10,6 +10,7 @@ cmTest::cmTest(cmMakefile* mf) : Backtrace(mf->GetBacktrace()) , PolicyStatusCMP0158(mf->GetPolicyStatus(cmPolicies::CMP0158)) + , PolicyStatusCMP0178(mf->GetPolicyStatus(cmPolicies::CMP0178)) { this->Makefile = mf; this->OldStyle = true; diff --git a/Source/cmTest.h b/Source/cmTest.h index 480966a..244aa62 100644 --- a/Source/cmTest.h +++ b/Source/cmTest.h @@ -61,12 +61,22 @@ public: bool GetOldStyle() const { return this->OldStyle; } void SetOldStyle(bool b) { this->OldStyle = b; } - /** Get/Set if CMP0158 policy is NEW */ + /** Get if CMP0158 policy is NEW */ bool GetCMP0158IsNew() const { return this->PolicyStatusCMP0158 == cmPolicies::NEW; } + /** Get/Set the CMP0178 policy setting */ + cmPolicies::PolicyStatus GetCMP0178() const + { + return this->PolicyStatusCMP0178; + } + void SetCMP0178(cmPolicies::PolicyStatus p) + { + this->PolicyStatusCMP0178 = p; + } + /** Set/Get whether lists in command lines should be expanded. */ bool GetCommandExpandLists() const; void SetCommandExpandLists(bool b); @@ -82,4 +92,5 @@ private: cmMakefile* Makefile; cmListFileBacktrace Backtrace; cmPolicies::PolicyStatus PolicyStatusCMP0158; + cmPolicies::PolicyStatus PolicyStatusCMP0178; }; diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index 840d8cf..ffb5e21 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -174,15 +174,36 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, if (!cmNonempty(launcher)) { return; } - cmList launcherWithArgs{ ge.Parse(*launcher)->Evaluate(this->LG, - config) }; + const auto propVal = ge.Parse(*launcher)->Evaluate(this->LG, config); + cmList launcherWithArgs(propVal, cmList::ExpandElements::Yes, + this->Test->GetCMP0178() == cmPolicies::NEW + ? cmList::EmptyElements::Yes + : cmList::EmptyElements::No); if (!launcherWithArgs.empty() && !launcherWithArgs[0].empty()) { + if (this->Test->GetCMP0178() == cmPolicies::WARN) { + cmList argsWithEmptyValuesPreserved( + propVal, cmList::ExpandElements::Yes, cmList::EmptyElements::Yes); + if (launcherWithArgs != argsWithEmptyValuesPreserved) { + this->Test->GetMakefile()->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat("The ", propertyName, " property of target '", + target->GetName(), + "' contains empty list items. Those empty items are " + "being silently discarded to preserve backward " + "compatibility.\n", + cmPolicies::GetPolicyWarning(cmPolicies::CMP0178))); + } + } std::string launcherExe(launcherWithArgs[0]); cmSystemTools::ConvertToUnixSlashes(launcherExe); os << cmOutputConverter::EscapeForCMake(launcherExe) << " "; for (std::string const& arg : cmMakeRange(launcherWithArgs).advance(1)) { - os << cmOutputConverter::EscapeForCMake(arg) << " "; + if (arg.empty()) { + os << "\"\" "; + } else { + os << cmOutputConverter::EscapeForCMake(arg) << " "; + } } } }; diff --git a/Tests/RunCMake/GoogleTest/GoogleTestLauncher-test-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTestLauncher-test-stdout.txt deleted file mode 100644 index 6313151..0000000 --- a/Tests/RunCMake/GoogleTest/GoogleTestLauncher-test-stdout.txt +++ /dev/null @@ -1,17 +0,0 @@ -1: Test command: "?[^ -]*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]GoogleTestLauncher-build([/\]Debug)?[/\]test_launcher(\.exe)?"? "launcherparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/GoogleTestLauncher-build(/Debug)?/test_launcher(\.exe)?" "emulatorparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/GoogleTestLauncher-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" -1: Working Directory: [^ -]*/Tests/RunCMake/GoogleTest/GoogleTestLauncher-build -1: Test timeout computed to be: [0-9]+ -1: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]GoogleTestLauncher-build([/\]Debug)?[/\]test_launcher(\.exe)?' -1: test_launcher: got arg 1 'launcherparam' -1: test_launcher: got arg 2 '--' -1: test_launcher: got arg 3 '[^']*/Tests/RunCMake/GoogleTest/GoogleTestLauncher-build(/Debug)?/test_launcher(\.exe)?' -1: launching: "[^"]*/Tests/RunCMake/GoogleTest/GoogleTestLauncher-build(/Debug)?/test_launcher(\.exe)?" "emulatorparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/GoogleTestLauncher-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" -1: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]GoogleTestLauncher-build([/\]Debug)?[/\]test_launcher(\.exe)?' -1: test_launcher: got arg 1 'emulatorparam' -1: test_launcher: got arg 2 '--' -1: test_launcher: got arg 3 '[^']*/Tests/RunCMake/GoogleTest/GoogleTestLauncher-build(/Debug)?/launcher_test(\.exe)?' -1: launching: "[^"]*/Tests/RunCMake/GoogleTest/GoogleTestLauncher-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" -1: launcher_test\.test1 -1/1 Test #1: launcher_test\.test1 [.]+ +Passed +[0-9.]+ sec diff --git a/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-test-stdout.txt b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-test-stdout.txt new file mode 100644 index 0000000..24cb1b1 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-test-stdout.txt @@ -0,0 +1,38 @@ +test 1 + Start 1: launcher_test\.test1 + +1: Test command: [^ +]*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-NEW-build([/\]Debug)?[/\]test_launcher(\.exe)?"? "" "launcherparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/test_launcher(\.exe)?" "" "emulatorparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "" "b" +1: Working Directory: [^ +]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build +1: Test timeout computed to be: [0-9]+ +1: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-NEW-build([/\]Debug)?[/\]test_launcher(\.exe)?' +1: test_launcher: got arg 1 '' +1: test_launcher: got arg 2 'launcherparam' +1: test_launcher: got arg 3 '--' +1: test_launcher: got arg 4 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/test_launcher(\.exe)?' +1: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/test_launcher(\.exe)?" "" "emulatorparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "" "b" +1: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-NEW-build([/\]Debug)?[/\]test_launcher(\.exe)?' +1: test_launcher: got arg 1 '' +1: test_launcher: got arg 2 'emulatorparam' +1: test_launcher: got arg 3 '--' +1: test_launcher: got arg 4 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/launcher_test(\.exe)?' +1: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "" "b" +1: launcher_test\.test1 +1/2 Test #1: launcher_test\.test1 [.]+ +Passed +[0-9.]+ sec +test 2 + Start 2: launcher_test\.test1 + +2: Test command: [^ +]*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-NEW-build([/\]Debug)?[/\]test_launcher(\.exe)?"? "" "launcherparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "a" "" "b" +2: Working Directory: [^ +]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build +2: Test timeout computed to be: [0-9]+ +2: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-NEW-build([/\]Debug)?[/\]test_launcher(\.exe)?' +2: test_launcher: got arg 1 '' +2: test_launcher: got arg 2 'launcherparam' +2: test_launcher: got arg 3 '--' +2: test_launcher: got arg 4 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/launcher_test(\.exe)?' +2: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "a" "" "b" +2: launcher_test.test1 +2/2 Test #2: launcher_test\.test1 [.]+ +Passed +[0-9.]+ sec diff --git a/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW.cmake b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW.cmake new file mode 100644 index 0000000..1621abc --- /dev/null +++ b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-NEW.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0178 NEW) +include(Launcher.cmake) diff --git a/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-test-stdout.txt b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-test-stdout.txt new file mode 100644 index 0000000..0b76200 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-test-stdout.txt @@ -0,0 +1,35 @@ +test 1 + Start 1: launcher_test\.test1 + +1: Test command: "?[^ +]*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-OLD-build([/\]Debug)?[/\]test_launcher(\.exe)?"? "launcherparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/test_launcher(\.exe)?" "emulatorparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "b" +1: Working Directory: [^ +]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build +1: Test timeout computed to be: [0-9]+ +1: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-OLD-build([/\]Debug)?[/\]test_launcher(\.exe)?' +1: test_launcher: got arg 1 'launcherparam' +1: test_launcher: got arg 2 '--' +1: test_launcher: got arg 3 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/test_launcher(\.exe)?' +1: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/test_launcher(\.exe)?" "emulatorparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "b" +1: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-OLD-build([/\]Debug)?[/\]test_launcher(\.exe)?' +1: test_launcher: got arg 1 'emulatorparam' +1: test_launcher: got arg 2 '--' +1: test_launcher: got arg 3 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/launcher_test(\.exe)?' +1: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "b" +1: launcher_test\.test1 +1/2 Test #1: launcher_test\.test1 [.]+ +Passed +[0-9.]+ sec +test 2 + Start 2: launcher_test\.test1 + +2: Test command: [^ +]*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-OLD-build([/\]Debug)?[/\]test_launcher(\.exe)?"? "launcherparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "a" "b" +2: Working Directory: [^ +]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build +2: Test timeout computed to be: [0-9]+ +2: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-OLD-build([/\]Debug)?[/\]test_launcher(\.exe)?' +2: test_launcher: got arg 1 'launcherparam' +2: test_launcher: got arg 2 '--' +2: test_launcher: got arg 3 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/launcher_test(\.exe)?' +2: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "a" "b" +2: launcher_test.test1 +2/2 Test #2: launcher_test\.test1 [.]+ +Passed +[0-9.]+ sec diff --git a/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD.cmake b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD.cmake new file mode 100644 index 0000000..8830cd0 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-OLD.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0178 OLD) +include(Launcher.cmake) diff --git a/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-stderr.txt b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-stderr.txt new file mode 100644 index 0000000..00b4939 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-stderr.txt @@ -0,0 +1,38 @@ +CMake Warning \(dev\) at [^ +]*/Modules/GoogleTest\.cmake:[0-9]+ \(message\): + The 'launcher_test' 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\. + + Policy CMP0178 is not set: Test command lines preserve empty arguments\. + Run "cmake --help-policy CMP0178" for policy details\. Use the cmake_policy + command to set the policy and suppress this warning\. +Call Stack \(most recent call first\): + Launcher\.cmake:[0-9]+ \(gtest_discover_tests\) + Launcher-CMP0178-WARN\.cmake:1 \(include\) + CMakeLists\.txt:3 \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. + +CMake Warning \(dev\) at [^ +]*/Modules/GoogleTest\.cmake:[0-9]+ \(message\): + The EXTRA_ARGS value contains one or more empty values\. Those empty values + are being silently discarded to preserve backward compatibility\. + + Policy CMP0178 is not set: Test command lines preserve empty arguments\. + Run "cmake --help-policy CMP0178" for policy details\. Use the cmake_policy + command to set the policy and suppress this warning\. +Call Stack \(most recent call first\): + Launcher\.cmake:[0-9]+ \(gtest_discover_tests\) + Launcher-CMP0178-WARN\.cmake:1 \(include\) + CMakeLists\.txt:3 \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. + +CMake Warning \(dev\) in CMakeLists\.txt: + The TEST_LAUNCHER property of target 'launcher_test' contains empty list + items\. Those empty items are being silently discarded to preserve backward + compatibility\. + + Policy CMP0178 is not set: Test command lines preserve empty arguments\. + Run "cmake --help-policy CMP0178" for policy details\. Use the cmake_policy + command to set the policy and suppress this warning\. +This warning is for project developers\. Use -Wno-dev to suppress it\. diff --git a/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-test-stdout.txt b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-test-stdout.txt new file mode 100644 index 0000000..1db6f50 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-test-stdout.txt @@ -0,0 +1,35 @@ +test 1 + Start 1: launcher_test\.test1 + +1: Test command: "?[^ +]*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-WARN-build([/\]Debug)?[/\]test_launcher(\.exe)?"? "launcherparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/test_launcher(\.exe)?" "emulatorparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "b" +1: Working Directory: [^ +]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build +1: Test timeout computed to be: [0-9]+ +1: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-WARN-build([/\]Debug)?[/\]test_launcher(\.exe)?' +1: test_launcher: got arg 1 'launcherparam' +1: test_launcher: got arg 2 '--' +1: test_launcher: got arg 3 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/test_launcher(\.exe)?' +1: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/test_launcher(\.exe)?" "emulatorparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "b" +1: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-WARN-build([/\]Debug)?[/\]test_launcher(\.exe)?' +1: test_launcher: got arg 1 'emulatorparam' +1: test_launcher: got arg 2 '--' +1: test_launcher: got arg 3 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/launcher_test(\.exe)?' +1: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "--gtest_also_run_disabled_tests" "a" "b" +1: launcher_test\.test1 +1/2 Test #1: launcher_test\.test1 [.]+ +Passed +[0-9.]+ sec +test 2 + Start 2: launcher_test\.test1 + +2: Test command: [^ +]*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-WARN-build([/\]Debug)?[/\]test_launcher(\.exe)?"? "launcherparam" "--" "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "a" "b" +2: Working Directory: [^ +]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build +2: Test timeout computed to be: [0-9]+ +2: test_launcher: got arg 0 '[^']*[/\]Tests[/\]RunCMake[/\]GoogleTest[/\]Launcher-CMP0178-WARN-build([/\]Debug)?[/\]test_launcher(\.exe)?' +2: test_launcher: got arg 1 'launcherparam' +2: test_launcher: got arg 2 '--' +2: test_launcher: got arg 3 '[^']*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/launcher_test(\.exe)?' +2: launching: "[^"]*/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN-build(/Debug)?/launcher_test(\.exe)?" "--gtest_filter=launcher_test\.test1" "a" "b" +2: launcher_test.test1 +2/2 Test #2: launcher_test\.test1 [.]+ +Passed +[0-9.]+ sec diff --git a/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN.cmake b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN.cmake new file mode 100644 index 0000000..e109075 --- /dev/null +++ b/Tests/RunCMake/GoogleTest/Launcher-CMP0178-WARN.cmake @@ -0,0 +1 @@ +include(Launcher.cmake) diff --git a/Tests/RunCMake/GoogleTest/GoogleTestLauncher.cmake b/Tests/RunCMake/GoogleTest/Launcher.cmake index 5f4e6eb..11ba87e 100644 --- a/Tests/RunCMake/GoogleTest/GoogleTestLauncher.cmake +++ b/Tests/RunCMake/GoogleTest/Launcher.cmake @@ -11,14 +11,14 @@ add_executable(launcher_test launcher_test.c) xcode_sign_adhoc(launcher_test) set(launcher "$<TARGET_FILE:test_launcher>" - "" # Verify that an empty list item will be preserved + "" # Verify CMP0178's handling of an empty list item "launcherparam" "--" ) set_property(TARGET launcher_test PROPERTY TEST_LAUNCHER "${launcher}") set(emulator "$<TARGET_FILE:test_launcher>" - "" # Verify that an empty list item will be preserved + "" # Verify CMP0178's handling of an empty list item "emulatorparam" "--" ) @@ -26,4 +26,10 @@ set_property(TARGET launcher_test PROPERTY CROSSCOMPILING_EMULATOR "${emulator}" gtest_discover_tests( launcher_test + EXTRA_ARGS a "" b +) + +gtest_add_tests( + TARGET launcher_test + EXTRA_ARGS a "" b ) diff --git a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake index 08cc274..e1bff64 100644 --- a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake +++ b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake @@ -101,7 +101,7 @@ function(run_GoogleTest DISCOVERY_MODE) ) endfunction() -function(run_GoogleTestLauncher DISCOVERY_MODE) +function(run_Launcher_CMP0178 DISCOVERY_MODE cmp0178) if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "14.0") return() endif() @@ -110,12 +110,12 @@ function(run_GoogleTestLauncher DISCOVERY_MODE) endif() # Use a single build tree for a few tests without cleaning. - set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTestLauncher-build) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Launcher-CMP0178-${cmp0178}-build) if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug) endif() - run_cmake_with_options(GoogleTestLauncher + run_cmake_with_options(Launcher-CMP0178-${cmp0178} -DCMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE=${DISCOVERY_MODE} ) @@ -123,14 +123,14 @@ function(run_GoogleTestLauncher DISCOVERY_MODE) # do not issue any warnings on stderr that would cause the build to fail set(RunCMake_TEST_OUTPUT_MERGE 1) - run_cmake_command(GoogleTestLauncher-build + run_cmake_command(Launcher-CMP0178-${cmp0178}-build ${CMAKE_COMMAND} --build . --config Debug ) unset(RunCMake_TEST_OUTPUT_MERGE) - run_cmake_command(GoogleTestLauncher-test + run_cmake_command(Launcher-CMP0178-${cmp0178}-test ${CMAKE_CTEST_COMMAND} -C Debug -V @@ -356,11 +356,13 @@ function(run_GoogleTest_discovery_test_list_scoped DISCOVERY_MODE) endfunction() foreach(DISCOVERY_MODE POST_BUILD PRE_TEST) - message("Testing ${DISCOVERY_MODE} discovery mode via CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE global override...") + message(STATUS "Testing ${DISCOVERY_MODE} discovery mode via CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE global override...") run_GoogleTest(${DISCOVERY_MODE}) - run_GoogleTestLauncher(${DISCOVERY_MODE}) run_GoogleTestXML(${DISCOVERY_MODE}) - message("Testing ${DISCOVERY_MODE} discovery mode via DISCOVERY_MODE option...") + run_Launcher_CMP0178(${DISCOVERY_MODE} NEW) + run_Launcher_CMP0178(${DISCOVERY_MODE} OLD) + run_Launcher_CMP0178(${DISCOVERY_MODE} WARN) + message(STATUS "Testing ${DISCOVERY_MODE} discovery mode via DISCOVERY_MODE option...") run_GoogleTest_discovery_timeout(${DISCOVERY_MODE}) run_GoogleTest_discovery_arg_change(${DISCOVERY_MODE}) run_GoogleTest_discovery_test_list(${DISCOVERY_MODE}) @@ -369,6 +371,6 @@ foreach(DISCOVERY_MODE POST_BUILD PRE_TEST) endforeach() if(RunCMake_GENERATOR_IS_MULTI_CONFIG) - message("Testing PRE_TEST discovery multi configuration...") + message(STATUS "Testing PRE_TEST discovery multi configuration...") run_GoogleTest_discovery_multi_config() endif() diff --git a/Tests/RunCMake/GoogleTest/launcher_test.c b/Tests/RunCMake/GoogleTest/launcher_test.c index ce91565..eed6206 100644 --- a/Tests/RunCMake/GoogleTest/launcher_test.c +++ b/Tests/RunCMake/GoogleTest/launcher_test.c @@ -10,7 +10,7 @@ TEST_F( launcher_test, test1 ) int main(int argc, char** argv) { - /* Note: GoogleTest.cmake doesn't actually depend on Google Test as such; + /* Note: Launcher.cmake doesn't actually depend on Google Test as such; * it only requires that we produces output in the expected format when * invoked with --gtest_list_tests. Thus, we fake that here. This allows us * to test the module without actually needing Google Test. */ |