Merge pull request #4466 from danfabo:fix-fetch-content-uses-gtest

PiperOrigin-RevId: 612560830
Change-Id: Ib639603d34258909cf0e0d6fceb297dd8c983d54
diff --git a/BUILD.bazel b/BUILD.bazel
index b1e3b7f..e407ae2 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -56,6 +56,12 @@
     constraint_values = ["@platforms//os:openbsd"],
 )
 
+# NOTE: Fuchsia is not an officially supported platform.
+config_setting(
+    name = "fuchsia",
+    constraint_values = ["@platforms//os:fuchsia"],
+)
+
 config_setting(
     name = "msvc_compiler",
     flag_values = {
@@ -147,6 +153,17 @@
             "@com_googlesource_code_re2//:re2",
         ],
         "//conditions:default": [],
+    }) + select({
+        # `gtest-death-test.cc` has `EXPECT_DEATH` that spawns a process,
+        # expects it to crash and inspects its logs with the given matcher,
+        # so that's why these libraries are needed.
+        # Otherwise, builds targeting Fuchsia would fail to compile.
+        ":fuchsia": [
+            "@fuchsia_sdk//pkg/fdio",
+            "@fuchsia_sdk//pkg/syslog",
+            "@fuchsia_sdk//pkg/zx",
+        ],
+        "//conditions:default": [],
     }),
 )
 
diff --git a/MODULE.bazel b/MODULE.bazel
index d4ad2b3..b81ebf0 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -53,5 +53,9 @@
 bazel_dep(name = "rules_python",
           version = "0.29.0")
 
+
+fake_fuchsia_sdk = use_repo_rule("//:fake_fuchsia_sdk.bzl", "fake_fuchsia_sdk")
+fake_fuchsia_sdk(name = "fuchsia_sdk")
+
 # https://github.com/bazelbuild/rules_python/blob/main/BZLMOD_SUPPORT.md#default-toolchain-is-not-the-local-system-python
 register_toolchains("@bazel_tools//tools/python:autodetecting_toolchain")
diff --git a/docs/gmock_for_dummies.md b/docs/gmock_for_dummies.md
index 9f24dca..ed2297c 100644
--- a/docs/gmock_for_dummies.md
+++ b/docs/gmock_for_dummies.md
@@ -261,6 +261,8 @@
 when you allocate mocks on the heap. You get that automatically if you use the
 `gtest_main` library already.
 
+###### Expectation Ordering
+
 **Important note:** gMock requires expectations to be set **before** the mock
 functions are called, otherwise the behavior is **undefined**. Do not alternate
 between calls to `EXPECT_CALL()` and calls to the mock functions, and do not set
diff --git a/docs/reference/mocking.md b/docs/reference/mocking.md
index 3ad4952..ab37ebf 100644
--- a/docs/reference/mocking.md
+++ b/docs/reference/mocking.md
@@ -81,8 +81,8 @@
     .Times(cardinality)            // Can be used at most once
     .InSequence(sequences...)      // Can be used any number of times
     .After(expectations...)        // Can be used any number of times
