-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
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.