From 6386897feb0a3f4fbe104fe1fa4570ec8158d9e5 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 10 May 2022 20:08:19 -0700 Subject: 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 --- docs/gmock_cook_book.md | 63 ++++++++++++++++++++++++++------ googlemock/include/gmock/gmock-actions.h | 14 +++---- googlemock/test/gmock-actions_test.cc | 2 +- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/docs/gmock_cook_book.md b/docs/gmock_cook_book.md index bf52fa8..b6abffa 100644 --- a/docs/gmock_cook_book.md +++ b/docs/gmock_cook_book.md @@ -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 - T operator()(T* arg) { - return ++(*arg); - } -} +``` +MockFunction 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 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 move_only_state; + std::unique_ptr operator()() && { return std::move(move_only_state); } +}; + +MockFunction()> mock; +EXPECT_CALL(mock, Call).WillOnce(MoveOnlyAction{std::make_unique(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` or +`Action. 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 diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index c83a99a..e022c12 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -322,16 +322,18 @@ struct is_callable_r_impl>, R, F, Args...> template using is_callable_r = is_callable_r_impl; +} // namespace internal + // Specialized for function types below. template 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 final { std::function 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 { // An action can be used as a OnceAction, since it's obviously safe to call it // once. - operator internal::OnceAction() const { // NOLINT + operator OnceAction() 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. diff --git a/googlemock/test/gmock-actions_test.cc b/googlemock/test/gmock-actions_test.cc index db112f1..7313b78 100644 --- a/googlemock/test/gmock-actions_test.cc +++ b/googlemock/test/gmock-actions_test.cc @@ -1920,7 +1920,7 @@ TEST(MockMethodTest, ActionSwallowsAllArguments) { struct ActionWithTemplatedConversionOperators { template - operator internal::OnceAction() && { // NOLINT + operator OnceAction() && { // NOLINT return [] { return 17; }; } -- cgit v0.12