diff --git a/.gitignore b/.gitignore index f0df39db1..b83d192c7 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,4 @@ googlemock/gtest /CMakeCache.txt /ALL_BUILD.vcxproj.filters /ALL_BUILD.vcxproj +_codeql_* diff --git a/googlemock/src/gmock-spec-builders.cc b/googlemock/src/gmock-spec-builders.cc index 88e0c0200..61357c719 100644 --- a/googlemock/src/gmock-spec-builders.cc +++ b/googlemock/src/gmock-spec-builders.cc @@ -456,7 +456,8 @@ static CallReaction intToCallReaction(int mock_behavior) { namespace { -typedef std::set FunctionMockers; +// Modern alias for FunctionMockers +using FunctionMockers = std::set; // The current state of a mock object. Such information is needed for // detecting leaked mock objects and explicitly verifying a mock's @@ -473,6 +474,8 @@ struct MockObjectState { ::std::string first_used_test; bool leakable; // true if and only if it's OK to leak the object. FunctionMockers function_mockers; // All registered methods of the object. + + const std::type_info* mock_type; // Dynamic mock type (if registered) }; // A global registry holding the state of all mock objects that are @@ -481,13 +484,22 @@ struct MockObjectState { // is removed from the registry in the mock object's destructor. class MockObjectRegistry { public: - // Maps a mock object (identified by its address) to its state. - typedef std::map StateMap; + // New alias for StateMap + using StateMap = std::map; - // This destructor will be called when a program exits, after all - // tests in it have been run. By then, there should be no mock - // object alive. Therefore we report any living object as test - // failure, unless the user explicitly asked us to ignore it. + // New method to register the type of mock + template + void RegisterMockType(const void* mock_obj) { + internal::MutexLock l(&internal::g_gmock_mutex); + StateMap::iterator it = states_.find(mock_obj); + if (it != states_.end()) { + it->second.mock_type = &typeid(*static_cast(mock_obj)); + } + } + + // This destructor will be called when the program exits, after all tests have run. + // At that point, there should be no live mock objects. Therefore, we report any still-live object as + // a test failure, unless the user has explicitly asked to ignore it. ~MockObjectRegistry() { if (!GMOCK_FLAG_GET(catch_leaked_mocks)) return; internal::MutexLock l(internal::g_gmock_mutex); @@ -498,9 +510,12 @@ class MockObjectRegistry { if (it->second.leakable) // The user said it's fine to leak this object. continue; - // FIXME: Print the type of the leaked object. - // This can help the user identify the leaked object. - std::cout << "\n"; + // Print the type of the leaked object, if available + std::string type_name = ""; + if (it->second.mock_type) { + type_name = it->second.mock_type->name(); + } + ::std::cerr << "ERROR: Leaked mock object of type: " << type_name << "\n"; const MockObjectState& state = it->second; std::cout << internal::FormatFileLocation(state.first_used_file, state.first_used_line); @@ -575,14 +590,14 @@ void Mock::AllowUninterestingCalls(uintptr_t mock_obj) // Tells Google Mock to warn the user about uninteresting calls on the // given mock object. void Mock::WarnUninterestingCalls(uintptr_t mock_obj) - GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { + GTEST_LOCK_EXCLUDED_(internal::gmock_mutex) { SetReactionOnUninterestingCalls(mock_obj, internal::kWarn); } // Tells Google Mock to fail uninteresting calls on the given mock // object. void Mock::FailUninterestingCalls(uintptr_t mock_obj) - GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { + GTEST_LOCK_EXCLUDED_(internal::gmock_mutex) { SetReactionOnUninterestingCalls(mock_obj, internal::kFail); } diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 808d89be9..c123f272f 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -561,6 +561,15 @@ GTEST_API_ TestInfo* MakeAndRegisterTestInfo( TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory); +// Backward-compatible overload for ABI compatibility with v1.14.0 and earlier. +// This version takes const char* instead of std::string to avoid ABI issues +// when passing std::string by value across library boundaries. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory); + // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 80a7edad9..637a01058 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -2829,6 +2829,19 @@ TestInfo* MakeAndRegisterTestInfo( return test_info; } +// Backward-compatible overload for ABI compatibility with v1.14.0 and earlier. +TestInfo* MakeAndRegisterTestInfo( + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) { + // Forward to the std::string version + return MakeAndRegisterTestInfo(std::string(test_suite_name), name, type_param, + value_param, std::move(code_location), + fixture_class_id, set_up_tc, tear_down_tc, + factory); +} + void ReportInvalidTestSuiteType(const char* test_suite_name, const CodeLocation& code_location) { Message errors;