Googletest export
Allow construction of an Action from a callable of zero args Action already allows construction from a callable with the same args as the mocked function, without needing to wrap the callable in Invoke. However, if you don't care about the arguments to the mocked function you need to either accept all of them or wrap your callable in InvokeWithoutArgs. This change makes both of those unnecessary, since it allows you to pass a no-args callable to Action directly. PiperOrigin-RevId: 296117034
This commit is contained in:
parent
23b2a3b1cf
commit
fd538161f4
|
@ -2174,7 +2174,7 @@ own precedence order distinct from the `ON_CALL` precedence order.
|
||||||
### Using Functions/Methods/Functors/Lambdas as Actions {#FunctionsAsActions}
|
### Using Functions/Methods/Functors/Lambdas as Actions {#FunctionsAsActions}
|
||||||
|
|
||||||
If the built-in actions don't suit you, you can use an existing callable
|
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 -->
|
<!-- GOOGLETEST_CM0024 DO NOT DELETE -->
|
||||||
|
|
||||||
|
@ -2203,6 +2203,7 @@ class Helper {
|
||||||
.WillRepeatedly(Invoke(NewPermanentCallback(Sum3, 1)));
|
.WillRepeatedly(Invoke(NewPermanentCallback(Sum3, 1)));
|
||||||
EXPECT_CALL(foo, ComplexJob(_))
|
EXPECT_CALL(foo, ComplexJob(_))
|
||||||
.WillOnce(Invoke(&helper, &Helper::ComplexJob))
|
.WillOnce(Invoke(&helper, &Helper::ComplexJob))
|
||||||
|
.WillOnce([] { return true; })
|
||||||
.WillRepeatedly([](int x) { return x > 0; });
|
.WillRepeatedly([](int x) { return x > 0; });
|
||||||
|
|
||||||
foo.Sum(5, 6); // Invokes CalculateSum(5, 6).
|
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*
|
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
|
with the signature of the mock function, meaning that the latter's arguments (if
|
||||||
be implicitly converted to the corresponding arguments of the former, and the
|
it takes any) can be implicitly converted to the corresponding arguments of the
|
||||||
former's return type can be implicitly converted to that of the latter. So, you
|
former, and the former's return type can be implicitly converted to that of the
|
||||||
can invoke something whose type is *not* exactly the same as the mock function,
|
latter. So, you can invoke something whose type is *not* exactly the same as the
|
||||||
as long as it's safe to do so - nice, huh?
|
mock function, as long as it's safe to do so - nice, huh?
|
||||||
|
|
||||||
**`Note:`{.escaped}**
|
**`Note:`{.escaped}**
|
||||||
|
|
||||||
|
@ -2267,19 +2268,20 @@ TEST_F(FooTest, Test) {
|
||||||
|
|
||||||
### Invoking a Function/Method/Functor/Lambda/Callback Without Arguments
|
### Invoking a Function/Method/Functor/Lambda/Callback Without Arguments
|
||||||
|
|
||||||
`Invoke()` is very useful for doing actions that are more complex. It passes the
|
`Invoke()` passes the mock function's arguments to the function, etc being
|
||||||
mock function's arguments to the function, etc being invoked such that the
|
invoked such that the callee has the full context of the call to work with. If
|
||||||
callee has the full context of the call to work with. If the invoked function is
|
the invoked function is not interested in some or all of the arguments, it can
|
||||||
not interested in some or all of the arguments, it can simply ignore them.
|
simply ignore them.
|
||||||
|
|
||||||
Yet, a common pattern is that a test author wants to invoke a function without
|
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
|
the arguments of the mock function. She could do that using a wrapper function
|
||||||
wrapper function that throws away the arguments before invoking an underlining
|
that throws away the arguments before invoking an underlining nullary function.
|
||||||
nullary function. Needless to say, this can be tedious and obscures the intent
|
Needless to say, this can be tedious and obscures the intent of the test.
|
||||||
of the test.
|
|
||||||
|
|
||||||
`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except that it
|
There are two solutions to this problem. First, you can pass any callable of
|
||||||
doesn't pass the mock function's arguments to the callee. Here's an example:
|
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
|
```cpp
|
||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
|
@ -2296,7 +2298,7 @@ bool Job2(int n, char c) { ... }
|
||||||
...
|
...
|
||||||
MockFoo foo;
|
MockFoo foo;
|
||||||
EXPECT_CALL(foo, ComplexJob(_))
|
EXPECT_CALL(foo, ComplexJob(_))
|
||||||
.WillOnce(InvokeWithoutArgs(Job1))
|
.WillOnce([] { Job1(); });
|
||||||
.WillOnce(InvokeWithoutArgs(NewPermanentCallback(Job2, 5, 'a')));
|
.WillOnce(InvokeWithoutArgs(NewPermanentCallback(Job2, 5, 'a')));
|
||||||
|
|
||||||
foo.ComplexJob(10); // Invokes Job1().
|
foo.ComplexJob(10); // Invokes Job1().
|
||||||
|
|
|
@ -263,6 +263,10 @@ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0);
|
||||||
|
|
||||||
#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_
|
#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
|
} // namespace internal
|
||||||
|
|
||||||
// When an unexpected function call is encountered, Google Mock will
|
// 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
|
// This cannot take std::function directly, because then Action would not be
|
||||||
// directly constructible from lambda (it would require two conversions).
|
// directly constructible from lambda (it would require two conversions).
|
||||||
template <typename G,
|
template <typename G,
|
||||||
typename = typename ::std::enable_if<
|
typename IsCompatibleFunctor =
|
||||||
::std::is_constructible<::std::function<F>, G>::value>::type>
|
::std::is_constructible<::std::function<F>, G>,
|
||||||
Action(G&& fun) : fun_(::std::forward<G>(fun)) {} // NOLINT
|
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.
|
// Constructs an Action from its implementation.
|
||||||
explicit Action(ActionInterface<F>* impl)
|
explicit Action(ActionInterface<F>* impl)
|
||||||
|
@ -490,6 +500,26 @@ class Action {
|
||||||
template <typename G>
|
template <typename G>
|
||||||
friend class Action;
|
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.
|
// fun_ is an empty function if and only if this is the DoDefault() action.
|
||||||
::std::function<F> fun_;
|
::std::function<F> fun_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1470,8 +1470,19 @@ TEST(FunctorActionTest, TypeConversion) {
|
||||||
EXPECT_EQ(1, s2.Perform(std::make_tuple("hello")));
|
EXPECT_EQ(1, s2.Perform(std::make_tuple("hello")));
|
||||||
|
|
||||||
// Also between the lambda and the action itself.
|
// Also between the lambda and the action itself.
|
||||||
const Action<bool(std::string)> x = [](Unused) { return 42; };
|
const Action<bool(std::string)> x1 = [](Unused) { return 42; };
|
||||||
EXPECT_TRUE(x.Perform(std::make_tuple("hello")));
|
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) {
|
TEST(FunctorActionTest, UnusedArguments) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user