gmock-actions: make OnceAction public.

So that it can be referenced in conversion operators for actions that need to
know the concrete return type.

PiperOrigin-RevId: 447889344
Change-Id: I643d3298bc8effd08741282a956c221f9d67d378
This commit is contained in:
Aaron Jacobs 2022-05-10 20:08:19 -07:00 committed by Copybara-Service
parent bda85449f4
commit 6386897feb
3 changed files with 59 additions and 20 deletions

View File

@ -3812,22 +3812,19 @@ Cardinality EvenNumber() {
.Times(EvenNumber());
```
### Writing New Actions Quickly {#QuickNewActions}
### Writing New Actions {#QuickNewActions}
If the built-in actions don't work for you, you can easily define your own one.
Just define a functor class with a (possibly templated) call operator, matching
the signature of your action.
All you need is a call operator with a signature compatible with the mocked
function. So you can use a lambda:
```cpp
struct Increment {
template <typename T>
T operator()(T* arg) {
return ++(*arg);
}
}
```
MockFunction<int(int)> mock;
EXPECT_CALL(mock, Call).WillOnce([](const int input) { return input * 7; });
EXPECT_EQ(14, mock.AsStdFunction()(2));
```
The same approach works with stateful functors (or any callable, really):
Or a struct with a call operator (even a templated one):
```
struct MultiplyBy {
@ -3835,12 +3832,54 @@ struct MultiplyBy {
T operator()(T arg) { return arg * multiplier; }
int multiplier;
}
};
// Then use:
// EXPECT_CALL(...).WillOnce(MultiplyBy{7});
```
It's also fine for the callable to take no arguments, ignoring the arguments
supplied to the mock function:
```
MockFunction<int(int)> mock;
EXPECT_CALL(mock, Call).WillOnce([] { return 17; });
EXPECT_EQ(17, mock.AsStdFunction()(0));
```
When used with `WillOnce`, the callable can assume it will be called at most
once and is allowed to be a move-only type:
```
// An action that contains move-only types and has an &&-qualified operator,
// demanding in the type system that it be called at most once. This can be
// used with WillOnce, but the compiler will reject it if handed to
// WillRepeatedly.
struct MoveOnlyAction {
std::unique_ptr<int> move_only_state;
std::unique_ptr<int> operator()() && { return std::move(move_only_state); }
};
MockFunction<std::unique_ptr<int>()> mock;
EXPECT_CALL(mock, Call).WillOnce(MoveOnlyAction{std::make_unique<int>(17)});
EXPECT_THAT(mock.AsStdFunction()(), Pointee(Eq(17)));
```
More generally, to use with a mock function whose signature is `R(Args...)` the
object can be anything convertible to `OnceAction<R(Args...)>` or
`Action<R(Args...)`>. The difference between the two is that `OnceAction` has
weaker requirements (`Action` requires a copy-constructible input that can be
called repeatedly whereas `OnceAction` requires only move-constructible and
supports `&&`-qualified call operators), but can be used only with `WillOnce`.
`OnceAction` is typically relevant only when supporting move-only types or
actions that want a type-system guarantee that they will be called at most once.
Typically the `OnceAction` and `Action` templates need not be referenced
directly in your actions: a struct or class with a call operator is sufficient,
as in the examples above. But fancier polymorphic actions that need to know the
specific return type of the mock function can define templated conversion
operators to make that possible. See `gmock-actions.h` for examples.
#### Legacy macro-based Actions
Before C++11, the functor-based actions were not supported; the old way of

View File

@ -322,16 +322,18 @@ struct is_callable_r_impl<void_t<call_result_t<F, Args...>>, R, F, Args...>
template <typename R, typename F, typename... Args>
using is_callable_r = is_callable_r_impl<void, R, F, Args...>;
} // namespace internal
// Specialized for function types below.
template <typename F>
class OnceAction;
// An action that can only be used once.
//
// This is what is accepted by WillOnce, which doesn't require the underlying
// action to be copy-constructible (only move-constructible), and promises to
// invoke it as an rvalue reference. This allows the action to work with
// move-only types like std::move_only_function in a type-safe manner.
// This is accepted by WillOnce, which doesn't require the underlying action to
// be copy-constructible (only move-constructible), and promises to invoke it as
// an rvalue reference. This allows the action to work with move-only types like
// std::move_only_function in a type-safe manner.
//
// For example:
//
@ -501,8 +503,6 @@ class OnceAction<Result(Args...)> final {
std::function<Result(Args...)> function_;
};
} // namespace internal
// When an unexpected function call is encountered, Google Mock will
// let it return a default value if the user has specified one for its
// return type, or if the return type has a built-in default value;
@ -742,7 +742,7 @@ class Action<R(Args...)> {
// An action can be used as a OnceAction, since it's obviously safe to call it
// once.
operator internal::OnceAction<F>() const { // NOLINT
operator OnceAction<F>() const { // NOLINT
// Return a OnceAction-compatible callable that calls Perform with the
// arguments it is provided. We could instead just return fun_, but then
// we'd need to handle the IsDoDefault() case separately.

View File

@ -1920,7 +1920,7 @@ TEST(MockMethodTest, ActionSwallowsAllArguments) {
struct ActionWithTemplatedConversionOperators {
template <typename... Args>
operator internal::OnceAction<int(Args...)>() && { // NOLINT
operator OnceAction<int(Args...)>() && { // NOLINT
return [] { return 17; };
}