aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiaoyi Zhang <zhangxy@google.com>2020-03-24 17:32:16 -0400
committerXiaoyi Zhang <zhangxy@google.com>2020-03-24 17:32:16 -0400
commit67cc66080d64e3fa5124fe57ed0cf15e2cecfdeb (patch)
treebc91e4f388888fefd64a89403edd6cb418e3b1ef
parent1ced315a483f4ecac21893ce6ceeb502afb82eff (diff)
parent53740ebc21d54f537f42fc565b0501e690c90dc4 (diff)
downloadgoogletest-67cc66080d64e3fa5124fe57ed0cf15e2cecfdeb.tar.gz
googletest-67cc66080d64e3fa5124fe57ed0cf15e2cecfdeb.tar.bz2
googletest-67cc66080d64e3fa5124fe57ed0cf15e2cecfdeb.zip
Merge pull request #2350 from adambadura:MockFunctionFromStdFunction
PiperOrigin-RevId: 302677275
-rw-r--r--googlemock/include/gmock/gmock-spec-builders.h130
-rw-r--r--googlemock/test/gmock-function-mocker_test.cc51
2 files changed, 143 insertions, 38 deletions
diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h
index 718c9484..4b5fc661 100644
--- a/googlemock/include/gmock/gmock-spec-builders.h
+++ b/googlemock/include/gmock/gmock-spec-builders.h
@@ -1786,10 +1786,79 @@ 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 +1892,34 @@ 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;
+class MockFunction : public internal::MockFunction<internal::SignatureOfT<F>> {
+ using Base = internal::MockFunction<internal::SignatureOfT<F>>;
-template <typename R, typename... Args>
-class MockFunction<R(Args...)> {
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 019e3cb9..94aaafba 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>
@@ -778,6 +779,56 @@ TEST(MockMethodMockFunctionTest, AsStdFunctionWithReferenceParameter) {
EXPECT_EQ(-1, call(foo.AsStdFunction(), i));
}
+namespace {
+
+template <typename Expected, typename F>
+static constexpr bool IsMockFunctionTemplateArgumentDeducedTo(
+ const MockFunction<F>&) {
+ return std::is_same<F, Expected>::value;
+}
+
+} // namespace
+
+template <typename F>
+class MockMethodMockFunctionSignatureTest : public Test {};
+
+using MockMethodMockFunctionSignatureTypes =
+ Types<void(), int(), void(int), int(int), int(bool, int),
+ int(bool, char, int, int, int, int, int, char, int, bool)>;
+TYPED_TEST_SUITE(MockMethodMockFunctionSignatureTest,
+ MockMethodMockFunctionSignatureTypes);
+
+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, ());