From 590080ec4a86ffebc696f57de10549740a3f92f2 Mon Sep 17 00:00:00 2001 From: Komi Atchoglo Date: Thu, 26 Dec 2024 04:20:56 +0100 Subject: [PATCH] Made modifiers inheritable * Mock object can be made Strict/Nice/Naggy by inheritance --- googlemock/include/gmock/gmock-nice-strict.h | 154 ++++++------------- googlemock/test/gmock-nice-strict_test.cc | 35 +++++ 2 files changed, 86 insertions(+), 103 deletions(-) diff --git a/googlemock/include/gmock/gmock-nice-strict.h b/googlemock/include/gmock/gmock-nice-strict.h index 056d471417..acf39e083f 100644 --- a/googlemock/include/gmock/gmock-nice-strict.h +++ b/googlemock/include/gmock/gmock-nice-strict.h @@ -70,26 +70,11 @@ #include "gmock/internal/gmock-port.h" namespace testing { -template -class NiceMock; -template -class NaggyMock; -template -class StrictMock; -namespace internal { -template -std::true_type StrictnessModifierProbe(const NiceMock&); -template -std::true_type StrictnessModifierProbe(const NaggyMock&); -template -std::true_type StrictnessModifierProbe(const StrictMock&); -std::false_type StrictnessModifierProbe(...); +template +class StrictNessBase; -template -constexpr bool HasStrictnessModifier() { - return decltype(StrictnessModifierProbe(std::declval()))::value; -} +namespace internal { // Base classes that register and deregister with testing::Mock to alter the // default behavior around uninteresting calls. Inheriting from one of these @@ -143,61 +128,58 @@ class StrictMockImpl { } }; +template +std::true_type StrictnessModifierProbe( + const StrictNessBase, T>&); +template +std::true_type StrictnessModifierProbe( + const StrictNessBase, T>&); +template +std::true_type StrictnessModifierProbe( + const StrictNessBase, T>&); +std::false_type StrictnessModifierProbe(...); + +template +constexpr bool HasStrictnessModifier() { + return decltype(StrictnessModifierProbe(std::declval()))::value; +} + } // namespace internal -template -class GTEST_INTERNAL_EMPTY_BASE_CLASS NiceMock - : private internal::NiceMockImpl, - public MockClass { +template +class GTEST_INTERNAL_EMPTY_BASE_CLASS StrictNessBase + : public StrictNessModifier { public: - static_assert(!internal::HasStrictnessModifier(), + static_assert(!internal::HasStrictnessModifier(), "Can't apply NiceMock to a class hierarchy that already has a " "strictness modifier. See " "https://google.github.io/googletest/" "gmock_cook_book.html#NiceStrictNaggy"); - NiceMock() : MockClass() { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } - - // Ideally, we would inherit base class's constructors through a using - // declaration, which would preserve their visibility. However, many existing - // tests rely on the fact that current implementation reexports protected - // constructors as public. These tests would need to be cleaned up first. - - // Single argument constructor is special-cased so that it can be - // made explicit. - template - explicit NiceMock(A&& arg) : MockClass(std::forward(arg)) { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } - - template - NiceMock(TArg1&& arg1, TArg2&& arg2, An&&... args) - : MockClass(std::forward(arg1), std::forward(arg2), - std::forward(args)...) { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } + StrictNessBase() = default; private: - NiceMock(const NiceMock&) = delete; - NiceMock& operator=(const NiceMock&) = delete; + StrictNessBase(const StrictNessBase&) = delete; + StrictNessBase& operator=(const StrictNessBase&) = delete; }; template -class GTEST_INTERNAL_EMPTY_BASE_CLASS NaggyMock - : private internal::NaggyMockImpl, - public MockClass { - static_assert(!internal::HasStrictnessModifier(), - "Can't apply NaggyMock to a class hierarchy that already has a " - "strictness modifier. See " - "https://google.github.io/googletest/" - "gmock_cook_book.html#NiceStrictNaggy"); +using NiceMockable = + StrictNessBase, MockClass>; +template +using StrictMockable = + StrictNessBase, MockClass>; + +template +using NaggyMockable = + StrictNessBase, MockClass>; + +template +class GTEST_INTERNAL_EMPTY_BASE_CLASS StrictNessMockImplBase + : public StrictNessModifier, + public MockClass { public: - NaggyMock() : MockClass() { + StrictNessMockImplBase() : MockClass() { static_assert(sizeof(*this) == sizeof(MockClass), "The impl subclass shouldn't introduce any padding"); } @@ -210,65 +192,31 @@ class GTEST_INTERNAL_EMPTY_BASE_CLASS NaggyMock // Single argument constructor is special-cased so that it can be // made explicit. template - explicit NaggyMock(A&& arg) : MockClass(std::forward(arg)) { + explicit StrictNessMockImplBase(A&& arg) : MockClass(std::forward(arg)) { static_assert(sizeof(*this) == sizeof(MockClass), "The impl subclass shouldn't introduce any padding"); } template - NaggyMock(TArg1&& arg1, TArg2&& arg2, An&&... args) + StrictNessMockImplBase(TArg1&& arg1, TArg2&& arg2, An&&... args) : MockClass(std::forward(arg1), std::forward(arg2), std::forward(args)...) { static_assert(sizeof(*this) == sizeof(MockClass), "The impl subclass shouldn't introduce any padding"); } - - private: - NaggyMock(const NaggyMock&) = delete; - NaggyMock& operator=(const NaggyMock&) = delete; }; template -class GTEST_INTERNAL_EMPTY_BASE_CLASS StrictMock - : private internal::StrictMockImpl, - public MockClass { - public: - static_assert( - !internal::HasStrictnessModifier(), - "Can't apply StrictMock to a class hierarchy that already has a " - "strictness modifier. See " - "https://google.github.io/googletest/" - "gmock_cook_book.html#NiceStrictNaggy"); - StrictMock() : MockClass() { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } - - // Ideally, we would inherit base class's constructors through a using - // declaration, which would preserve their visibility. However, many existing - // tests rely on the fact that current implementation reexports protected - // constructors as public. These tests would need to be cleaned up first. - - // Single argument constructor is special-cased so that it can be - // made explicit. - template - explicit StrictMock(A&& arg) : MockClass(std::forward(arg)) { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } +using NiceMock = + StrictNessMockImplBase, MockClass>; - template - StrictMock(TArg1&& arg1, TArg2&& arg2, An&&... args) - : MockClass(std::forward(arg1), std::forward(arg2), - std::forward(args)...) { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } +template +using StrictMock = + StrictNessMockImplBase, MockClass>; - private: - StrictMock(const StrictMock&) = delete; - StrictMock& operator=(const StrictMock&) = delete; -}; +template +using NaggyMock = + StrictNessMockImplBase, MockClass>; #undef GTEST_INTERNAL_EMPTY_BASE_CLASS diff --git a/googlemock/test/gmock-nice-strict_test.cc b/googlemock/test/gmock-nice-strict_test.cc index 95f0969035..19463ae69f 100644 --- a/googlemock/test/gmock-nice-strict_test.cc +++ b/googlemock/test/gmock-nice-strict_test.cc @@ -139,6 +139,21 @@ class MockBaz { MockBaz(MoveOnly) {} }; +class NiceMockModifier : public NiceMockable { + public: + NiceMockModifier() = default; +}; + +class NaggyMockModifier : public NaggyMockable { + public: + NaggyMockModifier() = default; +}; + +class StrictMockModifier : public StrictMockable { + public: + StrictMockModifier() = default; +}; + #if GTEST_HAS_STREAM_REDIRECTION // Tests that a raw mock generates warnings for uninteresting calls. @@ -324,6 +339,13 @@ TEST(NiceMockTest, IsNaggy_IsNice_IsStrict) { EXPECT_FALSE(Mock::IsStrict(&nice_foo)); } +TEST(NiceMockTest, IsNaggy_IsNice_IsStrict_Class) { + NiceMockModifier nice_foo; + EXPECT_FALSE(Mock::IsNaggy(&nice_foo)); + EXPECT_TRUE(Mock::IsNice(&nice_foo)); + EXPECT_FALSE(Mock::IsStrict(&nice_foo)); +} + #if GTEST_HAS_STREAM_REDIRECTION // Tests that a naggy mock generates warnings for uninteresting calls. @@ -443,6 +465,13 @@ TEST(NaggyMockTest, IsNaggy_IsNice_IsStrict) { EXPECT_FALSE(Mock::IsStrict(&naggy_foo)); } +TEST(NaggyMockTest, IsNaggy_IsNice_IsStrict_Class) { + NaggyMockModifier naggy_foo; + EXPECT_TRUE(Mock::IsNaggy(&naggy_foo)); + EXPECT_FALSE(Mock::IsNice(&naggy_foo)); + EXPECT_FALSE(Mock::IsStrict(&naggy_foo)); +} + // Tests that a strict mock allows expected calls. TEST(StrictMockTest, AllowsExpectedCall) { StrictMock strict_foo; @@ -537,5 +566,11 @@ TEST(StrictMockTest, IsNaggy_IsNice_IsStrict) { EXPECT_TRUE(Mock::IsStrict(&strict_foo)); } +TEST(StrictMockTest, IsNaggy_IsNice_IsStrict_Class) { + StrictMockModifier strict_foo; + EXPECT_FALSE(Mock::IsNaggy(&strict_foo)); + EXPECT_FALSE(Mock::IsNice(&strict_foo)); + EXPECT_TRUE(Mock::IsStrict(&strict_foo)); +} } // namespace gmock_nice_strict_test } // namespace testing