Skip to content

Commit fd53816

Browse files
Abseil TeamCJ-Johnson
authored andcommitted
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
1 parent 23b2a3b commit fd53816

File tree

3 files changed

+65
-22
lines changed

3 files changed

+65
-22
lines changed

googlemock/docs/cook_book.md

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,7 +2174,7 @@ own precedence order distinct from the `ON_CALL` precedence order.
21742174
### Using Functions/Methods/Functors/Lambdas as Actions {#FunctionsAsActions}
21752175

21762176
If the built-in actions don't suit you, you can use an existing callable
2177-
(function, `std::function`, method, functor, lambda as an action.
2177+
(function, `std::function`, method, functor, lambda) as an action.
21782178

21792179
<!-- GOOGLETEST_CM0024 DO NOT DELETE -->
21802180

@@ -2203,6 +2203,7 @@ class Helper {
22032203
.WillRepeatedly(Invoke(NewPermanentCallback(Sum3, 1)));
22042204
EXPECT_CALL(foo, ComplexJob(_))
22052205
.WillOnce(Invoke(&helper, &Helper::ComplexJob))
2206+
.WillOnce([] { return true; })
22062207
.WillRepeatedly([](int x) { return x > 0; });
22072208

22082209
foo.Sum(5, 6); // Invokes CalculateSum(5, 6).
@@ -2212,11 +2213,11 @@ class Helper {
22122213
```
22132214

22142215
The only requirement is that the type of the function, etc must be *compatible*
2215-
with the signature of the mock function, meaning that the latter's arguments can
2216-
be implicitly converted to the corresponding arguments of the former, and the
2217-
former's return type can be implicitly converted to that of the latter. So, you
2218-
can invoke something whose type is *not* exactly the same as the mock function,
2219-
as long as it's safe to do so - nice, huh?
2216+
with the signature of the mock function, meaning that the latter's arguments (if
2217+
it takes any) can be implicitly converted to the corresponding arguments of the
2218+
former, and the former's return type can be implicitly converted to that of the
2219+
latter. So, you can invoke something whose type is *not* exactly the same as the
2220+
mock function, as long as it's safe to do so - nice, huh?
22202221

22212222
**`Note:`{.escaped}**
22222223

@@ -2267,19 +2268,20 @@ TEST_F(FooTest, Test) {
22672268

22682269
### Invoking a Function/Method/Functor/Lambda/Callback Without Arguments
22692270

2270-
`Invoke()` is very useful for doing actions that are more complex. It passes the
2271-
mock function's arguments to the function, etc being invoked such that the
2272-
callee has the full context of the call to work with. If the invoked function is
2273-
not interested in some or all of the arguments, it can simply ignore them.
2271+
`Invoke()` passes the mock function's arguments to the function, etc being
2272+
invoked such that the callee has the full context of the call to work with. If
2273+
the invoked function is not interested in some or all of the arguments, it can
2274+
simply ignore them.
22742275

22752276
Yet, a common pattern is that a test author wants to invoke a function without
2276-
the arguments of the mock function. `Invoke()` allows her to do that using a
2277-
wrapper function that throws away the arguments before invoking an underlining
2278-
nullary function. Needless to say, this can be tedious and obscures the intent
2279-
of the test.
2277+
the arguments of the mock function. She could do that using a wrapper function
2278+
that throws away the arguments before invoking an underlining nullary function.
2279+
Needless to say, this can be tedious and obscures the intent of the test.
22802280

2281-
`InvokeWithoutArgs()` solves this problem. It's like `Invoke()` except that it
2282-
doesn't pass the mock function's arguments to the callee. Here's an example:
2281+
There are two solutions to this problem. First, you can pass any callable of
2282+
zero args as an action. Alternatively, use `InvokeWithoutArgs()`, which is like
2283+
`Invoke()` except that it doesn't pass the mock function's arguments to the
2284+
callee. Here's an example of each:
22832285

22842286
```cpp
22852287
using ::testing::_;
@@ -2296,7 +2298,7 @@ bool Job2(int n, char c) { ... }
22962298
...
22972299
MockFoo foo;
22982300
EXPECT_CALL(foo, ComplexJob(_))
2299-
.WillOnce(InvokeWithoutArgs(Job1))
2301+
.WillOnce([] { Job1(); });
23002302
.WillOnce(InvokeWithoutArgs(NewPermanentCallback(Job2, 5, 'a')));
23012303

23022304
foo.ComplexJob(10); // Invokes Job1().

googlemock/include/gmock/gmock-actions.h

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0);
263263

264264
#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_
265265

266+
// Simple two-arg form of std::disjunction.
267+
template <typename P, typename Q>
268+
using disjunction = typename ::std::conditional<P::value, P, Q>::type;
269+
266270
} // namespace internal
267271

268272
// When an unexpected function call is encountered, Google Mock will
@@ -456,9 +460,15 @@ class Action {
456460
// This cannot take std::function directly, because then Action would not be
457461
// directly constructible from lambda (it would require two conversions).
458462
template <typename G,
459-
typename = typename ::std::enable_if<
460-
::std::is_constructible<::std::function<F>, G>::value>::type>
461-
Action(G&& fun) : fun_(::std::forward<G>(fun)) {} // NOLINT
463+
typename IsCompatibleFunctor =
464+
::std::is_constructible<::std::function<F>, G>,
465+
typename IsNoArgsFunctor =
466+
::std::is_constructible<::std::function<Result()>, G>,
467+
typename = typename ::std::enable_if<internal::disjunction<
468+
IsCompatibleFunctor, IsNoArgsFunctor>::value>::type>
469+
Action(G&& fun) { // NOLINT
470+
Init(::std::forward<G>(fun), IsCompatibleFunctor());
471+
}
462472

463473
// Constructs an Action from its implementation.
464474
explicit Action(ActionInterface<F>* impl)
@@ -490,6 +500,26 @@ class Action {
490500
template <typename G>
491501
friend class Action;
492502

503+
template <typename G>
504+
void Init(G&& g, ::std::true_type) {
505+
fun_ = ::std::forward<G>(g);
506+
}
507+
508+
template <typename G>
509+
void Init(G&& g, ::std::false_type) {
510+
fun_ = IgnoreArgs<typename ::std::decay<G>::type>{::std::forward<G>(g)};
511+
}
512+
513+
template <typename FunctionImpl>
514+
struct IgnoreArgs {
515+
template <typename... Args>
516+
Result operator()(const Args&...) const {
517+
return function_impl();
518+
}
519+
520+
FunctionImpl function_impl;
521+
};
522+
493523
// fun_ is an empty function if and only if this is the DoDefault() action.
494524
::std::function<F> fun_;
495525
};

googlemock/test/gmock-actions_test.cc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,8 +1470,19 @@ TEST(FunctorActionTest, TypeConversion) {
14701470
EXPECT_EQ(1, s2.Perform(std::make_tuple("hello")));
14711471

14721472
// Also between the lambda and the action itself.
1473-
const Action<bool(std::string)> x = [](Unused) { return 42; };
1474-
EXPECT_TRUE(x.Perform(std::make_tuple("hello")));
1473+
const Action<bool(std::string)> x1 = [](Unused) { return 42; };
1474+
const Action<bool(std::string)> x2 = [] { return 42; };
1475+
EXPECT_TRUE(x1.Perform(std::make_tuple("hello")));
1476+
EXPECT_TRUE(x2.Perform(std::make_tuple("hello")));
1477+
1478+
// Ensure decay occurs where required.
1479+
std::function<int()> f = [] { return 7; };
1480+
Action<int(int)> d = f;
1481+
f = nullptr;
1482+
EXPECT_EQ(7, d.Perform(std::make_tuple(1)));
1483+
1484+
// Ensure creation of an empty action succeeds.
1485+
Action<void(int)>(nullptr);
14751486
}
14761487

14771488
TEST(FunctorActionTest, UnusedArguments) {

0 commit comments

Comments
 (0)