GoogleTest: Add DISCOVERY_USE_TEST_ENV

This commit is contained in:
Máté Ferenc Nagy-Egri 2026-01-04 18:13:50 +01:00
parent a469fea3a3
commit aca0b57db4
3 changed files with 107 additions and 1 deletions

View File

@ -181,6 +181,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
[XML_OUTPUT_DIR dir]
[DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
[DISCOVERY_EXTRA_ARGS args...]
[DISCOVERY_USE_TEST_ENV]
)
.. versionadded:: 3.10
@ -337,6 +338,59 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
pass lists as property values. Do note that doing so the chosen character
cannot appear in any of the property values.
``DISCOVERY_USE_TEST_ENV``
.. versionadded:: 4.3
By default, only test execution uses the environment described by the
:prop_test:`ENVIRONMENT` and :prop_test`ENVIRONMENT_MODIFICATION` test
properties. This option tells the module to also apply these properties to
the discovery step, regardless of ``DISCOVERY_MODE``.
Examples
========
``DISCOVERY_USE_TEST_ENV`` allows describing test environments where even
discovery depends on environment modifications. Combining it with
``LIST_SEPARATOR`` enables even more complex scenarios requiring multiple
environment modfiications. This can be crucial on Windows platforms, where
RPATH isn't available to tell the linker about DLL dependency locations in
the build tree. Without modifying the environment, one has to resort to
other methods, typically copying DLLs next to test executables with
``add_custom_command()``s. As mentioned in ``DISCOVERY_MODE``, setting the
discovery mode to ``PRE_TEST`` helps in some cases, but is of limited use.
Setting the environment as flexibly, robustly in a multi-config generator
friendly way from a CMake preset JSON or an external script is challanging.
.. code-block:: cmake
# Test executable depending on two SHARED libraries
# even during discovery.
add_executable(my_test my_test.cpp)
target_link_libraries(my_test PRIVATE
shared_lib1
shared_lib2
GTest::gtest
GTest::gtest_main
)
set(LABELS label1 label2)
set(ENVIRONMENT_MODIFICATION
PATH=path_list_prepend:$<TARGET_FILE_DIR:shared_lib1>
PATH=path_list_prepend:$<TARGET_FILE_DIR:shared_lib2>
)
set(LIST_SEPARATOR ",")
list(JOIN LABELS ${LIST_SEPARATOR} LABELS)
list(JOIN ENVIRONMENT_MODIFICATION ${LIST_SEPARATOR} ENVIRONMENT_MODIFICATION)
gtest_discover_tests(my_test
LIST_SEPARATOR ${LIST_SEPARATOR}
PROPERTIES
LABELS "${LABELS}"
ENVIRONMENT_MODIFICATION "${ENVIRONMENT_MODIFICATION}"
DISCOVERY_USE_TEST_ENV ON
)
#]=======================================================================]
# Save project's policies
@ -562,6 +616,7 @@ function(gtest_discover_tests target)
set(options
NO_PRETTY_TYPES
NO_PRETTY_VALUES
DISCOVERY_USE_TEST_ENV
)
set(oneValueArgs
TEST_PREFIX
@ -694,10 +749,34 @@ function(gtest_discover_tests target)
endif()
if(arg_DISCOVERY_MODE STREQUAL "POST_BUILD")
if(arg_DISCOVERY_USE_TEST_ENV)
foreach(PROP ENVIRONMENT ENVIRONMENT_MODIFICATION)
list(FIND arg_PROPERTIES ${PROP} ${PROP}_INDEX)
if(NOT ${PROP}_INDEX EQUAL -1)
math(EXPR VALUE_INDEX "${${PROP}_INDEX} + 1")
list(GET arg_PROPERTIES ${VALUE_INDEX} ${PROP}_VALUE)
string(REPLACE "${arg_LIST_SEPARATOR}" ";" ${PROP}_VALUE "${${PROP}_VALUE}")
endif()
endforeach()
# if discovery should use test env, then one of the relevant test props
# must have been set, otherwise TEST_ENV_FRAGMENT will be ill-formed.
if(NOT ENVIRONMENT_INDEX EQUAL -1 OR NOT ENVIRONMENT_MODIFICATION_INDEX EQUAL -1)
foreach(ENV_MOD_VALUE IN LISTS ENVIRONMENT_MODIFICATION_VALUE)
list(APPEND ENVIRONMENT_MODIFICATION_FRAGMENT "--modify" "${ENV_MOD_VALUE}")
endforeach()
set(TEST_ENV_FRAGMENT
-E env
${ENVIRONMENT_VALUE}
${ENVIRONMENT_MODIFICATION_FRAGMENT}
--
"${CMAKE_COMMAND}"
)
endif()
endif()
add_custom_command(
TARGET ${target} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
COMMAND "${CMAKE_COMMAND}" ${TEST_ENV_FRAGMENT}
-D "TEST_TARGET=${target}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${target}>"
-D "TEST_EXECUTOR=${test_executor}"
@ -709,6 +788,7 @@ function(gtest_discover_tests target)
-D "TEST_FILTER=${arg_TEST_FILTER}"
-D "NO_PRETTY_TYPES=${arg_NO_PRETTY_TYPES}"
-D "NO_PRETTY_VALUES=${arg_NO_PRETTY_VALUES}"
-D "DISCOVERY_USE_TEST_ENV=${arg_DISCOVERY_USE_TEST_ENV}"
-D "LIST_SEPARATOR=${arg_LIST_SEPARATOR}"
-D "TEST_LIST=${arg_TEST_LIST}"
-D "CTEST_FILE=${ctest_tests_file}"

View File

@ -126,3 +126,16 @@ gtest_discover_tests(test_gtest5
PROPERTIES
ENVIRONMENT "${ENVIRONMENT}"
)
# Check if DISCOVERY_USE_TEST_ENV really inherits relevant properties
add_executable(test_gtest5env main5.cxx)
target_link_libraries(test_gtest5env GTest::GTest)
target_compile_definitions(test_gtest5env PRIVATE DISCOVERY_USE_TEST_ENV)
set(ENVIRONMENT VALX=1)
set(ENVIRONMENT_MODIFICATION VALY=set:2)
gtest_discover_tests(test_gtest5env
PROPERTIES
ENVIRONMENT "${ENVIRONMENT}"
ENVIRONMENT_MODIFICATION "${ENVIRONMENT_MODIFICATION}"
DISCOVERY_USE_TEST_ENV ON
)

View File

@ -7,3 +7,16 @@ TEST(GoogleTest, Add)
EXPECT_EQ(std::atoi(std::getenv("VALX")) + std::atoi(std::getenv("VALY")),
3);
}
#ifdef DISCOVERY_USE_TEST_ENV
int main(int argc, char* argv[])
{
if (std::getenv("VALX") == nullptr || std::getenv("VALY") == nullptr) {
std::cerr << "VALX or VALY not present in main." << std::endl;
return -1;
}
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#endif