Skip to content

Add MockFunction support for std::function #2277

@adambadura

Description

@adambadura

MockFunction requires function signature R(Args...) as its template argument. This makes it difficult to use it with std::function hidden under some type name. std::function doesn't provide any member type to allow to (safely and easily) reflect its own arguments (the signature).

The problem shows when we want to refer to std::function through its type name like:

using my_callback = std::function<bool(int)>;

Now, we cannot do ::testing::MockFunction<my_callback>. We have to do ::testing::MockFunction<bool(int)>, which is a maintenance issue requiring us to repeat the type definition.

Below is my proposal to add the support:

diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h
index 1f261bd2..47c34980 100644
--- a/googlemock/include/gmock/gmock-spec-builders.h
+++ b/googlemock/include/gmock/gmock-spec-builders.h
@@ -1836,6 +1836,24 @@ void ReportUninterestingCall(CallReaction reaction, const std::string& msg);
 //   EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1));
 //   Foo(callback.AsStdFunction());
 // }
+template <typename F>
+struct SignatureOf;
+
+template <typename R, typename... Args>
+struct SignatureOf<R(Args...)> {
+ using type = R(Args...);
+};
+
+template <typename R, typename... Args>
+struct SignatureOf<std::function<R(Args...)>> {
+ using type = R(Args...);
+};
+
+template <typename F>
+using SignatureOfT = typename SignatureOf<F>::type;
+
+namespace internal {
+
 template <typename F>
 class MockFunction;
 
@@ -1858,20 +1876,25 @@ class MockFunction<R(Args...)> {
     return mock_.Invoke(std::forward<Args>(args)...);
   }
 
-  internal::MockSpec<R(Args...)> gmock_Call(Matcher<Args>... m) {
+  MockSpec<R(Args...)> gmock_Call(Matcher<Args>... m) {
     mock_.RegisterOwner(this);
     return mock_.With(std::move(m)...);
   }
 
-  internal::MockSpec<R(Args...)> gmock_Call(const internal::WithoutMatchers&,
-                                            R (*)(Args...)) {
+  MockSpec<R(Args...)> gmock_Call(const WithoutMatchers&,
+                                  R (*)(Args...)) {
     return this->gmock_Call(::testing::A<Args>()...);
   }
 
  private:
-  mutable internal::FunctionMocker<R(Args...)> mock_;
+  mutable FunctionMocker<R(Args...)> mock_;
 };
 
+}  // namespace internal
+
+template <typename F>
+using MockFunction = internal::MockFunction<SignatureOfT<F>>;
+
 // 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

The solution is based on the introduction of SignatureOf meta-function which translates types provided to MetaFunction into function signature. This allows to support std::function and could be later easily extended further, including user extending it with user-types. (boost::function and folly::Function being good examples of extension candidates.)

The meta-function based solution as compared to a more classic approach of specialization also avoids the choice between duplicating code or using inheritance, which then creates an issue of virtual destructor.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions