GoogleTest: Honor TEST_LAUNCHER in gtest_discover_tests

We run test executables to discover tests.  Use the same launchers that
are used to run the tests.  We already handle `CROSSCOMPILING_EMULATOR`.
Update the logic to account for the `TEST_LAUNCHER` property added by
commit 1ec0372ed4 (add_test: Optionally use a launcher for tests running
in-project targets, 2023-11-11), and for the `CROSSCOMPILING_EMULATOR`
behavior change in commit ca5a300d7f (add_test: Honor
CROSSCOMPILING_EMULATOR only when cross-compiling, 2023-11-02).

Fixes: #25603
Co-authored-by: Brad King <brad.king@kitware.com>
Signed-off-by: Ralf Habacker <ralf.habacker@freenet.de>
This commit is contained in:
Ralf Habacker 2024-01-17 22:51:30 +01:00 committed by Brad King
parent 622a498477
commit f875c479f5
7 changed files with 207 additions and 5 deletions

View File

@ -475,10 +475,29 @@ function(gtest_discover_tests TARGET)
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(crosscompiling_emulator
get_property(test_launcher
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
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()
if(_DISCOVERY_MODE STREQUAL "POST_BUILD")
add_custom_command(
@ -487,7 +506,7 @@ function(gtest_discover_tests TARGET)
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_EXECUTOR=${test_executor}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
@ -529,7 +548,7 @@ function(gtest_discover_tests TARGET)
" include(\"${CMAKE_ROOT}/Modules/GoogleTestAddTests.cmake\")" "\n"
" gtest_discover_tests_impl(" "\n"
" TEST_EXECUTABLE" " [==[" "$<TARGET_FILE:${TARGET}>" "]==]" "\n"
" TEST_EXECUTOR" " [==[" "${crosscompiling_emulator}" "]==]" "\n"
" TEST_EXECUTOR" " [==[" "${test_executor}" "]==]" "\n"
" TEST_WORKING_DIR" " [==[" "${_WORKING_DIRECTORY}" "]==]" "\n"
" TEST_EXTRA_ARGS" " [==[" "${_EXTRA_ARGS}" "]==]" "\n"
" TEST_PROPERTIES" " [==[" "${_PROPERTIES}" "]==]" "\n"

View File

@ -425,7 +425,11 @@ endif()
add_RunCMake_test(GeneratorToolset)
add_RunCMake_test(GetPrerequisites -DSAMPLE_EXE=$<TARGET_FILE:exit_code>)
add_RunCMake_test(GNUInstallDirs -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME})
add_RunCMake_test(GoogleTest) # Note: does not actually depend on Google Test
add_RunCMake_test(GoogleTest # Note: does not actually depend on Google Test
-DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
-DCMAKE_VS_PLATFORM_NAME=${CMAKE_VS_PLATFORM_NAME}
)
add_RunCMake_test(Graphviz)
add_RunCMake_test(Languages)
add_RunCMake_test(LinkItemValidation)

View File

@ -0,0 +1,17 @@
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

View File

@ -0,0 +1,29 @@
enable_language(C)
include(GoogleTest)
enable_testing()
include(xcode_sign_adhoc.cmake)
add_executable(test_launcher test_launcher.c)
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
"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
"emulatorparam"
"--"
)
set_property(TARGET launcher_test PROPERTY CROSSCOMPILING_EMULATOR "${emulator}")
gtest_discover_tests(
launcher_test
)

View File

@ -101,6 +101,43 @@ function(run_GoogleTest DISCOVERY_MODE)
)
endfunction()
function(run_GoogleTestLauncher DISCOVERY_MODE)
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "14.0")
return()
endif()
if(CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64" AND CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "19.36")
return()
endif()
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTestLauncher-build)
if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
endif()
run_cmake_with_options(GoogleTestLauncher
-DCMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE=${DISCOVERY_MODE}
)
set(RunCMake_TEST_NO_CLEAN 1)
# 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
${CMAKE_COMMAND}
--build .
--config Debug
)
unset(RunCMake_TEST_OUTPUT_MERGE)
run_cmake_command(GoogleTestLauncher-test
${CMAKE_CTEST_COMMAND}
-C Debug
-V
--no-label-sumary
)
endfunction()
function(run_GoogleTestXML DISCOVERY_MODE)
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTestXML-build)
@ -321,6 +358,7 @@ endfunction()
foreach(DISCOVERY_MODE POST_BUILD PRE_TEST)
message("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_GoogleTest_discovery_timeout(${DISCOVERY_MODE})

View File

@ -0,0 +1,24 @@
#include <stdio.h>
#include <string.h>
/* Having this as comment lets gtest_add_tests recognizes the test we fake
here without requiring googletest
TEST_F( launcher_test, test1 )
{
}
*/
int main(int argc, char** argv)
{
/* Note: GoogleTest.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. */
if (argc > 1 && strcmp(argv[1], "--gtest_list_tests") == 0) {
printf("launcher_test.\n");
printf(" test1\n");
}
printf("launcher_test.test1\n");
return 0;
}

View File

@ -0,0 +1,71 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_MSC_VER) && _MSC_VER < 1900
# include <stdarg.h>
static int snprintf(char* buffer, size_t count, const char* format, ...)
{
int n;
va_list argptr;
va_start(argptr, format);
n = _vscprintf(format, argptr);
vsnprintf_s(buffer, count, _TRUNCATE, format, argptr);
va_end(argptr);
return n;
}
#endif
static int launch(int argc, const char* argv[])
{
char cmd[4096];
size_t len = 0;
const char* sep = "";
int i;
int n;
#ifdef _WIN32
n = snprintf(cmd + len, sizeof(cmd) - len, "cmd /C \"");
if (n < 0) {
return 1;
}
len += n;
#endif
for (i = 0; i < argc; ++i) {
n = snprintf(cmd + len, sizeof(cmd) - len, "%s\"%s\"", sep, argv[i]);
if (n < 0) {
return 1;
}
len += n;
if (len >= sizeof(cmd)) {
fprintf(stderr, "error: command too long\n");
return 1;
}
sep = " ";
}
#ifdef _WIN32
printf("launching: %s\n", cmd + 8);
n = snprintf(cmd + len, sizeof(cmd) - len, "\"");
if (n < 1) {
return 1;
}
#else
printf("launching: %s\n", cmd);
#endif
fflush(stdout);
return system(cmd);
}
int main(int argc, const char* argv[])
{
int ownArgs = 1;
int i;
for (i = 0; i < argc; ++i) {
printf("test_launcher: got arg %d '%s'\n", i, argv[i]);
if (ownArgs && strcmp(argv[i], "--") == 0) {
ownArgs = 0;
} else if (!ownArgs) {
return launch(argc - i, argv + i);
}
}
return 1;
}