-    .WillRepeatedly(action)        // Can be used any number of times
-    .WillOnce(action)              // Can be used at most once
+    .WillOnce(action)              // Can be used any number of times
+    .WillRepeatedly(action)        // Can be used at most once
     .RetiresOnSaturation();        // Can be used at most once
 ```
 
diff --git a/fake_fuchsia_sdk.bzl b/fake_fuchsia_sdk.bzl
new file mode 100644
index 0000000..2024dc6
--- /dev/null
+++ b/fake_fuchsia_sdk.bzl
@@ -0,0 +1,33 @@
+"""Provides a fake @fuchsia_sdk implementation that's used when the real one isn't available.
+
+This is needed since bazel queries on targets that depend on //:gtest (eg:
+`bazel query "deps(set(//googletest/test:gtest_all_test))"`) will fail if @fuchsia_sdk is not
+defined when bazel is evaluating the transitive closure of the query target.
+
+See https://github.com/google/googletest/issues/4472.
+"""
+
+def _fake_fuchsia_sdk_impl(repo_ctx):
+    for stub_target in repo_ctx.attr._stub_build_targets:
+        stub_package = stub_target
+        stub_target_name = stub_target.split("/")[-1]
+        repo_ctx.file("%s/BUILD.bazel" % stub_package, """
+filegroup(
+    name = "%s",
+)
+""" % stub_target_name)
+
+fake_fuchsia_sdk = repository_rule(
+    doc = "Used to create a fake @fuchsia_sdk repository with stub build targets.",
+    implementation = _fake_fuchsia_sdk_impl,
+    attrs = {
+        "_stub_build_targets": attr.string_list(
+            doc = "The stub build targets to initialize.",
+            default = [
+                "pkg/fdio",
+                "pkg/syslog",
+                "pkg/zx",
+            ],
+        ),
+    },
+)
diff --git a/googlemock/include/gmock/gmock-more-actions.h b/googlemock/include/gmock/gmock-more-actions.h
index dd90e31..e341d47 100644
--- a/googlemock/include/gmock/gmock-more-actions.h
+++ b/googlemock/include/gmock/gmock-more-actions.h
@@ -592,8 +592,9 @@
 // Overloads for other custom-callables are provided in the
 // internal/custom/gmock-generated-actions.h header.
 template <typename F, typename... Args>
-auto InvokeArgument(F f, Args... args) -> decltype(f(args...)) {
-  return f(args...);
+auto InvokeArgument(F &&f,
+                    Args... args) -> decltype(std::forward<F>(f)(args...)) {
+  return std::forward<F>(f)(args...);
 }
 
 template <std::size_t index, typename... Params>
diff --git a/googlemock/test/gmock-more-actions_test.cc b/googlemock/test/gmock-more-actions_test.cc
index 16af689..7ed89a9 100644
--- a/googlemock/test/gmock-more-actions_test.cc
+++ b/googlemock/test/gmock-more-actions_test.cc
@@ -91,6 +91,10 @@
   UnaryMoveOnlyFunctor(UnaryMoveOnlyFunctor&&) = default;
 };
 
+struct OneShotUnaryFunctor {
+  int operator()(bool x) && { return x ? 1 : -1; }
+};
+
 const char* Binary(const char* input, short n) { return input + n; }  // NOLINT
 
 int Ternary(int x, char y, short z) { return x + y + z; }  // NOLINT
@@ -716,6 +720,12 @@
   EXPECT_EQ(1, a.Perform(std::make_tuple(UnaryMoveOnlyFunctor())));
 }
 
+// Tests using InvokeArgument with a one-shot unary functor.
+TEST(InvokeArgumentTest, OneShotFunctor1) {
+  Action<int(OneShotUnaryFunctor)> a = InvokeArgument<0>(true);  // NOLINT
+  EXPECT_EQ(1, a.Perform(std::make_tuple(OneShotUnaryFunctor())));
+}
+
 // Tests using InvokeArgument with a 5-ary function.
 TEST(InvokeArgumentTest, Function5) {
   Action<int(int (*)(int, int, int, int, int))> a =  // NOLINT
diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h
index 15d0539..2b70e49 100644
--- a/googletest/include/gtest/gtest.h
+++ b/googletest/include/gtest/gtest.h
@@ -60,16 +60,16 @@
 #include <type_traits>
 #include <vector>
 
-#include "gtest/gtest-assertion-result.h"
-#include "gtest/gtest-death-test.h"
-#include "gtest/gtest-matchers.h"
-#include "gtest/gtest-message.h"
-#include "gtest/gtest-param-test.h"
-#include "gtest/gtest-printers.h"
-#include "gtest/gtest-test-part.h"
-#include "gtest/gtest-typed-test.h"
-#include "gtest/gtest_pred_impl.h"
-#include "gtest/gtest_prod.h"
+#include "gtest/gtest-assertion-result.h"  // IWYU pragma: export
+#include "gtest/gtest-death-test.h"  // IWYU pragma: export
+#include "gtest/gtest-matchers.h"  // IWYU pragma: export
+#include "gtest/gtest-message.h"  // IWYU pragma: export
+#include "gtest/gtest-param-test.h"  // IWYU pragma: export
+#include "gtest/gtest-printers.h"  // IWYU pragma: export
+#include "gtest/gtest-test-part.h"  // IWYU pragma: export
+#include "gtest/gtest-typed-test.h"  // IWYU pragma: export
+#include "gtest/gtest_pred_impl.h"  // IWYU pragma: export
+#include "gtest/gtest_prod.h"  // IWYU pragma: export
 #include "gtest/internal/gtest-internal.h"
 #include "gtest/internal/gtest-string.h"
 
@@ -1262,6 +1262,20 @@
   // total_test_suite_count() - 1. If i is not in that range, returns NULL.
   TestSuite* GetMutableTestSuite(int i);
 
+  // Invokes OsStackTrackGetterInterface::UponLeavingGTest. UponLeavingGTest()
+  // should be called immediately before Google Test calls user code. It saves
+  // some information about the current stack that CurrentStackTrace() will use
+  // to find and hide Google Test stack frames.
+  void UponLeavingGTest();
+
+  // Sets the TestSuite object for the test that's currently running.
+  void set_current_test_suite(TestSuite* a_current_test_suite)
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Sets the TestInfo object for the test that's currently running.
+  void set_current_test_info(TestInfo* a_current_test_info)
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
   // Accessors for the implementation object.
   internal::UnitTestImpl* impl() { return impl_; }
   const internal::UnitTestImpl* impl() const { return impl_; }
@@ -1270,6 +1284,8 @@
   // members of UnitTest.
   friend class ScopedTrace;
   friend class Test;
+  friend class TestInfo;
+  friend class TestSuite;
   friend class internal::AssertHelper;
   friend class internal::StreamingListenerTest;
   friend class internal::UnitTestRecordPropertyTestHelper;
diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc
index f914db5..15472f1 100644
--- a/googletest/src/gtest-death-test.cc
+++ b/googletest/src/gtest-death-test.cc
@@ -630,13 +630,13 @@
 #ifndef GTEST_OS_WINDOWS
 // Note: The return value points into args, so the return value's lifetime is
 // bound to that of args.
-static std::unique_ptr<char*[]> CreateArgvFromArgs(
-    std::vector<std::string>& args) {
-  auto result = std::make_unique<char*[]>(args.size() + 1);
-  for (size_t i = 0; i < args.size(); ++i) {
-    result[i] = &args[i][0];
+static std::vector<char*> CreateArgvFromArgs(std::vector<std::string>& args) {
+  std::vector<char*> result;
+  result.reserve(args.size() + 1);
+  for (auto& arg : args) {
+    result.push_back(&arg[0]);
   }
-  result[args.size()] = nullptr;  // extra null terminator
+  result.push_back(nullptr);  // Extra null terminator.
   return result;
 }
 #endif
@@ -1036,8 +1036,8 @@
   // "Fuchsia Test Component" which contains a "Fuchsia Component Manifest")
   // Launching processes is a privileged operation in Fuchsia, and the
   // declaration indicates that the ability is required for the component.
-  std::unique_ptr<char*[]> argv = CreateArgvFromArgs(args);
-  status = fdio_spawn_etc(child_job, FDIO_SPAWN_CLONE_ALL, argv[0], argv.get(),
+  std::vector<char*> argv = CreateArgvFromArgs(args);
+  status = fdio_spawn_etc(child_job, FDIO_SPAWN_CLONE_ALL, argv[0], argv.data(),
                           nullptr, 2, spawn_actions,
                           child_process_.reset_and_get_address(), nullptr);
   GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
@@ -1388,8 +1388,8 @@
   // is necessary.
   FlushInfoLog();
 
-  std::unique_ptr<char*[]> argv = CreateArgvFromArgs(args);
-  const pid_t child_pid = ExecDeathTestSpawnChild(argv.get(), pipe_fd[0]);
+  std::vector<char*> argv = CreateArgvFromArgs(args);
+  const pid_t child_pid = ExecDeathTestSpawnChild(argv.data(), pipe_fd[0]);
   GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
   set_child_pid(child_pid);
   set_read_fd(pipe_fd[0]);
diff --git a/googletest/src/gtest-internal-inl.h b/googletest/src/gtest-internal-inl.h
index 4799a1e..6dea34f 100644
--- a/googletest/src/gtest-internal-inl.h
+++ b/googletest/src/gtest-internal-inl.h
@@ -709,18 +709,6 @@
     return type_parameterized_test_registry_;
   }
 
-  // Sets the TestSuite object for the test that's currently running.
-  void set_current_test_suite(TestSuite* a_current_test_suite) {
-    current_test_suite_ = a_current_test_suite;
-  }
-
-  // Sets the TestInfo object for the test that's currently running.  If
-  // current_test_info is NULL, the assertion results will be stored in
-  // ad_hoc_test_result_.
-  void set_current_test_info(TestInfo* a_current_test_info) {
-    current_test_info_ = a_current_test_info;
-  }
-
   // Registers all parameterized tests defined using TEST_P and
   // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter
   // combination. This method can be called more then once; it has guards
@@ -841,6 +829,18 @@
   // GTEST_FLAG(catch_exceptions) at the moment it starts.
   void set_catch_exceptions(bool value) { catch_exceptions_ = value; }
 
+  // Sets the TestSuite object for the test that's currently running.
+  void set_current_test_suite(TestSuite* a_current_test_suite) {
+    current_test_suite_ = a_current_test_suite;
+  }
+
+  // Sets the TestInfo object for the test that's currently running.  If
+  // current_test_info is NULL, the assertion results will be stored in
+  // ad_hoc_test_result_.
+  void set_current_test_info(TestInfo* a_current_test_info) {
+    current_test_info_ = a_current_test_info;
+  }
+
   // The UnitTest object that owns this implementation object.
   UnitTest* const parent_;
 
diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc
index d25f5c4..c5f22bb 100644
--- a/googletest/src/gtest.cc
+++ b/googletest/src/gtest.cc
@@ -2836,14 +2836,13 @@
   }
 
   // Tells UnitTest where to store test result.
-  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
-  impl->set_current_test_info(this);
+  UnitTest::GetInstance()->set_current_test_info(this);
 
   // Notifies the unit test event listeners that a test is about to start.
   repeater->OnTestStart(*this);
   result_.set_start_timestamp(internal::GetTimeInMillis());
   internal::Timer timer;
-  impl->os_stack_trace_getter()->UponLeavingGTest();
+  UnitTest::GetInstance()->UponLeavingGTest();
 
   // Creates the test object.
   Test* const test = internal::HandleExceptionsInMethodIfSupported(
@@ -2861,7 +2860,7 @@
 
   if (test != nullptr) {
     // Deletes the test object.
-    impl->os_stack_trace_getter()->UponLeavingGTest();
+    UnitTest::GetInstance()->UponLeavingGTest();
     internal::HandleExceptionsInMethodIfSupported(
         test, &Test::DeleteSelf_, "the test fixture's destructor");
   }
@@ -2873,15 +2872,14 @@
 
   // Tells UnitTest to stop associating assertion results to this
   // test.
-  impl->set_current_test_info(nullptr);
+  UnitTest::GetInstance()->set_current_test_info(nullptr);
 }
 
 // Skip and records a skipped test result for this object.
 void TestInfo::Skip() {
   if (!should_run_) return;
 
-  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
-  impl->set_current_test_info(this);
+  UnitTest::GetInstance()->set_current_test_info(this);
 
   TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
 
@@ -2890,12 +2888,13 @@
 
   const TestPartResult test_part_result =
       TestPartResult(TestPartResult::kSkip, this->file(), this->line(), "");
-  impl->GetTestPartResultReporterForCurrentThread()->ReportTestPartResult(
-      test_part_result);
+  internal::GetUnitTestImpl()
+      ->GetTestPartResultReporterForCurrentThread()
+      ->ReportTestPartResult(test_part_result);
 
   // Notifies the unit test event listener that a test has just finished.
   repeater->OnTestEnd(*this);
-  impl->set_current_test_info(nullptr);
+  UnitTest::GetInstance()->set_current_test_info(nullptr);
 }
 
 // class TestSuite
@@ -2991,8 +2990,7 @@
 void TestSuite::Run() {
   if (!should_run_) return;
 
-  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
-  impl->set_current_test_suite(this);
+  UnitTest::GetInstance()->set_current_test_suite(this);
 
   TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
 
@@ -3022,7 +3020,7 @@
   repeater->OnTestCaseStart(*this);
 #endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
-  impl->os_stack_trace_getter()->UponLeavingGTest();
+  UnitTest::GetInstance()->UponLeavingGTest();
   internal::HandleExceptionsInMethodIfSupported(
       this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()");
 
@@ -3047,7 +3045,7 @@
   }
   elapsed_time_ = timer.Elapsed();
 
-  impl->os_stack_trace_getter()->UponLeavingGTest();
+  UnitTest::GetInstance()->UponLeavingGTest();
   internal::HandleExceptionsInMethodIfSupported(
       this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()");
 
@@ -3058,15 +3056,14 @@
   repeater->OnTestCaseEnd(*this);
 #endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
-  impl->set_current_test_suite(nullptr);
+  UnitTest::GetInstance()->set_current_test_suite(nullptr);
 }
 
 // Skips all tests under this TestSuite.
 void TestSuite::Skip() {
   if (!should_run_) return;
 
-  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
-  impl->set_current_test_suite(this);
+  UnitTest::GetInstance()->set_current_test_suite(this);
 
   TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
 
@@ -3088,7 +3085,7 @@
   repeater->OnTestCaseEnd(*this);
 #endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
-  impl->set_current_test_suite(nullptr);
+  UnitTest::GetInstance()->set_current_test_suite(nullptr);
 }
 
 // Clears the results of all tests in this test suite.
@@ -5304,6 +5301,22 @@
   return impl()->GetMutableSuiteCase(i);
 }
 
+void UnitTest::UponLeavingGTest() {
+  impl()->os_stack_trace_getter()->UponLeavingGTest();
+}
+
+// Sets the TestSuite object for the test that's currently running.
+void UnitTest::set_current_test_suite(TestSuite* a_current_test_suite) {
+  internal::MutexLock lock(&mutex_);
+  impl_->set_current_test_suite(a_current_test_suite);
+}
+
+// Sets the TestInfo object for the test that's currently running.
+void UnitTest::set_current_test_info(TestInfo* a_current_test_info) {
+  internal::MutexLock lock(&mutex_);
+  impl_->set_current_test_info(a_current_test_info);
+}
+
 // Returns the list of event listeners that can be used to track events
 // inside Google Test.
 TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); }
diff --git a/googletest_deps.bzl b/googletest_deps.bzl
index 8958890..1b7d2c8 100644
--- a/googletest_deps.bzl
+++ b/googletest_deps.bzl
@@ -1,6 +1,7 @@
 """Load dependencies needed to use the googletest library as a 3rd-party consumer."""
 
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("//:fake_fuchsia_sdk.bzl", "fake_fuchsia_sdk")
 
 def googletest_deps():
     """Loads common dependencies needed to use the googletest library."""
@@ -20,3 +21,8 @@
             strip_prefix = "abseil-cpp-20240116.0",
             urls = ["https://github.com/abseil/abseil-cpp/releases/download/20240116.0/abseil-cpp-20240116.0.tar.gz"],
         )
+
+    if not native.existing_rule("fuchsia_sdk"):
+        fake_fuchsia_sdk(
+            name = "fuchsia_sdk",
+        )