From de5be0eb28b74ecd6335e3bd61d9dc8914ce0e57 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 8 Nov 2018 11:14:50 -0500 Subject: Googletest export Move FunctionMocker and MockFunction out of the pump file and implement with variadic templates. PiperOrigin-RevId: 220640265 --- googlemock/include/gmock/gmock-spec-builders.h | 213 +++++++++++++++++-------- 1 file changed, 144 insertions(+), 69 deletions(-) (limited to 'googlemock/include/gmock/gmock-spec-builders.h') diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h index e58adfcb..9dce2247 100644 --- a/googlemock/include/gmock/gmock-spec-builders.h +++ b/googlemock/include/gmock/gmock-spec-builders.h @@ -106,9 +106,6 @@ template class TypedExpectation; // Helper class for testing the Expectation class template. class ExpectationTester; -// Base class for function mockers. -template class FunctionMockerBase; - // Protects the mock object registry (in class Mock), all function // mockers, and all expectations. // @@ -125,9 +122,9 @@ GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex); // Untyped base class for ActionResultHolder. class UntypedActionResultHolderBase; -// Abstract base class of FunctionMockerBase. This is the +// Abstract base class of FunctionMocker. This is the // type-agnostic part of the function mocker interface. Its pure -// virtual methods are implemented by FunctionMockerBase. +// virtual methods are implemented by FunctionMocker. class GTEST_API_ UntypedFunctionMockerBase { public: UntypedFunctionMockerBase(); @@ -415,7 +412,7 @@ class GTEST_API_ Mock { // Needed for a function mocker to register itself (so that we know // how to clear a mock object). template - friend class internal::FunctionMockerBase; + friend class internal::FunctionMocker; template friend class NiceMock; @@ -478,7 +475,7 @@ class GTEST_API_ Mock { // Unregisters a mock method; removes the owning mock object from // the registry when the last mock method associated with it has // been unregistered. This is called only in the destructor of - // FunctionMockerBase. + // FunctionMocker. static void UnregisterLocked(internal::UntypedFunctionMockerBase* mocker) GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex); }; // class Mock @@ -534,7 +531,7 @@ class GTEST_API_ Expectation { friend class ::testing::internal::UntypedFunctionMockerBase; template - friend class ::testing::internal::FunctionMockerBase; + friend class ::testing::internal::FunctionMocker; template friend class ::testing::internal::TypedExpectation; @@ -893,7 +890,7 @@ class TypedExpectation : public ExpectationBase { typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; typedef typename Function::Result Result; - TypedExpectation(FunctionMockerBase* owner, const char* a_file, int a_line, + TypedExpectation(FunctionMocker* owner, const char* a_file, int a_line, const std::string& a_source_text, const ArgumentMatcherTuple& m) : ExpectationBase(a_file, a_line, a_source_text), @@ -1082,7 +1079,7 @@ class TypedExpectation : public ExpectationBase { private: template - friend class FunctionMockerBase; + friend class FunctionMocker; // Returns an Expectation object that references and co-owns this // expectation. @@ -1161,10 +1158,9 @@ class TypedExpectation : public ExpectationBase { } // Returns the action that should be taken for the current invocation. - const Action& GetCurrentAction( - const FunctionMockerBase* mocker, - const ArgumentTuple& args) const - GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { + const Action& GetCurrentAction(const FunctionMocker* mocker, + const ArgumentTuple& args) const + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); const int count = call_count(); Assert(count >= 1, __FILE__, __LINE__, @@ -1199,12 +1195,11 @@ class TypedExpectation : public ExpectationBase { // Mock does it to 'why'. This method is not const as it calls // IncrementCallCount(). A return value of NULL means the default // action. - const Action* GetActionForArguments( - const FunctionMockerBase* mocker, - const ArgumentTuple& args, - ::std::ostream* what, - ::std::ostream* why) - GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { + const Action* GetActionForArguments(const FunctionMocker* mocker, + const ArgumentTuple& args, + ::std::ostream* what, + ::std::ostream* why) + GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); if (IsSaturated()) { // We have an excessive call. @@ -1233,7 +1228,7 @@ class TypedExpectation : public ExpectationBase { // All the fields below won't change once the EXPECT_CALL() // statement finishes. - FunctionMockerBase* const owner_; + FunctionMocker* const owner_; ArgumentMatcherTuple matchers_; Matcher extra_matcher_; Action repeated_action_; @@ -1265,7 +1260,7 @@ class MockSpec { // Constructs a MockSpec object, given the function mocker object // that the spec is associated with. - MockSpec(internal::FunctionMockerBase* function_mocker, + MockSpec(internal::FunctionMocker* function_mocker, const ArgumentMatcherTuple& matchers) : function_mocker_(function_mocker), matchers_(matchers) {} @@ -1301,7 +1296,7 @@ class MockSpec { friend class internal::FunctionMocker; // The function mocker that owns this spec. - internal::FunctionMockerBase* const function_mocker_; + internal::FunctionMocker* const function_mocker_; // The argument matchers specified in the spec. ArgumentMatcherTuple matchers_; @@ -1402,7 +1397,7 @@ class ActionResultHolder : public UntypedActionResultHolderBase { // result in a new-ed ActionResultHolder. template static ActionResultHolder* PerformDefaultAction( - const FunctionMockerBase* func_mocker, + const FunctionMocker* func_mocker, typename Function::ArgumentTuple&& args, const std::string& call_description) { return new ActionResultHolder(Wrapper(func_mocker->PerformDefaultAction( @@ -1442,7 +1437,7 @@ class ActionResultHolder : public UntypedActionResultHolderBase { // of an empty ActionResultHolder*. template static ActionResultHolder* PerformDefaultAction( - const FunctionMockerBase* func_mocker, + const FunctionMocker* func_mocker, typename Function::ArgumentTuple&& args, const std::string& call_description) { func_mocker->PerformDefaultAction(std::move(args), call_description); @@ -1463,22 +1458,39 @@ class ActionResultHolder : public UntypedActionResultHolderBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionResultHolder); }; -// The base of the function mocker class for the given function type. -// We put the methods in this class instead of its child to avoid code -// bloat. template -class FunctionMockerBase : public UntypedFunctionMockerBase { +class FunctionMocker; + +template +class FunctionMocker : public UntypedFunctionMockerBase { + using F = R(Args...); + public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; + using Result = R; + using ArgumentTuple = std::tuple; + using ArgumentMatcherTuple = std::tuple...>; - FunctionMockerBase() {} + FunctionMocker() {} + + // There is no generally useful and implementable semantics of + // copying a mock object, so copying a mock is usually a user error. + // Thus we disallow copying function mockers. If the user really + // wants to copy a mock object, they should implement their own copy + // operation, for example: + // + // class MockFoo : public Foo { + // public: + // // Defines a copy constructor explicitly. + // MockFoo(const MockFoo& src) {} + // ... + // }; + FunctionMocker(const FunctionMocker&) = delete; + FunctionMocker& operator=(const FunctionMocker&) = delete; // The destructor verifies that all expectations on this mock // function have been satisfied. If not, it will report Google Test // non-fatal failures for the violations. - virtual ~FunctionMockerBase() + virtual ~FunctionMocker() GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { MutexLock l(&g_gmock_mutex); VerifyAndClearExpectationsLocked(); @@ -1509,7 +1521,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // mutable state of this object, and thus can be called concurrently // without locking. // L = * - Result PerformDefaultAction(typename Function::ArgumentTuple&& args, + Result PerformDefaultAction(ArgumentTuple&& args, const std::string& call_description) const { const OnCallSpec* const spec = this->FindOnCallSpec(args); @@ -1584,25 +1596,26 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { g_gmock_mutex.Lock(); } - protected: - template - friend class MockSpec; - - typedef ActionResultHolder ResultHolder; - // Returns the result of invoking this mock function with the given // arguments. This function can be safely called from multiple // threads concurrently. - Result InvokeWith(typename Function::ArgumentTuple&& args) - GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { - // const_cast is required since in C++98 we still pass ArgumentTuple around - // by const& instead of rvalue reference. - void* untyped_args = const_cast(static_cast(&args)); - std::unique_ptr holder( - DownCast_(this->UntypedInvokeWith(untyped_args))); + Result Invoke(Args... args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { + ArgumentTuple tuple(std::forward(args)...); + std::unique_ptr holder(DownCast_( + this->UntypedInvokeWith(static_cast(&tuple)))); return holder->Unwrap(); } + MockSpec With(Matcher... m) { + return MockSpec(this, ::std::make_tuple(std::move(m)...)); + } + + protected: + template + friend class MockSpec; + + typedef ActionResultHolder ResultHolder; + // Adds and returns a default action spec for this mock function. OnCallSpec& AddNewOnCallSpec( const char* file, int line, @@ -1779,36 +1792,98 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { expectation->DescribeCallCountTo(why); } } - - // There is no generally useful and implementable semantics of - // copying a mock object, so copying a mock is usually a user error. - // Thus we disallow copying function mockers. If the user really - // wants to copy a mock object, they should implement their own copy - // operation, for example: - // - // class MockFoo : public Foo { - // public: - // // Defines a copy constructor explicitly. - // MockFoo(const MockFoo& src) {} - // ... - // }; - GTEST_DISALLOW_COPY_AND_ASSIGN_(FunctionMockerBase); -}; // class FunctionMockerBase +}; // class FunctionMocker GTEST_DISABLE_MSC_WARNINGS_POP_() // 4355 -// Implements methods of FunctionMockerBase. - -// Verifies that all expectations on this mock function have been -// satisfied. Reports one or more Google Test non-fatal failures and -// returns false if not. - // Reports an uninteresting call (whose description is in msg) in the // manner specified by 'reaction'. void ReportUninterestingCall(CallReaction reaction, const std::string& msg); } // namespace internal +// A MockFunction class has one mock method whose type is F. It is +// useful when you just want your test code to emit some messages and +// have Google Mock verify the right messages are sent (and perhaps at +// the right times). For example, if you are exercising code: +// +// Foo(1); +// Foo(2); +// Foo(3); +// +// and want to verify that Foo(1) and Foo(3) both invoke +// mock.Bar("a"), but Foo(2) doesn't invoke anything, you can write: +// +// TEST(FooTest, InvokesBarCorrectly) { +// MyMock mock; +// MockFunction check; +// { +// InSequence s; +// +// EXPECT_CALL(mock, Bar("a")); +// EXPECT_CALL(check, Call("1")); +// EXPECT_CALL(check, Call("2")); +// EXPECT_CALL(mock, Bar("a")); +// } +// Foo(1); +// check.Call("1"); +// Foo(2); +// check.Call("2"); +// Foo(3); +// } +// +// The expectation spec says that the first Bar("a") must happen +// before check point "1", the second Bar("a") must happen after check +// point "2", and nothing should happen between the two check +// points. The explicit check points make it easy to tell which +// Bar("a") is called by which call to Foo(). +// +// MockFunction can also be used to exercise code that accepts +// std::function callbacks. To do so, use AsStdFunction() method +// to create std::function proxy forwarding to original object's Call. +// Example: +// +// TEST(FooTest, RunsCallbackWithBarArgument) { +// MockFunction callback; +// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1)); +// Foo(callback.AsStdFunction()); +// } +template +class MockFunction; + +template +class MockFunction { + public: + MockFunction() {} + MockFunction(const MockFunction&) = delete; + MockFunction& operator=(const MockFunction&) = delete; + + std::function AsStdFunction() { + return [this](Args... args) -> R { + return this->Call(std::forward(args)...); + }; + } + + // Implementation detail: the expansion of the MOCK_METHOD macro. + R Call(Args... args) { + mock_.SetOwnerAndName(this, "Call"); + return mock_.Invoke(std::forward(args)...); + } + + internal::MockSpec gmock_Call(Matcher... m) { + mock_.RegisterOwner(this); + return mock_.With(std::move(m)...); + } + + internal::MockSpec gmock_Call(const internal::WithoutMatchers&, + R (*)(Args...)) { + return this->gmock_Call(::testing::A()...); + } + + private: + mutable internal::FunctionMocker mock_; +}; + // The style guide prohibits "using" statements in a namespace scope // inside a header file. However, the MockSpec class template is // meant to be defined in the ::testing namespace. The following line -- cgit v1.2.3