aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Badura <adam.f.badura@gmail.com>2019-07-11 10:20:21 +0200
committerAdam Badura <adam.f.badura@gmail.com>2020-03-18 01:11:30 +0100
commit53740ebc21d54f537f42fc565b0501e690c90dc4 (patch)
tree6cdd9534fd94cbb113b083ba8bcd742c46fec75c
parente41f31f2af3a713e8652d1e091a13bed22781ec3 (diff)
downloadgoogletest-53740ebc21d54f537f42fc565b0501e690c90dc4.tar.gz
googletest-53740ebc21d54f537f42fc565b0501e690c90dc4.tar.bz2
googletest-53740ebc21d54f537f42fc565b0501e690c90dc4.zip
Add support for std::function in MockFunction (#2277)
-rw-r--r--googlemock/include/gmock/gmock-spec-builders.h132
-rw-r--r--googlemock/test/gmock-function-mocker_test.cc21
2 files changed, 113 insertions, 40 deletions
diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h
index 718c9484..30a75ce3 100644
--- a/googlemock/include/gmock/gmock-spec-builders.h
+++ b/googlemock/include/gmock/gmock-spec-builders.h
@@ -1786,10 +1786,80 @@ void ReportUninterestingCall(CallReaction reaction, const std::string& msg);
} // namespace internal
-// A MockFunction<F> 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:
+namespace internal {
+
+template <typename F>
+class MockFunction;
+
+template <typename R, typename... Args>
+class MockFunction<R(Args...)> {
+ public:
+ MockFunction(const MockFunction&) = delete;
+ MockFunction& operator=(const MockFunction&) = delete;
+
+ std::function<R(Args...)> AsStdFunction() {
+ return [this](Args... args) -> R {
+ return this->Call(std::forward<Args>(args)...);
+ };
+ }
+
+ // Implementation detail: the expansion of the MOCK_METHOD macro.
+ R Call(Args... args) {
+ mock_.SetOwnerAndName(this, "Call");
+ return mock_.Invoke(std::forward<Args>(args)...);
+ }
+
+ MockSpec<R(Args...)> gmock_Call(Matcher<Args>... m) {
+ mock_.RegisterOwner(this);
+ return mock_.With(std::move(m)...);
+ }
+
+ MockSpec<R(Args...)> gmock_Call(const WithoutMatchers&,
+ R (*)(Args...)) {
+ return this->gmock_Call(::testing::A<Args>()...);
+ }
+
+ protected:
+ MockFunction() = default;
+ ~MockFunction() = default;
+
+ private:
+ FunctionMocker<R(Args...)> mock_;
+};
+
+/*
+The SignatureOf<F> struct is a meta-function returning function signature
+corresponding to the provided F argument.
+
+It makes use of MockFunction easier by allowing it to accept more F arguments
+than just function signatures.
+
+Specializations provided here cover only a signature type itself and
+std::function. However, if need be it can be easily extended to cover also other
+types (like for example boost::function).
+*/
+
+template <typename F>
+struct SignatureOf;
+
+template <typename R, typename... Args>
+struct SignatureOf<R(Args...)> {
+ using type = R(Args...);
+};
+
+template <typename F>
+struct SignatureOf<std::function<F>> : SignatureOf<F> {};
+
+template <typename F>
+using SignatureOfT = typename SignatureOf<F>::type;
+
+} // namespace internal
+
+// A MockFunction<F> type has one mock method whose type is
+// internal::SignatureOfT<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);
@@ -1823,49 +1893,33 @@ void ReportUninterestingCall(CallReaction reaction, const std::string& msg);
// Bar("a") is called by which call to Foo().
//
// MockFunction<F> can also be used to exercise code that accepts
-// std::function<F> callbacks. To do so, use AsStdFunction() method
-// to create std::function proxy forwarding to original object's Call.
-// Example:
+// std::function<internal::SignatureOfT<F>> callbacks. To do so, use
+// AsStdFunction() method to create std::function proxy forwarding to
+// original object's Call. Example:
//
// TEST(FooTest, RunsCallbackWithBarArgument) {
// MockFunction<int(string)> callback;
// EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1));
// Foo(callback.AsStdFunction());
// }
+//
+// The internal::SignatureOfT<F> indirection allows to use other types
+// than just function signature type. This is typically useful when
+// providing a mock for a predefined std::function type. Example:
+//
+// using FilterPredicate = std::function<bool(string)>;
+// void MyFilterAlgorithm(FilterPredicate predicate);
+//
+// TEST(FooTest, FilterPredicateAlwaysAccepts) {
+// MockFunction<FilterPredicate> predicateMock;
+// EXPECT_CALL(predicateMock, Call(_)).WillRepeatedly(Return(true));
+// MyFilterAlgorithm(predicateMock.AsStdFunction());
+// }
template <typename F>
-class MockFunction;
-
-template <typename R, typename... Args>
-class MockFunction<R(Args...)> {
+class MockFunction : public internal::MockFunction<internal::SignatureOfT<F>> {
+ using Base = internal::MockFunction<internal::SignatureOfT<F>>;
public:
- MockFunction() {}
- MockFunction(const MockFunction&) = delete;
- MockFunction& operator=(const MockFunction&) = delete;
-
- std::function<R(Args...)> AsStdFunction() {
- return [this](Args... args) -> R {
- return this->Call(std::forward<Args>(args)...);
- };
- }
-
- // Implementation detail: the expansion of the MOCK_METHOD macro.
- R Call(Args... args) {
- mock_.SetOwnerAndName(this, "Call");
- return mock_.Invoke(std::forward<Args>(args)...);
- }
-
- internal::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...)) {
- return this->gmock_Call(::testing::A<Args>()...);
- }
-
- private:
- internal::FunctionMocker<R(Args...)> mock_;
+ using Base::Base;
};
// The style guide prohibits "using" statements in a namespace scope
diff --git a/googlemock/test/gmock-function-mocker_test.cc b/googlemock/test/gmock-function-mocker_test.cc
index 164c6b47..920b097f 100644
--- a/googlemock/test/gmock-function-mocker_test.cc
+++ b/googlemock/test/gmock-function-mocker_test.cc
@@ -40,6 +40,7 @@
# include <objbase.h>
#endif // GTEST_OS_WINDOWS
+#include <functional>
#include <map>
#include <string>
#include <type_traits>
@@ -802,12 +803,30 @@ using MockMethodMockFunctionSignatureTypes = Types<
>;
TYPED_TEST_SUITE(MockMethodMockFunctionSignatureTest, MockMethodMockFunctionSignatureTypes);
-TYPED_TEST(MockMethodMockFunctionSignatureTest, IsMockFunctionTemplateArgumentDeduced) {
+TYPED_TEST(MockMethodMockFunctionSignatureTest, IsMockFunctionTemplateArgumentDeducedForRawSignature) {
using Argument = TypeParam;
MockFunction<Argument> foo;
EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<Argument>(foo));
}
+TYPED_TEST(MockMethodMockFunctionSignatureTest, IsMockFunctionTemplateArgumentDeducedForStdFunction) {
+ using Argument = std::function<TypeParam>;
+ MockFunction<Argument> foo;
+ EXPECT_TRUE(IsMockFunctionTemplateArgumentDeducedTo<Argument>(foo));
+}
+
+TYPED_TEST(MockMethodMockFunctionSignatureTest, IsMockFunctionCallMethodSignatureTheSameForRawSignatureAndStdFunction) {
+ using ForRawSignature = decltype(&MockFunction<TypeParam>::Call);
+ using ForStdFunction = decltype(&MockFunction<std::function<TypeParam>>::Call);
+ EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value));
+}
+
+TYPED_TEST(MockMethodMockFunctionSignatureTest, IsMockFunctionAsStdFunctionMethodSignatureTheSameForRawSignatureAndStdFunction) {
+ using ForRawSignature = decltype(&MockFunction<TypeParam>::AsStdFunction);
+ using ForStdFunction = decltype(&MockFunction<std::function<TypeParam>>::AsStdFunction);
+ EXPECT_TRUE((std::is_same<ForRawSignature, ForStdFunction>::value));
+}
+
struct MockMethodSizes0 {
MOCK_METHOD(void, func, ());