This commit is contained in:
AKJ7 2025-02-18 12:27:36 -08:00 committed by GitHub
commit bc66a01428
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 86 additions and 103 deletions

View File

@ -70,26 +70,11 @@
#include "gmock/internal/gmock-port.h" #include "gmock/internal/gmock-port.h"
namespace testing { namespace testing {
template <class MockClass>
class NiceMock; template <class StrictNessModifier, class MockClass>
template <class MockClass> class StrictNessBase;
class NaggyMock;
template <class MockClass>
class StrictMock;
namespace internal { 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 <typename T>
constexpr bool HasStrictnessModifier() {
return decltype(StrictnessModifierProbe(std::declval<const T&>()))::value;
}
// Base classes that register and deregister with testing::Mock to alter the // Base classes that register and deregister with testing::Mock to alter the
// default behavior around uninteresting calls. Inheriting from one of these // 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 } // namespace internal
template <class MockClass> template <class StrictNessModifier, class MockClass>
class GTEST_INTERNAL_EMPTY_BASE_CLASS NiceMock class GTEST_INTERNAL_EMPTY_BASE_CLASS StrictNessBase
: private internal::NiceMockImpl<MockClass>, : public StrictNessModifier {
public MockClass {
public: public:
static_assert(!internal::HasStrictnessModifier<MockClass>(), static_assert(!internal::HasStrictnessModifier<StrictNessModifier>(),
"Can't apply NiceMock to a class hierarchy that already has a " "Can't apply NiceMock to a class hierarchy that already has a "
"strictness modifier. See " "strictness modifier. See "
"https://google.github.io/googletest/" "https://google.github.io/googletest/"
"gmock_cook_book.html#NiceStrictNaggy"); "gmock_cook_book.html#NiceStrictNaggy");
NiceMock() : MockClass() { StrictNessBase() = default;
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");
}
private: private:
NiceMock(const NiceMock&) = delete; StrictNessBase(const StrictNessBase&) = delete;
NiceMock& operator=(const NiceMock&) = delete; StrictNessBase& operator=(const StrictNessBase&) = delete;
}; };
template <class MockClass> template <class MockClass>
class GTEST_INTERNAL_EMPTY_BASE_CLASS NaggyMock using NiceMockable =
: private internal::NaggyMockImpl<MockClass>, StrictNessBase<internal::NiceMockImpl<MockClass>, 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");
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: public:
NaggyMock() : MockClass() { StrictNessMockImplBase() : MockClass() {
static_assert(sizeof(*this) == sizeof(MockClass), static_assert(sizeof(*this) == sizeof(MockClass),
"The impl subclass shouldn't introduce any padding"); "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 // Single argument constructor is special-cased so that it can be
// made explicit. // made explicit.
template <typename A> 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), static_assert(sizeof(*this) == sizeof(MockClass),
"The impl subclass shouldn't introduce any padding"); "The impl subclass shouldn't introduce any padding");
} }
template <typename TArg1, typename TArg2, typename... An> 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), : MockClass(std::forward<TArg1>(arg1), std::forward<TArg2>(arg2),
std::forward<An>(args)...) { std::forward<An>(args)...) {
static_assert(sizeof(*this) == sizeof(MockClass), static_assert(sizeof(*this) == sizeof(MockClass),
"The impl subclass shouldn't introduce any padding"); "The impl subclass shouldn't introduce any padding");
} }
private:
NaggyMock(const NaggyMock&) = delete;
NaggyMock& operator=(const NaggyMock&) = delete;
}; };
template <class MockClass> template <class MockClass>
class GTEST_INTERNAL_EMPTY_BASE_CLASS StrictMock using NiceMock =
: private internal::StrictMockImpl<MockClass>, StrictNessMockImplBase<internal::NiceMockImpl<MockClass>, 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 template <class MockClass>
// declaration, which would preserve their visibility. However, many existing using StrictMock =
// tests rely on the fact that current implementation reexports protected StrictNessMockImplBase<internal::StrictMockImpl<MockClass>, MockClass>;
// constructors as public. These tests would need to be cleaned up first.
// Single argument constructor is special-cased so that it can be template <class MockClass>
// made explicit. using NaggyMock =
template <typename A> StrictNessMockImplBase<internal::NaggyMockImpl<MockClass>, MockClass>;
explicit StrictMock(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>
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");
}
private:
StrictMock(const StrictMock&) = delete;
StrictMock& operator=(const StrictMock&) = delete;
};
#undef GTEST_INTERNAL_EMPTY_BASE_CLASS #undef GTEST_INTERNAL_EMPTY_BASE_CLASS

View File

@ -139,6 +139,21 @@ class MockBaz {
MockBaz(MoveOnly) {} 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 #if GTEST_HAS_STREAM_REDIRECTION
// Tests that a raw mock generates warnings for uninteresting calls. // 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)); 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 #if GTEST_HAS_STREAM_REDIRECTION
// Tests that a naggy mock generates warnings for uninteresting calls. // 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)); 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. // Tests that a strict mock allows expected calls.
TEST(StrictMockTest, AllowsExpectedCall) { TEST(StrictMockTest, AllowsExpectedCall) {
StrictMock<MockFoo> strict_foo; StrictMock<MockFoo> strict_foo;
@ -537,5 +566,11 @@ TEST(StrictMockTest, IsNaggy_IsNice_IsStrict) {
EXPECT_TRUE(Mock::IsStrict(&strict_foo)); 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 gmock_nice_strict_test
} // namespace testing } // namespace testing