diff options
Diffstat (limited to 'googlemock')
-rw-r--r-- | googlemock/docs/cook_book.md | 38 | ||||
-rw-r--r-- | googlemock/docs/for_dummies.md | 2 | ||||
-rw-r--r-- | googlemock/include/gmock/gmock-actions.h | 39 | ||||
-rw-r--r-- | googlemock/include/gmock/gmock-matchers.h | 13 | ||||
-rw-r--r-- | googlemock/include/gmock/gmock-spec-builders.h | 130 | ||||
-rw-r--r-- | googlemock/test/BUILD.bazel | 2 | ||||
-rw-r--r-- | googlemock/test/gmock-actions_test.cc | 15 | ||||
-rw-r--r-- | googlemock/test/gmock-function-mocker_test.cc | 51 | ||||
-rw-r--r-- | googlemock/test/gmock-matchers_test.cc | 17 |
9 files changed, 230 insertions, 77 deletions
diff --git a/googlemock/docs/cook_book.md b/googlemock/docs/cook_book.md index a493521..51eb94a 100644 --- a/googlemock/docs/cook_book.md +++ b/googlemock/docs/cook_book.md @@ -421,7 +421,7 @@ sadly they are side effects of C++'s limitations): `NiceMock<StrictMock<MockFoo> >`) is **not** supported. 2. `NiceMock<MockFoo>` and `StrictMock<MockFoo>` may not work correctly if the destructor of `MockFoo` is not virtual. We would like to fix this, but it - requires cleaning up existing tests. http://b/28934720 tracks the issue. + requires cleaning up existing tests. 3. During the constructor or destructor of `MockFoo`, the mock object is *not* nice or strict. This may cause surprises if the constructor or destructor calls a mock method on `this` object. (This behavior, however, is consistent @@ -2174,7 +2174,7 @@ own precedence order distinct from the `ON_CALL` precedence order. ### Using Functions/Methods/Functors/Lambdas as Actions {#FunctionsAsActions} If the built-in actions don't suit you, you can use an existing callable -(function, `std::function`, method, functor, lambda as an action. +(function, `std::function`, method, functor, lambda) as an action. <!-- GOOGLETEST_CM0024 DO NOT DELETE --> @@ -2203,6 +2203,7 @@ class Helper { .WillRepeatedly(Invoke(NewPermanentCallback(Sum3, 1))); EXPECT_CALL(foo, ComplexJob(_)) .WillOnce(Invoke(&helper, &Helper::ComplexJob)) + .WillOnce([] { return true; }) .WillRepeatedly([](int x) { return x > 0; }); foo.Sum(5, 6); // Invokes CalculateSum(5, 6). @@ -2212,11 +2213,11 @@ class Helper { ``` The only requirement is that the type of the function, etc must be *compatible* -with the signature of the mock function, meaning that the latter's arguments can -be implicitly converted to the corresponding arguments of the former, and the -former's return type can be implicitly converted to that of the latter. So, you -can invoke something whose type is *not* exactly the same as the mock function, -as long as it's safe to do so - nice, huh? +with the signature of the mock function, meaning that the latter's arguments (if +it takes any) can be implicitly converted to the corresponding arguments of the +former, and the former's return type can be implicitly converted to that of the +latter. So, you can invoke something whose type is *not* exactly the same as the +mock function, as long as it's safe to do so - nice, huh? **`Note:`{.escaped}** @@ -2267,19 +2268,20 @@ TEST_F(FooTest, Test) { ### Invoking a Function/Method/Functor/Lambda/Callback Without Arguments -`Invoke()` is very useful for doing actions that are more complex. It passes the -mock function's arguments to the function, etc being invoked such that the -callee has the full context of the call to work with. If the invoked function is -not interested in some or all of the arguments, it can simply ignore them. +`Invoke()` passes the mock function's arguments to the function, etc being +invoked such that the callee has the full context of the call to work with. If +the invoked function is not interested in some or all of the arguments, it can +simply ignore them. Yet, a common pattern is that a test author wants to invoke a function without -the arguments of the mock function. `Invoke()` allows her to do that using a -wrapper function that throws away the arguments before invoking an underlining -nullary function. Needless to say, this can be tedious and obscures the intent -of the test. +the arguments of the mock function. She could do that using a wrapper function +that throws away the arguments before invoking an underlining nullary function. +Needless to say, this can be tedious and obscures the intent of the test. -`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except that it -doesn't pass the mock function's arguments to the callee. Here's an example: +There are two solutions to this problem. First, you can pass any callable of +zero args as an action. Alternatively, use `InvokeWithoutArgs()`, which is like +`Invoke()` except that it doesn't pass the mock function's arguments to the +callee. Here's an example of each: ```cpp using ::testing::_; @@ -2296,7 +2298,7 @@ bool Job2(int n, char c) { ... } ... MockFoo foo; EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(InvokeWithoutArgs(Job1)) + .WillOnce([] { Job1(); }); .WillOnce(InvokeWithoutArgs(NewPermanentCallback(Job2, 5, 'a'))); foo.ComplexJob(10); // Invokes Job1(). diff --git a/googlemock/docs/for_dummies.md b/googlemock/docs/for_dummies.md index 93cf06f..327e6cc 100644 --- a/googlemock/docs/for_dummies.md +++ b/googlemock/docs/for_dummies.md @@ -374,7 +374,7 @@ convenient way of saying "any value". In the above examples, `100` and `50` are also matchers; implicitly, they are the same as `Eq(100)` and `Eq(50)`, which specify that the argument must be equal (using `operator==`) to the matcher argument. There are many -[built-in matchers](#MatcherList) for common types (as well as +[built-in matchers](cheat_sheet.md#MatcherList) for common types (as well as [custom matchers](cook_book.md#NewMatchers)); for example: ```cpp diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index e46bcaa..615651b 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -263,6 +263,10 @@ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); #undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ +// Simple two-arg form of std::disjunction. +template <typename P, typename Q> +using disjunction = typename ::std::conditional<P::value, P, Q>::type; + } // namespace internal // When an unexpected function call is encountered, Google Mock will @@ -456,9 +460,15 @@ class Action { // This cannot take std::function directly, because then Action would not be // directly constructible from lambda (it would require two conversions). template <typename G, - typename = typename ::std::enable_if< - ::std::is_constructible<::std::function<F>, G>::value>::type> - Action(G&& fun) : fun_(::std::forward<G>(fun)) {} // NOLINT + typename IsCompatibleFunctor = + ::std::is_constructible<::std::function<F>, G>, + typename IsNoArgsFunctor = + ::std::is_constructible<::std::function<Result()>, G>, + typename = typename ::std::enable_if<internal::disjunction< + IsCompatibleFunctor, IsNoArgsFunctor>::value>::type> + Action(G&& fun) { // NOLINT + Init(::std::forward<G>(fun), IsCompatibleFunctor()); + } // Constructs an Action from its implementation. explicit Action(ActionInterface<F>* impl) @@ -490,6 +500,26 @@ class Action { template <typename G> friend class Action; + template <typename G> + void Init(G&& g, ::std::true_type) { + fun_ = ::std::forward<G>(g); + } + + template <typename G> + void Init(G&& g, ::std::false_type) { + fun_ = IgnoreArgs<typename ::std::decay<G>::type>{::std::forward<G>(g)}; + } + + template <typename FunctionImpl> + struct IgnoreArgs { + template <typename... Args> + Result operator()(const Args&...) const { + return function_impl(); + } + + FunctionImpl function_impl; + }; + // fun_ is an empty function if and only if this is the DoDefault() action. ::std::function<F> fun_; }; @@ -940,7 +970,8 @@ struct InvokeMethodWithoutArgsAction { Class* const obj_ptr; const MethodPtr method_ptr; - using ReturnType = typename std::result_of<MethodPtr(Class*)>::type; + using ReturnType = + decltype((std::declval<Class*>()->*std::declval<MethodPtr>())()); template <typename... Args> ReturnType operator()(const Args&...) const { diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 4b6ac56..fe88a7c 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -424,7 +424,14 @@ class MatcherCastImpl<T, Matcher<U> > { !std::is_base_of<FromType, ToType>::value, "Can't implicitly convert from <base> to <derived>"); - return source_matcher_.MatchAndExplain(static_cast<U>(x), listener); + // Do the cast to `U` explicitly if necessary. + // Otherwise, let implicit conversions do the trick. + using CastType = + typename std::conditional<std::is_convertible<T&, const U&>::value, + T&, U>::type; + + return source_matcher_.MatchAndExplain(static_cast<CastType>(x), + listener); } void DescribeTo(::std::ostream* os) const override { @@ -524,8 +531,8 @@ inline Matcher<T> SafeMatcherCast(const M& polymorphic_matcher_or_value) { template <typename T, typename U> inline Matcher<T> SafeMatcherCast(const Matcher<U>& matcher) { // Enforce that T can be implicitly converted to U. - GTEST_COMPILE_ASSERT_((std::is_convertible<T, U>::value), - "T must be implicitly convertible to U"); + static_assert(std::is_convertible<const T&, const U&>::value, + "T must be implicitly convertible to U"); // Enforce that we are not converting a non-reference type T to a reference // type U. GTEST_COMPILE_ASSERT_( diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h index 718c948..4b5fc66 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/BUILD.bazel b/googlemock/test/BUILD.bazel index da95ed5..4aa9a75 100644 --- a/googlemock/test/BUILD.bazel +++ b/googlemock/test/BUILD.bazel @@ -28,8 +28,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -# Author: misterg@google.com (Gennadiy Civil) -# # Bazel Build for Google C++ Testing Framework(Google Test)-googlemock load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test") diff --git a/googlemock/test/gmock-actions_test.cc b/googlemock/test/gmock-actions_test.cc index 58a2d35..d1229ac 100644 --- a/googlemock/test/gmock-actions_test.cc +++ b/googlemock/test/gmock-actions_test.cc @@ -1470,8 +1470,19 @@ TEST(FunctorActionTest, TypeConversion) { EXPECT_EQ(1, s2.Perform(std::make_tuple("hello"))); // Also between the lambda and the action itself. - const Action<bool(std::string)> x = [](Unused) { return 42; }; - EXPECT_TRUE(x.Perform(std::make_tuple("hello"))); + const Action<bool(std::string)> x1 = [](Unused) { return 42; }; + const Action<bool(std::string)> x2 = [] { return 42; }; + EXPECT_TRUE(x1.Perform(std::make_tuple("hello"))); + EXPECT_TRUE(x2.Perform(std::make_tuple("hello"))); + + // Ensure decay occurs where required. + std::function<int()> f = [] { return 7; }; + Action<int(int)> d = f; + f = nullptr; + EXPECT_EQ(7, d.Perform(std::make_tuple(1))); + + // Ensure creation of an empty action succeeds. + Action<void(int)>(nullptr); } TEST(FunctorActionTest, UnusedArguments) { diff --git a/googlemock/test/gmock-function-mocker_test.cc b/googlemock/test/gmock-function-mocker_test.cc index 019e3cb..94aaafb 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, ()); diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc index c1949e6..186d8aa 100644 --- a/googlemock/test/gmock-matchers_test.cc +++ b/googlemock/test/gmock-matchers_test.cc @@ -765,10 +765,11 @@ TEST(SafeMatcherCastTest, FromConstReferenceToReference) { // Tests that MatcherCast<const T&>(m) works when m is a Matcher<T>. TEST(SafeMatcherCastTest, FromNonReferenceToConstReference) { - Matcher<int> m1 = Eq(0); - Matcher<const int&> m2 = SafeMatcherCast<const int&>(m1); - EXPECT_TRUE(m2.Matches(0)); - EXPECT_FALSE(m2.Matches(1)); + Matcher<std::unique_ptr<int>> m1 = IsNull(); + Matcher<const std::unique_ptr<int>&> m2 = + SafeMatcherCast<const std::unique_ptr<int>&>(m1); + EXPECT_TRUE(m2.Matches(std::unique_ptr<int>())); + EXPECT_FALSE(m2.Matches(std::unique_ptr<int>(new int))); } // Tests that SafeMatcherCast<T&>(m) works when m is a Matcher<T>. @@ -4725,20 +4726,18 @@ TEST(SizeIsTest, ExplainsResult) { Matcher<vector<int> > m1 = SizeIs(2); Matcher<vector<int> > m2 = SizeIs(Lt(2u)); Matcher<vector<int> > m3 = SizeIs(AnyOf(0, 3)); - Matcher<vector<int> > m4 = SizeIs(GreaterThan(1)); + Matcher<vector<int> > m4 = SizeIs(Gt(1u)); vector<int> container; EXPECT_EQ("whose size 0 doesn't match", Explain(m1, container)); EXPECT_EQ("whose size 0 matches", Explain(m2, container)); EXPECT_EQ("whose size 0 matches", Explain(m3, container)); - EXPECT_EQ("whose size 0 doesn't match, which is 1 less than 1", - Explain(m4, container)); + EXPECT_EQ("whose size 0 doesn't match", Explain(m4, container)); container.push_back(0); container.push_back(0); EXPECT_EQ("whose size 2 matches", Explain(m1, container)); EXPECT_EQ("whose size 2 doesn't match", Explain(m2, container)); EXPECT_EQ("whose size 2 doesn't match", Explain(m3, container)); - EXPECT_EQ("whose size 2 matches, which is 1 more than 1", - Explain(m4, container)); + EXPECT_EQ("whose size 2 matches", Explain(m4, container)); } #if GTEST_HAS_TYPED_TEST |