diff --git a/docs/gmock_cheat_sheet.md b/docs/gmock_cheat_sheet.md index 62159998b..4cb3fd733 100644 --- a/docs/gmock_cheat_sheet.md +++ b/docs/gmock_cheat_sheet.md @@ -189,6 +189,14 @@ expectations must be matched in a given order, you can use the [`InSequence` clause](reference/mocking.md#EXPECT_CALL.InSequence) of `EXPECT_CALL`, or use an [`InSequence` object](reference/mocking.md#InSequence). +## Distinguishing between Unintresting Calls from Different Mocks + +By default unintresting mock function calls will be logged as function name and its address. +In case when multiple instances of same mocked class is used it can be useful to set mock name: +```cpp +Mock::SetMockName(&mock_obj, "NamedObject"); +``` + ## Verifying and Resetting a Mock gMock will verify the expectations on a mock object when it is destructed, or diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h index f1c979d6f..d002dffbb 100644 --- a/googlemock/include/gmock/gmock-spec-builders.h +++ b/googlemock/include/gmock/gmock-spec-builders.h @@ -382,6 +382,15 @@ class GTEST_API_ Mock { static bool VerifyAndClear(void* mock_obj) GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); + // Set name for mock. Will be used in output. + // Useful when multiple instances of same mock is required. + static void SetMockName(void* mock_obj, const std::string& mock_name) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); + + // Returns mock name which was set using SetMockName + static std::string GetMockName(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); + // Returns whether the mock was created as a naggy mock (default) static bool IsNaggy(void* mock_obj) GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex); @@ -1622,6 +1631,8 @@ class FunctionMocker final : public UntypedFunctionMockerBase { DescribeDefaultActionTo(args, os); *os << " Function call: " << Name(); UniversalPrint(args, os); + const auto mock_name = Mock::GetMockName(MockObject()); + if (!mock_name.empty()) *os << " on " << mock_name; } // Returns the expectation that matches the given function arguments diff --git a/googlemock/src/gmock-spec-builders.cc b/googlemock/src/gmock-spec-builders.cc index 88e0c0200..d222dd792 100644 --- a/googlemock/src/gmock-spec-builders.cc +++ b/googlemock/src/gmock-spec-builders.cc @@ -471,6 +471,7 @@ struct MockObjectState { int first_used_line; ::std::string first_used_test_suite; ::std::string first_used_test; + ::std::string name; bool leakable; // true if and only if it's OK to leak the object. FunctionMockers function_mockers; // All registered methods of the object. }; @@ -634,6 +635,22 @@ bool Mock::VerifyAndClear(void* mock_obj) return VerifyAndClearExpectationsLocked(mock_obj); } +// Set name for mock. Will be used in output. +// Useful when multiple instances of same mock is required. +void Mock::SetMockName(void* mock_obj, const std::string& mock_name) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { + internal::MutexLock l(&internal::g_gmock_mutex); + g_mock_object_registry.states()[mock_obj].name = mock_name; +} + +// Returns mock name which was set using SetMockName +std::string Mock::GetMockName(const void* mock_obj) + GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) { + internal::MutexLock l(&internal::g_gmock_mutex); + if (g_mock_object_registry.states().count(mock_obj) == 0) return ""; + return g_mock_object_registry.states()[mock_obj].name; +} + // Verifies and clears all expectations on the given mock object. If // the expectations aren't satisfied, generates one or more Google // Test non-fatal failures and returns false. @@ -712,14 +729,13 @@ void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) internal::g_gmock_mutex.AssertHeld(); for (MockObjectRegistry::StateMap::iterator it = g_mock_object_registry.states().begin(); - it != g_mock_object_registry.states().end(); ++it) { + it != g_mock_object_registry.states().end();) { FunctionMockers& mockers = it->second.function_mockers; - if (mockers.erase(mocker) > 0) { - // mocker was in mockers and has been just removed. - if (mockers.empty()) { - g_mock_object_registry.states().erase(it); - } - return; + mockers.erase(mocker); + if (mockers.empty()) { + it = g_mock_object_registry.states().erase(it); + } else { + ++it; } } } diff --git a/googlemock/test/gmock-nice-strict_test.cc b/googlemock/test/gmock-nice-strict_test.cc index 95f096903..3cb0ce472 100644 --- a/googlemock/test/gmock-nice-strict_test.cc +++ b/googlemock/test/gmock-nice-strict_test.cc @@ -190,6 +190,24 @@ TEST(RawMockTest, InfoForUninterestingCall) { GMOCK_FLAG_SET(verbose, saved_flag); } +// Tests that a raw mock using mock name in warnings for uninteresting calls. +TEST(RawMockTest, NamedMockInUninteresingCall) { + MockFoo raw_foo; + + const std::string saved_flag = GMOCK_FLAG_GET(verbose); + GMOCK_FLAG_SET(verbose, "info"); + + const std::string test_name = "NamedMock"; + Mock::SetMockName(&raw_foo, test_name); + CaptureStdout(); + raw_foo.DoThis(); + ASSERT_THAT(GetCapturedStdout(), + HasSubstr("Uninteresting mock function call")); + EXPECT_THAT(GetCapturedStdout(), HasSubstr(test_name)); + + GMOCK_FLAG_SET(verbose, saved_flag); +} + TEST(RawMockTest, IsNaggy_IsNice_IsStrict) { MockFoo raw_foo; EXPECT_TRUE(Mock::IsNaggy(&raw_foo));