Fixes a lock reentrancy when destroying a mock causes destruction of another mock (issue 79) (by Aaron Jacobs).

This commit is contained in:
vladlosev
2011-10-24 23:41:07 +00:00
parent 4d60a596b4
commit 9bcb5f9146
3 changed files with 85 additions and 5 deletions

View File

@@ -88,13 +88,14 @@ using testing::Mock;
using testing::Ne;
using testing::Return;
using testing::Sequence;
using testing::SetArgPointee;
using testing::internal::ExpectationTester;
using testing::internal::FormatFileLocation;
using testing::internal::g_gmock_mutex;
using testing::internal::kErrorVerbosity;
using testing::internal::kInfoVerbosity;
using testing::internal::kWarningVerbosity;
using testing::internal::String;
using testing::internal::linked_ptr;
using testing::internal::string;
#if GTEST_HAS_STREAM_REDIRECTION
@@ -157,6 +158,16 @@ class MockB {
GTEST_DISALLOW_COPY_AND_ASSIGN_(MockB);
};
class ReferenceHoldingMock {
public:
ReferenceHoldingMock() {}
MOCK_METHOD1(AcceptReference, void(linked_ptr<MockA>*));
private:
GTEST_DISALLOW_COPY_AND_ASSIGN_(ReferenceHoldingMock);
};
// Tests that EXPECT_CALL and ON_CALL compile in a presence of macro
// redefining a mock method name. This could happen, for example, when
// the tested code #includes Win32 API headers which define many APIs
@@ -2439,6 +2450,46 @@ TEST(VerifyAndClearTest, DoesNotAffectOtherMockObjects) {
EXPECT_EQ(2, b1.DoB(0));
}
TEST(VerifyAndClearTest,
DestroyingChainedMocksDoesNotDeadlockThroughExpectations) {
linked_ptr<MockA> a(new MockA);
ReferenceHoldingMock test_mock;
// EXPECT_CALL stores a reference to a inside test_mock.
EXPECT_CALL(test_mock, AcceptReference(_))
.WillRepeatedly(SetArgPointee<0>(a));
// Throw away the reference to the mock that we have in a. After this, the
// only reference to it is stored by test_mock.
a.reset();
// When test_mock goes out of scope, it destroys the last remaining reference
// to the mock object originally pointed to by a. This will cause the MockA
// destructor to be called from inside the ReferenceHoldingMock destructor.
// The state of all mocks is protected by a single global lock, but there
// should be no deadlock.
}
TEST(VerifyAndClearTest,
DestroyingChainedMocksDoesNotDeadlockThroughDefaultAction) {
linked_ptr<MockA> a(new MockA);
ReferenceHoldingMock test_mock;
// ON_CALL stores a reference to a inside test_mock.
ON_CALL(test_mock, AcceptReference(_))
.WillByDefault(SetArgPointee<0>(a));
// Throw away the reference to the mock that we have in a. After this, the
// only reference to it is stored by test_mock.
a.reset();
// When test_mock goes out of scope, it destroys the last remaining reference
// to the mock object originally pointed to by a. This will cause the MockA
// destructor to be called from inside the ReferenceHoldingMock destructor.
// The state of all mocks is protected by a single global lock, but there
// should be no deadlock.
}
// Tests that a mock function's action can call a mock function
// (either the same function or a different one) either as an explicit
// action or as a default action without causing a dead lock. It