| # Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| # file Copyright.txt or https://cmake.org/licensing for details. | |
| #[=======================================================================[.rst: | |
| GoogleTest | |
| ---------- | |
| .. versionadded:: 3.9 | |
| This module defines functions to help use the Google Test infrastructure. Two | |
| mechanisms for adding tests are provided. :command:`gtest_add_tests` has been | |
| around for some time, originally via ``find_package(GTest)``. | |
| :command:`gtest_discover_tests` was introduced in CMake 3.10. | |
| The (older) :command:`gtest_add_tests` scans source files to identify tests. | |
| This is usually effective, with some caveats, including in cross-compiling | |
| environments, and makes setting additional properties on tests more convenient. | |
| However, its handling of parameterized tests is less comprehensive, and it | |
| requires re-running CMake to detect changes to the list of tests. | |
| The (newer) :command:`gtest_discover_tests` discovers tests by asking the | |
| compiled test executable to enumerate its tests. This is more robust and | |
| provides better handling of parameterized tests, and does not require CMake | |
| to be re-run when tests change. However, it may not work in a cross-compiling | |
| environment, and setting test properties is less convenient. | |
| More details can be found in the documentation of the respective functions. | |
| Both commands are intended to replace use of :command:`add_test` to register | |
| tests, and will create a separate CTest test for each Google Test test case. | |
| Note that this is in some cases less efficient, as common set-up and tear-down | |
| logic cannot be shared by multiple test cases executing in the same instance. | |
| However, it provides more fine-grained pass/fail information to CTest, which is | |
| usually considered as more beneficial. By default, the CTest test name is the | |
| same as the Google Test name (i.e. ``suite.testcase``); see also | |
| ``TEST_PREFIX`` and ``TEST_SUFFIX``. | |
| .. command:: gtest_add_tests | |
| Automatically add tests with CTest by scanning source code for Google Test | |
| macros: | |
| .. code-block:: cmake | |
| gtest_add_tests(TARGET target | |
| [SOURCES src1...] | |
| [EXTRA_ARGS args...] | |
| [WORKING_DIRECTORY dir] | |
| [TEST_PREFIX prefix] | |
| [TEST_SUFFIX suffix] | |
| [SKIP_DEPENDENCY] | |
| [TEST_LIST outVar] | |
| ) | |
| ``gtest_add_tests`` attempts to identify tests by scanning source files. | |
| Although this is generally effective, it uses only a basic regular expression | |
| match, which can be defeated by atypical test declarations, and is unable to | |
| fully "split" parameterized tests. Additionally, it requires that CMake be | |
| re-run to discover any newly added, removed or renamed tests (by default, | |
| this means that CMake is re-run when any test source file is changed, but see | |
| ``SKIP_DEPENDENCY``). However, it has the advantage of declaring tests at | |
| CMake time, which somewhat simplifies setting additional properties on tests, | |
| and always works in a cross-compiling environment. | |
| The options are: | |
| ``TARGET target`` | |
| Specifies the Google Test executable, which must be a known CMake | |
| executable target. CMake will substitute the location of the built | |
| executable when running the test. | |
| ``SOURCES src1...`` | |
| When provided, only the listed files will be scanned for test cases. If | |
| 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 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. | |
| ``TEST_PREFIX prefix`` | |
| Specifies a ``prefix`` to be prepended to the name of each discovered test | |
| case. This can be useful when the same source files are being used in | |
| multiple calls to ``gtest_add_test()`` but with different ``EXTRA_ARGS``. | |
| ``TEST_SUFFIX suffix`` | |
| Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of | |
| every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may | |
| be specified. | |
| ``SKIP_DEPENDENCY`` | |
| Normally, the function creates a dependency which will cause CMake to be | |
| re-run if any of the sources being scanned are changed. This is to ensure | |
| that the list of discovered tests is updated. If this behavior is not | |
| desired (as may be the case while actually writing the test cases), this | |
| option can be used to prevent the dependency from being added. | |
| ``TEST_LIST outVar`` | |
| The variable named by ``outVar`` will be populated in the calling scope | |
| 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 | |
| include(GoogleTest) | |
| add_executable(FooTest FooUnitTest.cxx) | |
| gtest_add_tests(TARGET FooTest | |
| TEST_SUFFIX .noArgs | |
| TEST_LIST noArgsTests | |
| ) | |
| gtest_add_tests(TARGET FooTest | |
| EXTRA_ARGS --someArg someValue | |
| TEST_SUFFIX .withArgs | |
| TEST_LIST withArgsTests | |
| ) | |
| set_tests_properties(${noArgsTests} PROPERTIES TIMEOUT 10) | |
| set_tests_properties(${withArgsTests} PROPERTIES TIMEOUT 20) | |
| For backward compatibility, the following form is also supported: | |
| .. code-block:: cmake | |
| gtest_add_tests(exe args files...) | |
| ``exe`` | |
| The path to the test executable or the name of a CMake target. | |
| ``args`` | |
| A ;-list of extra arguments to be passed to executable. The entire | |
| list must be passed as a single argument. Enclose it in quotes, | |
| or pass ``""`` for no arguments. | |
| ``files...`` | |
| A list of source files to search for tests and test fixtures. | |
| Alternatively, use ``AUTO`` to specify that ``exe`` is the name | |
| of a CMake executable target whose sources should be scanned. | |
| .. code-block:: cmake | |
| include(GoogleTest) | |
| set(FooTestArgs --foo 1 --bar 2) | |
| add_executable(FooTest FooUnitTest.cxx) | |
| gtest_add_tests(FooTest "${FooTestArgs}" AUTO) | |
| .. command:: gtest_discover_tests | |
| Automatically add tests with CTest by querying the compiled test executable | |
| for available tests: | |
| .. code-block:: cmake | |
| gtest_discover_tests(target | |
| [EXTRA_ARGS args...] | |
| [WORKING_DIRECTORY dir] | |
| [TEST_PREFIX prefix] | |
| [TEST_SUFFIX suffix] | |
| [TEST_FILTER expr] | |
| [NO_PRETTY_TYPES] [NO_PRETTY_VALUES] | |
| [PROPERTIES name1 value1...] | |
| [TEST_LIST var] | |
| [DISCOVERY_TIMEOUT seconds] | |
| [XML_OUTPUT_DIR dir] | |
| [DISCOVERY_MODE <POST_BUILD|PRE_TEST>] | |
| [DISCOVERY_EXTRA_ARGS args...] | |
| ) | |
| .. versionadded:: 3.10 | |
| ``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 | |
| assigned to the set of tests as a whole using the ``PROPERTIES`` option. If | |
| more fine-grained test control is needed, custom content may be provided | |
| through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES` | |
| directory property. The set of discovered tests is made accessible to such a | |
| script via the ``<target>_TESTS`` variable (see the ``TEST_LIST`` option | |
| below for further discussion and limitations). | |
| The options are: | |
| ``target`` | |
| Specifies the Google Test executable, which must be a known CMake | |
| executable target. CMake will substitute the location of the built | |
| executable when running the test. | |
| ``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. | |
| ``TEST_PREFIX prefix`` | |
| Specifies a ``prefix`` to be prepended to the name of each discovered test | |
| case. This can be useful when the same test executable is being used in | |
| multiple calls to ``gtest_discover_tests()`` but with different | |
| ``EXTRA_ARGS``. | |
| ``TEST_SUFFIX suffix`` | |
| Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of | |
| every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may | |
| be specified. | |
| ``TEST_FILTER expr`` | |
| .. versionadded:: 3.22 | |
| Filter expression to pass as a ``--gtest_filter`` argument during test | |
| discovery. Note that the expression is a wildcard-based format that | |
| matches against the original test names as used by gtest. For type or | |
| value-parameterized tests, these names may be different to the potentially | |
| pretty-printed test names that :program:`ctest` uses. | |
| ``NO_PRETTY_TYPES`` | |
| By default, the type index of type-parameterized tests is replaced by the | |
| actual type name in the CTest test name. If this behavior is undesirable | |
| (e.g. because the type names are unwieldy), this option will suppress this | |
| behavior. | |
| ``NO_PRETTY_VALUES`` | |
| By default, the value index of value-parameterized tests is replaced by the | |
| actual value in the CTest test name. If this behavior is undesirable | |
| (e.g. because the value strings are unwieldy), this option will suppress | |
| this behavior. | |
| ``PROPERTIES name1 value1...`` | |
| Specifies additional properties to be set on all tests discovered by this | |
| invocation of ``gtest_discover_tests()``. | |
| ``TEST_LIST var`` | |
| Make the list of tests available in the variable ``var``, rather than the | |
| default ``<target>_TESTS``. This can be useful when the same test | |
| executable is being used in multiple calls to ``gtest_discover_tests()``. | |
| Note that this variable is only available in CTest. | |
| Due to a limitation of CMake's parsing rules, any test with a square | |
| bracket in its name will be omitted from the list of tests stored in | |
| this variable. Such tests will still be defined and executed by | |
| ``ctest`` as normal though. | |
| ``DISCOVERY_TIMEOUT num`` | |
| .. versionadded:: 3.10.3 | |
| Specifies how long (in seconds) CMake will wait for the test to enumerate | |
| available tests. If the test takes longer than this, discovery (and your | |
| build) will fail. Most test executables will enumerate their tests very | |
| quickly, but under some exceptional circumstances, a test may require a | |
| longer timeout. The default is 5. See also the ``TIMEOUT`` option of | |
| :command:`execute_process`. | |
| .. note:: | |
| In CMake versions 3.10.1 and 3.10.2, this option was called ``TIMEOUT``. | |
| This clashed with the ``TIMEOUT`` test property, which is one of the | |
| common properties that would be set with the ``PROPERTIES`` keyword, | |
| usually leading to legal but unintended behavior. The keyword was | |
| changed to ``DISCOVERY_TIMEOUT`` in CMake 3.10.3 to address this | |
| problem. The ambiguous behavior of the ``TIMEOUT`` keyword in 3.10.1 | |
| and 3.10.2 has not been preserved. | |
| ``XML_OUTPUT_DIR dir`` | |
| .. versionadded:: 3.18 | |
| If specified, the parameter is passed along with ``--gtest_output=xml:`` | |
| to test executable. The actual file name is the same as the test target, | |
| including prefix and suffix. This should be used instead of | |
| ``EXTRA_ARGS --gtest_output=xml`` to avoid race conditions writing the | |
| XML result output when using parallel test execution. | |
| ``DISCOVERY_MODE`` | |
| .. versionadded:: 3.18 | |
| Provides greater control over when ``gtest_discover_tests()`` performs test | |
| discovery. By default, ``POST_BUILD`` sets up a post-build command | |
| to perform test discovery at build time. In certain scenarios, like | |
| cross-compiling, this ``POST_BUILD`` behavior is not desirable. | |
| By contrast, ``PRE_TEST`` delays test discovery until just prior to test | |
| execution. This way test discovery occurs in the target environment | |
| where the test has a better chance at finding appropriate runtime | |
| dependencies. | |
| ``DISCOVERY_MODE`` defaults to the value of the | |
| ``CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not | |
| passed when calling ``gtest_discover_tests()``. This provides a mechanism | |
| for globally selecting a preferred test discovery behavior without having | |
| to modify each call site. | |
| ``DISCOVERY_EXTRA_ARGS args...`` | |
| .. versionadded:: 3.31 | |
| Any extra arguments to pass on the command line for the discovery command. | |
| .. 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 | |
| block(SCOPE_FOR POLICIES) | |
| cmake_policy(VERSION 3.30) | |
| #------------------------------------------------------------------------------ | |
| function(gtest_add_tests) | |
| if (ARGC LESS 1) | |
| message(FATAL_ERROR "No arguments supplied to gtest_add_tests()") | |
| endif() | |
| set(options | |
| SKIP_DEPENDENCY | |
| ) | |
| set(oneValueArgs | |
| TARGET | |
| WORKING_DIRECTORY | |
| TEST_PREFIX | |
| TEST_SUFFIX | |
| TEST_LIST | |
| ) | |
| set(multiValueArgs | |
| SOURCES | |
| EXTRA_ARGS | |
| ) | |
| 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) | |
| 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 | |
| if (ARGC LESS 3) | |
| message(FATAL_ERROR "gtest_add_tests() without keyword options requires at least 3 arguments") | |
| endif() | |
| set(arg_TARGET "${ARGV0}") | |
| set(arg_EXTRA_ARGS "${ARGV1}") | |
| if(NOT "${ARGV2}" STREQUAL "AUTO") | |
| set(arg_SOURCES "${ARGV}") | |
| list(REMOVE_AT arg_SOURCES 0 1) | |
| endif() | |
| endif() | |
| # The non-keyword syntax allows the first argument to be an arbitrary | |
| # executable rather than a target if source files are also provided. In all | |
| # other cases, both forms require a target. | |
| if(NOT TARGET "${arg_TARGET}" AND NOT arg_SOURCES) | |
| message(FATAL_ERROR "${arg_TARGET} does not define an existing CMake target") | |
| endif() | |
| if(NOT arg_WORKING_DIRECTORY) | |
| unset(maybe_WORKING_DIRECTORY) | |
| else() | |
| set(maybe_WORKING_DIRECTORY "WORKING_DIRECTORY \${arg_WORKING_DIRECTORY}") | |
| endif() | |
| if(NOT arg_SOURCES) | |
| get_property(arg_SOURCES TARGET ${arg_TARGET} PROPERTY SOURCES) | |
| endif() | |
| unset(testList) | |
| set(gtest_case_name_regex ".*\\([ \r\n\t]*([A-Za-z_0-9]+)[ \r\n\t]*,[ \r\n\t]*([A-Za-z_0-9]+)[ \r\n\t]*\\).*") | |
| set(gtest_test_type_regex "(TYPED_TEST|TEST)_?[FP]?") | |
| set(each_line_regex "([^\r\n]*[\r\n])") | |
| foreach(source IN LISTS arg_SOURCES) | |
| if(NOT arg_SKIP_DEPENDENCY) | |
| set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${source}) | |
| endif() | |
| file(READ "${source}" contents) | |
| # Replace characters in file content that are special to CMake | |
| string(REPLACE "[" "<OPEN_BRACKET>" contents "${contents}") | |
| string(REPLACE "]" "<CLOSE_BRACKET>" contents "${contents}") | |
| string(REPLACE ";" "\\;" contents "${contents}") | |
| # Split into lines | |
| string(REGEX MATCHALL "${each_line_regex}" content_lines "${contents}") | |
| set(line "0") | |
| # Stores the line number of the start of a test definition | |
| set(accumulate_line "0") | |
| # Stores accumulated lines to match multi-line test definitions | |
| set(accumulated "") | |
| # Iterate over each line in the file so that we know the line number of a test definition | |
| foreach(line_str IN LISTS content_lines) | |
| math(EXPR line "${line}+1") | |
| # Check if the current line is the start of a test definition | |
| string(REGEX MATCH "[ \t]*${gtest_test_type_regex}[ \t]*[\\(]*" accumulate_start_hit "${line_str}") | |
| if(accumulate_start_hit) | |
| set(accumulate_line "${line}") | |
| endif() | |
| # Append the current line to the accumulated string | |
| set(accumulated "${accumulated}${line_str}") | |
| # Attempt to match a complete test definition in the accumulated string | |
| string(REGEX MATCH "${gtest_test_type_regex}[ \r\n\t]*\\(([A-Za-z_0-9 ,\r\n\t]+)\\)" hit "${accumulated}") | |
| if(hit) | |
| # Reset accumulated for the next match | |
| set(accumulated "") | |
| else() | |
| # Continue accumulating lines | |
| continue() | |
| endif() | |
| # At this point, the start line of the test definition is known | |
| # Hence, we can set the test's DEF_SOURCE_LINE property with | |
| # ${source}:${accumulate_line} below. | |
| # VS Code CMake Tools extension looks for DEF_SOURCE_LINE | |
| # to locate the test definition for its "Go to test" feature. | |
| string(REGEX MATCH "${gtest_test_type_regex}" test_type ${hit}) | |
| # Parameterized tests have a different signature for the filter | |
| if("x${test_type}" STREQUAL "xTEST_P") | |
| string(REGEX REPLACE ${gtest_case_name_regex} "*/\\1.\\2/*" gtest_test_name ${hit}) | |
| elseif("x${test_type}" STREQUAL "xTYPED_TEST_P") | |
| string(REGEX REPLACE ${gtest_case_name_regex} "*/\\1/*.\\2" gtest_test_name ${hit}) | |
| elseif("x${test_type}" STREQUAL "xTEST_F" OR "x${test_type}" STREQUAL "xTEST") | |
| string(REGEX REPLACE ${gtest_case_name_regex} "\\1.\\2" gtest_test_name ${hit}) | |
| elseif("x${test_type}" STREQUAL "xTYPED_TEST") | |
| string(REGEX REPLACE ${gtest_case_name_regex} "\\1/*.\\2" gtest_test_name ${hit}) | |
| else() | |
| message(WARNING "Could not parse GTest ${hit} for adding to CTest.") | |
| 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 | |
| # Note that this check is to allow backwards compatibility so this | |
| # module can be copied locally in projects to use with older CMake | |
| # versions | |
| if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.8.20170401) | |
| string(REGEX REPLACE | |
| "(^|\\.)DISABLED_" "\\1" | |
| orig_test_name "${gtest_test_name}" | |
| ) | |
| set(ctest_test_name | |
| ${arg_TEST_PREFIX}${orig_test_name}${arg_TEST_SUFFIX} | |
| ) | |
| cmake_language(EVAL CODE " | |
| add_test(NAME \${ctest_test_name} | |
| ${maybe_WORKING_DIRECTORY} | |
| 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}") | |
| list(APPEND testList ${ctest_test_name}) | |
| endif() | |
| else() | |
| set(ctest_test_name ${arg_TEST_PREFIX}${gtest_test_name}${arg_TEST_SUFFIX}) | |
| cmake_language(EVAL CODE " | |
| add_test(NAME \${ctest_test_name} | |
| ${maybe_WORKING_DIRECTORY} | |
| 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( | |
| ${ctest_test_name} | |
| PROPERTIES | |
| SKIP_REGULAR_EXPRESSION "\\[ SKIPPED \\]" | |
| DEF_SOURCE_LINE "${source}:${accumulate_line}" | |
| ) | |
| list(APPEND testList ${ctest_test_name}) | |
| endif() | |
| endforeach() | |
| endforeach() | |
| if(arg_TEST_LIST) | |
| set(${arg_TEST_LIST} ${testList} PARENT_SCOPE) | |
| endif() | |
| endfunction() | |
| #------------------------------------------------------------------------------ | |
| function(gtest_discover_tests target) | |
| set(options | |
| NO_PRETTY_TYPES | |
| NO_PRETTY_VALUES | |
| ) | |
| set(oneValueArgs | |
| TEST_PREFIX | |
| TEST_SUFFIX | |
| WORKING_DIRECTORY | |
| TEST_LIST | |
| DISCOVERY_TIMEOUT | |
| XML_OUTPUT_DIR | |
| DISCOVERY_MODE | |
| ) | |
| set(multiValueArgs | |
| EXTRA_ARGS | |
| DISCOVERY_EXTRA_ARGS | |
| PROPERTIES | |
| TEST_FILTER | |
| ) | |
| cmake_parse_arguments(PARSE_ARGV 1 arg | |
| "${options}" "${oneValueArgs}" "${multiValueArgs}" | |
| ) | |
| if(NOT arg_WORKING_DIRECTORY) | |
| set(arg_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") | |
| endif() | |
| if(NOT arg_TEST_LIST) | |
| set(arg_TEST_LIST ${target}_TESTS) | |
| endif() | |
| if(NOT arg_DISCOVERY_TIMEOUT) | |
| set(arg_DISCOVERY_TIMEOUT 5) | |
| endif() | |
| if(NOT arg_DISCOVERY_MODE) | |
| if(NOT CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE) | |
| set(CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE "POST_BUILD") | |
| endif() | |
| set(arg_DISCOVERY_MODE ${CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE}) | |
| endif() | |
| get_property( | |
| has_counter | |
| TARGET ${target} | |
| PROPERTY CTEST_DISCOVERED_TEST_COUNTER | |
| SET | |
| ) | |
| if(has_counter) | |
| get_property( | |
| counter | |
| TARGET ${target} | |
| PROPERTY CTEST_DISCOVERED_TEST_COUNTER | |
| ) | |
| math(EXPR counter "${counter} + 1") | |
| else() | |
| set(counter 1) | |
| endif() | |
| set_property( | |
| TARGET ${target} | |
| PROPERTY CTEST_DISCOVERED_TEST_COUNTER | |
| ${counter} | |
| ) | |
| # Define rule to generate test list for aforementioned test executable | |
| set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${target}[${counter}]") | |
| set(ctest_include_file "${ctest_file_base}_include.cmake") | |
| set(ctest_tests_file "${ctest_file_base}_tests.cmake") | |
| get_property(test_launcher | |
| TARGET ${target} | |
| PROPERTY TEST_LAUNCHER | |
| ) | |
| cmake_policy(GET CMP0158 _CMP0158 | |
| PARENT_SCOPE # undocumented, do not use outside of CMake | |
| ) | |
| if(NOT _CMP0158 OR _CMP0158 STREQUAL "OLD" OR _CMP0158 STREQUAL "NEW" AND CMAKE_CROSSCOMPILING) | |
| get_property(crosscompiling_emulator | |
| TARGET ${target} | |
| PROPERTY CROSSCOMPILING_EMULATOR | |
| ) | |
| endif() | |
| if(test_launcher AND crosscompiling_emulator) | |
| set(test_executor "${test_launcher}" "${crosscompiling_emulator}") | |
| elseif(test_launcher) | |
| set(test_executor "${test_launcher}") | |
| elseif(crosscompiling_emulator) | |
| set(test_executor "${crosscompiling_emulator}") | |
| else() | |
| 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 | |
| BYPRODUCTS "${ctest_tests_file}" | |
| COMMAND "${CMAKE_COMMAND}" | |
| -D "TEST_TARGET=${target}" | |
| -D "TEST_EXECUTABLE=$<TARGET_FILE:${target}>" | |
| -D "TEST_EXECUTOR=${test_executor}" | |
| -D "TEST_WORKING_DIR=${arg_WORKING_DIRECTORY}" | |
| -D "TEST_EXTRA_ARGS=${arg_EXTRA_ARGS}" | |
| -D "TEST_PROPERTIES=${arg_PROPERTIES}" | |
| -D "TEST_PREFIX=${arg_TEST_PREFIX}" | |
| -D "TEST_SUFFIX=${arg_TEST_SUFFIX}" | |
| -D "TEST_FILTER=${arg_TEST_FILTER}" | |
| -D "NO_PRETTY_TYPES=${arg_NO_PRETTY_TYPES}" | |
| -D "NO_PRETTY_VALUES=${arg_NO_PRETTY_VALUES}" | |
| -D "TEST_LIST=${arg_TEST_LIST}" | |
| -D "CTEST_FILE=${ctest_tests_file}" | |
| -D "TEST_DISCOVERY_TIMEOUT=${arg_DISCOVERY_TIMEOUT}" | |
| -D "TEST_DISCOVERY_EXTRA_ARGS=${arg_DISCOVERY_EXTRA_ARGS}" | |
| -D "TEST_XML_OUTPUT_DIR=${arg_XML_OUTPUT_DIR}" | |
| -P "${CMAKE_ROOT}/Modules/GoogleTestAddTests.cmake" | |
| VERBATIM | |
| ) | |
| file(WRITE "${ctest_include_file}" | |
| "if(EXISTS \"${ctest_tests_file}\")\n" | |
| " include(\"${ctest_tests_file}\")\n" | |
| "else()\n" | |
| " add_test(${target}_NOT_BUILT ${target}_NOT_BUILT)\n" | |
| "endif()\n" | |
| ) | |
| elseif(arg_DISCOVERY_MODE STREQUAL "PRE_TEST") | |
| get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL | |
| PROPERTY GENERATOR_IS_MULTI_CONFIG | |
| ) | |
| if(GENERATOR_IS_MULTI_CONFIG) | |
| set(ctest_tests_file "${ctest_file_base}_tests-$<CONFIG>.cmake") | |
| endif() | |
| string(CONCAT ctest_include_content | |
| "if(EXISTS \"$<TARGET_FILE:${target}>\")" "\n" | |
| " if(NOT EXISTS \"${ctest_tests_file}\" OR" "\n" | |
| " NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${target}>\" OR\n" | |
| " NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"\${CMAKE_CURRENT_LIST_FILE}\")\n" | |
| " include(\"${CMAKE_ROOT}/Modules/GoogleTestAddTests.cmake\")" "\n" | |
| " gtest_discover_tests_impl(" "\n" | |
| " TEST_EXECUTABLE" " [==[$<TARGET_FILE:${target}>]==]" "\n" | |
| " TEST_EXECUTOR" " [==[${test_executor}]==]" "\n" | |
| " TEST_WORKING_DIR" " [==[${arg_WORKING_DIRECTORY}]==]" "\n" | |
| " TEST_EXTRA_ARGS" " [==[${arg_EXTRA_ARGS}]==]" "\n" | |
| " TEST_PROPERTIES" " [==[${arg_PROPERTIES}]==]" "\n" | |
| " TEST_PREFIX" " [==[${arg_TEST_PREFIX}]==]" "\n" | |
| " TEST_SUFFIX" " [==[${arg_TEST_SUFFIX}]==]" "\n" | |
| " TEST_FILTER" " [==[${arg_TEST_FILTER}]==]" "\n" | |
| " NO_PRETTY_TYPES" " [==[${arg_NO_PRETTY_TYPES}]==]" "\n" | |
| " NO_PRETTY_VALUES" " [==[${arg_NO_PRETTY_VALUES}]==]" "\n" | |
| " TEST_LIST" " [==[${arg_TEST_LIST}]==]" "\n" | |
| " CTEST_FILE" " [==[${ctest_tests_file}]==]" "\n" | |
| " TEST_DISCOVERY_TIMEOUT" " [==[${arg_DISCOVERY_TIMEOUT}]==]" "\n" | |
| " TEST_DISCOVERY_EXTRA_ARGS [==[${arg_DISCOVERY_EXTRA_ARGS}]==]" "\n" | |
| " TEST_XML_OUTPUT_DIR" " [==[${arg_XML_OUTPUT_DIR}]==]" "\n" | |
| " )" "\n" | |
| " endif()" "\n" | |
| " include(\"${ctest_tests_file}\")" "\n" | |
| "else()" "\n" | |
| " add_test(${target}_NOT_BUILT ${target}_NOT_BUILT)" "\n" | |
| "endif()" "\n" | |
| ) | |
| if(GENERATOR_IS_MULTI_CONFIG) | |
| foreach(_config ${CMAKE_CONFIGURATION_TYPES}) | |
| file(GENERATE | |
| OUTPUT "${ctest_file_base}_include-${_config}.cmake" | |
| CONTENT "${ctest_include_content}" | |
| CONDITION $<CONFIG:${_config}> | |
| ) | |
| endforeach() | |
| file(WRITE "${ctest_include_file}" | |
| "include(\"${ctest_file_base}_include-\${CTEST_CONFIGURATION_TYPE}.cmake\")" | |
| ) | |
| else() | |
| file(GENERATE | |
| OUTPUT "${ctest_file_base}_include.cmake" | |
| CONTENT "${ctest_include_content}" | |
| ) | |
| file(WRITE "${ctest_include_file}" | |
| "include(\"${ctest_file_base}_include.cmake\")" | |
| ) | |
| endif() | |
| else() | |
| message(FATAL_ERROR "Unknown DISCOVERY_MODE: ${arg_DISCOVERY_MODE}") | |
| endif() | |
| # Add discovered tests to directory TEST_INCLUDE_FILES | |
| set_property(DIRECTORY | |
| APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}" | |
| ) | |
| endfunction() | |
| ############################################################################### | |
| # Restore project's policies | |
| endblock() |