diff --git a/deps/googletest/include/gtest/gtest-typed-test.h b/deps/googletest/include/gtest/gtest-typed-test.h index 8575a41076ed..19b492289817 100644 --- a/deps/googletest/include/gtest/gtest-typed-test.h +++ b/deps/googletest/include/gtest/gtest-typed-test.h @@ -256,8 +256,11 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. -#define TYPED_TEST_SUITE_P(SuiteName) \ - static ::testing::internal::TypedTestSuitePState \ +// Marked [[maybe_unused]] because TypedTestSuitePState is +// constexpr-constructible and trivially destructible, so an uninstantiated +// suite would otherwise trigger -Wunused-variable. +#define TYPED_TEST_SUITE_P(SuiteName) \ + [[maybe_unused]] static ::testing::internal::TypedTestSuitePState \ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName) // Legacy API is deprecated but still available @@ -267,22 +270,24 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); TYPED_TEST_SUITE_P #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -#define TYPED_TEST_P(SuiteName, TestName) \ - namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ - template \ - class TestName : public SuiteName { \ - private: \ - typedef SuiteName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - void TestBody() override; \ - }; \ - [[maybe_unused]] static bool gtest_##TestName##_defined_ = \ - GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ - __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \ - GTEST_STRINGIFY_(TestName)); \ - } \ - template \ - void GTEST_SUITE_NAMESPACE_( \ +#define TYPED_TEST_P(SuiteName, TestName) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + template \ + class TestName : public SuiteName { \ + private: \ + typedef SuiteName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + void TestBody() override; \ + }; \ + static ::testing::internal::TypedTestSuitePState::RegisteredTest \ + gtest_##TestName##_registered_test_ = {GTEST_STRINGIFY_(TestName), \ + __FILE__, __LINE__, nullptr}; \ + [[maybe_unused]] static bool gtest_##TestName##_defined_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTest( \ + >est_##TestName##_registered_test_, GTEST_STRINGIFY_(SuiteName)); \ + } \ + template \ + void GTEST_SUITE_NAMESPACE_( \ SuiteName)::TestName::TestBody() // Note: this won't work correctly if the trailing arguments are macros. diff --git a/deps/googletest/include/gtest/internal/gtest-internal.h b/deps/googletest/include/gtest/internal/gtest-internal.h index f845ffed298e..5a83b4edd60a 100644 --- a/deps/googletest/include/gtest/internal/gtest-internal.h +++ b/deps/googletest/include/gtest/internal/gtest-internal.h @@ -577,51 +577,87 @@ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) // State of the definition of a type-parameterized test suite. +// Uses an intrusive linked list of caller-allocated POD RegisteredTest nodes +// rather than an STL container. +// REQUIRES: TypedTestSuitePState must be constexpr-constructible and trivially +// destructible so that namespace-scope static instances defined by +// TYPED_TEST_SUITE_P avoid -Wglobal-constructors and -Wexit-time-destructors. class GTEST_API_ [[nodiscard]] TypedTestSuitePState { public: - TypedTestSuitePState() : registered_(false) {} - - // Adds the given test name to defined_test_names_ and return true - // if the test suite hasn't been registered; otherwise aborts the - // program. - bool AddTestName(const char* file, int line, const char* case_name, - const char* test_name) { + // Caller-owned POD node linked into registered_tests_; must outlive this + // TypedTestSuitePState instance. + struct RegisteredTest { + const char* name; + const char* file; + int line; + RegisteredTest* next; + }; + + constexpr TypedTestSuitePState() = default; + + // Adds the given test to registered_tests_ and returns true if the test + // suite hasn't been registered; otherwise aborts the program. + bool AddTest(RegisteredTest* test, const char* case_name) { if (registered_) { fprintf(stderr, "%s Test %s must be defined before " "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n", - FormatFileLocation(file, line).c_str(), test_name, case_name); + FormatFileLocation(test->file, test->line).c_str(), test->name, + case_name); fflush(stderr); posix::Abort(); } - registered_tests_.emplace(test_name, CodeLocation(file, line)); + // Insert into registered_tests_ in lexicographical order by test name + // (ignoring duplicates) so VerifyRegisteredTestNames reports missing tests + // in deterministic sorted order. + RegisteredTest** p = ®istered_tests_; + while (*p != nullptr && strcmp((*p)->name, test->name) < 0) { + p = &(*p)->next; + } + if (*p == nullptr || strcmp((*p)->name, test->name) != 0) { + test->next = *p; + *p = test; + } return true; } bool TestExists(const std::string& test_name) const { - return registered_tests_.count(test_name) > 0; + return FindTest(test_name) != nullptr; } - const CodeLocation& GetCodeLocation(const std::string& test_name) const { - RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); - GTEST_CHECK_(it != registered_tests_.end()); - return it->second; + CodeLocation GetCodeLocation(const std::string& test_name) const { + const RegisteredTest* test = FindTest(test_name); + GTEST_CHECK_(test != nullptr); + return CodeLocation(test->file, test->line); } // Verifies that registered_tests match the test names in - // defined_test_names_; returns registered_tests if successful, or + // registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. const char* VerifyRegisteredTestNames(const char* test_suite_name, const char* file, int line, const char* registered_tests); private: - typedef ::std::map> RegisteredTestsMap; + const RegisteredTest* FindTest(const std::string& test_name) const { + for (const RegisteredTest* it = registered_tests_; it != nullptr; + it = it->next) { + if (test_name == it->name) { + return it; + } + } + return nullptr; + } - bool registered_; - RegisteredTestsMap registered_tests_; + bool registered_ = false; + RegisteredTest* registered_tests_ = nullptr; }; +static_assert((static_cast(TypedTestSuitePState{}), true), + "TypedTestSuitePState must be constexpr-constructible"); +static_assert(std::is_trivially_destructible_v, + "TypedTestSuitePState must be trivially destructible"); + // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ using TypedTestCasePState = TypedTestSuitePState; diff --git a/deps/googletest/src/gtest-typed-test.cc b/deps/googletest/src/gtest-typed-test.cc index b251c09deb80..e2cfaa019a9a 100644 --- a/deps/googletest/src/gtest-typed-test.cc +++ b/deps/googletest/src/gtest-typed-test.cc @@ -62,7 +62,6 @@ const char* TypedTestSuitePState::VerifyRegisteredTestNames( const char* registered_tests) { RegisterTypeParameterizedTestSuite(test_suite_name, CodeLocation(file, line)); - typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; std::vector name_vec = SplitIntoTestNames(registered_tests); @@ -78,7 +77,7 @@ const char* TypedTestSuitePState::VerifyRegisteredTestNames( continue; } - if (registered_tests_.count(name) != 0) { + if (TestExists(name)) { tests.insert(name); } else { errors << "No test named " << name @@ -86,10 +85,10 @@ const char* TypedTestSuitePState::VerifyRegisteredTestNames( } } - for (RegisteredTestIter it = registered_tests_.begin(); - it != registered_tests_.end(); ++it) { - if (tests.count(it->first) == 0) { - errors << "You forgot to list test " << it->first << ".\n"; + for (const RegisteredTest* it = registered_tests_; it != nullptr; + it = it->next) { + if (tests.count(it->name) == 0) { + errors << "You forgot to list test " << it->name << ".\n"; } }