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 MockClass> -class NiceMock; -template <class MockClass> -class NaggyMock; -template <class MockClass> -class StrictMock; -namespace internal { -template <typename T> -std::true_type StrictnessModifierProbe(const NiceMock<T>&); -template <typename T> -std::true_type StrictnessModifierProbe(const NaggyMock<T>&); -template <typename T> -std::true_type StrictnessModifierProbe(const StrictMock<T>&); -std::false_type StrictnessModifierProbe(...); +template <class StrictNessModifier, class MockClass> +class StrictNessBase; -template <typename T> -constexpr bool HasStrictnessModifier() { - return decltype(StrictnessModifierProbe(std::declval<const T&>()))::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 <typename T> +std::true_type StrictnessModifierProbe( + const StrictNessBase<internal::NiceMockImpl<T>, T>&); +template <typename T> +std::true_type StrictnessModifierProbe( + const StrictNessBase<internal::NaggyMockImpl<T>, T>&); +template <typename T> +std::true_type StrictnessModifierProbe( + const StrictNessBase<internal::StrictMockImpl<T>, T>&); +std::false_type StrictnessModifierProbe(...); + +template <typename T> +constexpr bool HasStrictnessModifier() { + return decltype(StrictnessModifierProbe(std::declval<const T&>()))::value; +} + } // namespace internal -template <class MockClass> -class GTEST_INTERNAL_EMPTY_BASE_CLASS NiceMock - : private internal::NiceMockImpl<MockClass>, - public MockClass { +template <class StrictNessModifier, class MockClass> +class GTEST_INTERNAL_EMPTY_BASE_CLASS StrictNessBase + : public StrictNessModifier { public: - static_assert(!internal::HasStrictnessModifier<MockClass>(), + static_assert(!internal::HasStrictnessModifier<StrictNessModifier>(), "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 <typename A> - explicit NiceMock(A&& arg) : MockClass(std::forward<A>(arg)) { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } - - template <typename TArg1, typename TArg2, typename... An> - NiceMock(TArg1&& arg1, TArg2&& arg2, An&&... args) - : MockClass(std::forward<TArg1>(arg1), std::forward<TArg2>(arg2), - std::forward<An>(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 MockClass> -class GTEST_INTERNAL_EMPTY_BASE_CLASS NaggyMock - : private internal::NaggyMockImpl<MockClass>, - public MockClass { - static_assert(!internal::HasStrictnessModifier<MockClass>(), - "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<internal::NiceMockImpl<MockClass>, MockClass>; +template <class MockClass> +using StrictMockable = + StrictNessBase<internal::StrictMockImpl<MockClass>, MockClass>; + +template <class MockClass> +using NaggyMockable = + StrictNessBase<internal::NaggyMockImpl<MockClass>, MockClass>; + +template <class StrictNessModifier, class MockClass> +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 <typename A> - explicit NaggyMock(A&& arg) : MockClass(std::forward<A>(arg)) { + explicit StrictNessMockImplBase(A&& arg) : MockClass(std::forward<A>(arg)) { static_assert(sizeof(*this) == sizeof(MockClass), "The impl subclass shouldn't introduce any padding"); } template <typename TArg1, typename TArg2, typename... An> - NaggyMock(TArg1&& arg1, TArg2&& arg2, An&&... args) + StrictNessMockImplBase(TArg1&& arg1, TArg2&& arg2, An&&... args) : MockClass(std::forward<TArg1>(arg1), std::forward<TArg2>(arg2), std::forward<An>(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 MockClass> -class GTEST_INTERNAL_EMPTY_BASE_CLASS StrictMock - : private internal::StrictMockImpl<MockClass>, - public MockClass { - public: - static_assert( - !internal::HasStrictnessModifier<MockClass>(), - "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 <typename A> - explicit StrictMock(A&& arg) : MockClass(std::forward<A>(arg)) { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } +using NiceMock = + StrictNessMockImplBase<internal::NiceMockImpl<MockClass>, MockClass>; - template <typename TArg1, typename TArg2, typename... An> - StrictMock(TArg1&& arg1, TArg2&& arg2, An&&... args) - : MockClass(std::forward<TArg1>(arg1), std::forward<TArg2>(arg2), - std::forward<An>(args)...) { - static_assert(sizeof(*this) == sizeof(MockClass), - "The impl subclass shouldn't introduce any padding"); - } +template <class MockClass> +using StrictMock = + StrictNessMockImplBase<internal::StrictMockImpl<MockClass>, MockClass>; - private: - StrictMock(const StrictMock&) = delete; - StrictMock& operator=(const StrictMock&) = delete; -}; +template <class MockClass> +using NaggyMock = + StrictNessMockImplBase<internal::NaggyMockImpl<MockClass>, 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<NiceMockModifier> { + public: + NiceMockModifier() = default; +}; + +class NaggyMockModifier : public NaggyMockable<NaggyMockModifier> { + public: + NaggyMockModifier() = default; +}; + +class StrictMockModifier : public StrictMockable<StrictMockModifier> { + 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<MockFoo> 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