Merge topic 'gtest-test-target' into release-4.4

4f0dea4ea5 Merge branch 'backport-4.2-gtest-test-target' into gtest-test-target
fc1b218b37 GoogleTest: Fix gtest_discover_tests race on POST_BUILD of multiple targets
e79506fadf GoogleTest: Fix gtest_discover_tests race on POST_BUILD of multiple targets

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !12276
diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake
index 68f2520..61c2bc2 100644
--- a/Modules/GoogleTest.cmake
+++ b/Modules/GoogleTest.cmake
@@ -685,6 +685,7 @@
     string(CONCAT discovery_content
       "include(\"${CMAKE_ROOT}/Modules/GoogleTestAddTests.cmake\")"         "\n"
       "gtest_discover_tests_impl("                                          "\n"
+      "  TEST_TARGET"            " [==[${target}]==]"                       "\n"
       "  TEST_EXECUTABLE"        " [==[$<TARGET_FILE:${target}>]==]"        "\n"
       "  TEST_EXECUTOR"          " [==[${test_executor}]==]"                "\n"
       "  TEST_WORKING_DIR"       " [==[${arg_WORKING_DIRECTORY}]==]"        "\n"
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-discovery-post-build-race-check.cmake b/Tests/RunCMake/GoogleTest/GoogleTest-discovery-post-build-race-check.cmake
new file mode 100644
index 0000000..47ac65b
--- /dev/null
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-discovery-post-build-race-check.cmake
@@ -0,0 +1,18 @@
+if(NOT DEFINED binary_dir)
+  message(FATAL_ERROR "binary_dir is required")
+endif()
+if(NOT DEFINED target_count)
+  message(FATAL_ERROR "target_count is required")
+endif()
+
+file(GLOB discovery_json_files "${binary_dir}/cmake_test_discovery_*.json")
+list(LENGTH discovery_json_files discovery_json_count)
+
+if(NOT discovery_json_count EQUAL target_count)
+  message(FATAL_ERROR
+    "Expected ${target_count} unique discovery JSON files, found ${discovery_json_count}. "
+    "Likely shared discovery scratch file collision in POST_BUILD discovery."
+  )
+endif()
+
+message(STATUS "Found ${discovery_json_count}/${target_count} unique discovery JSON files")
diff --git a/Tests/RunCMake/GoogleTest/GoogleTestDiscoveryPostBuildRace.cmake b/Tests/RunCMake/GoogleTest/GoogleTestDiscoveryPostBuildRace.cmake
new file mode 100644
index 0000000..bc5696f
--- /dev/null
+++ b/Tests/RunCMake/GoogleTest/GoogleTestDiscoveryPostBuildRace.cmake
@@ -0,0 +1,27 @@
+enable_language(CXX)
+include(GoogleTest)
+
+enable_testing()
+
+include(xcode_sign_adhoc.cmake)
+
+set(race_target_count 16)
+set(race_targets)
+
+foreach(i RANGE 1 ${race_target_count})
+  set(t race_fake_gtest_${i})
+  add_executable(${t} fake_gtest.cpp)
+  xcode_sign_adhoc(${t})
+  # Avoid timeouts on low-resource hardware at high parallelism.
+  gtest_discover_tests(${t} DISCOVERY_MODE POST_BUILD DISCOVERY_TIMEOUT 30)
+  list(APPEND race_targets ${t})
+endforeach()
+
+add_custom_target(check_discovery_json_files
+  COMMAND ${CMAKE_COMMAND}
+    -Dbinary_dir=${CMAKE_CURRENT_BINARY_DIR}
+    -Dtarget_count=${race_target_count}
+    -P ${CMAKE_CURRENT_LIST_DIR}/GoogleTest-discovery-post-build-race-check.cmake
+  DEPENDS ${race_targets}
+  VERBATIM
+)
diff --git a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
index a910e1f..8ebcfb8 100644
--- a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
@@ -357,6 +357,27 @@
   )
 endfunction()
 
+function(run_GoogleTest_discovery_post_build_race)
+  # Use a single build tree for this test without cleaning.
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTest-discovery-post-build-race)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+  endif()
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  run_cmake(GoogleTestDiscoveryPostBuildRace)
+
+  run_cmake_command(GoogleTest-discovery-post-build-race-build
+    ${CMAKE_COMMAND}
+    --build .
+    --config Debug
+    -j 16
+    --target check_discovery_json_files
+  )
+endfunction()
+
 function(run_GoogleTest_discovery_test_list_scoped DISCOVERY_MODE)
   # Use a single build tree for a few tests without cleaning.
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTest-discovery-test-list-scoped-build)
@@ -516,3 +537,8 @@
 
 run_GoogleTest_LegacyParser()
 run_GoogleTest_DEF_SOURCE_LINE()
+
+# This test is meaningful only for generators which support parallel builds.
+if (NOT RunCMake_GENERATOR MATCHES "(Borland|NMake|Watcom)")
+  run_GoogleTest_discovery_post_build_race()
+endif()