diff options
author | Abseil Team <absl-team@google.com> | 2020-08-17 16:07:02 (GMT) |
---|---|---|
committer | vslashg <gfalcon@google.com> | 2020-08-24 03:50:54 (GMT) |
commit | fc1e7788993bd1418f80d64eb430bd9ac023db68 (patch) | |
tree | 635927e3cece061c1c042d90c1ef71f32b0b8098 /googlemock | |
parent | adeef192947fbc0f68fa14a6c494c8df32177508 (diff) | |
download | googletest-fc1e7788993bd1418f80d64eb430bd9ac023db68.zip googletest-fc1e7788993bd1418f80d64eb430bd9ac023db68.tar.gz googletest-fc1e7788993bd1418f80d64eb430bd9ac023db68.tar.bz2 |
Googletest export
Fix DoAll to work with move-only sink arguments.
This changes types of the first n - 1 actions so that they only get a readonly
view of the arguments. The last action will accept move only objects.
PiperOrigin-RevId: 327031893
Diffstat (limited to 'googlemock')
-rw-r--r-- | googlemock/docs/cheat_sheet.md | 2 | ||||
-rw-r--r-- | googlemock/include/gmock/gmock-actions.h | 23 | ||||
-rw-r--r-- | googlemock/test/gmock-generated-actions_test.cc | 27 |
3 files changed, 42 insertions, 10 deletions
diff --git a/googlemock/docs/cheat_sheet.md b/googlemock/docs/cheat_sheet.md index 2500260..cc7e699 100644 --- a/googlemock/docs/cheat_sheet.md +++ b/googlemock/docs/cheat_sheet.md @@ -618,7 +618,7 @@ composite action - trying to do so will result in a run-time error. <!-- mdformat off(no multiline tables) --> | | | | :----------------------------- | :------------------------------------------ | -| `DoAll(a1, a2, ..., an)` | Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. | +| `DoAll(a1, a2, ..., an)` | Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void and will receive a readonly view of the arguments. | | `IgnoreResult(a)` | Perform action `a` and ignore its result. `a` must not return void. | | `WithArg<N>(a)` | Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | | `WithArgs<N1, N2, ..., Nk>(a)` | Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index 79054db..3aba9ec 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -1032,9 +1032,13 @@ struct WithArgsAction { template <typename... Actions> struct DoAllAction { private: - template <typename... Args, size_t... I> - std::vector<Action<void(Args...)>> Convert(IndexSequence<I...>) const { - return {std::get<I>(actions)...}; + template <typename T> + using NonFinalType = + typename std::conditional<std::is_scalar<T>::value, T, const T&>::type; + + template <typename ActionT, size_t... I> + std::vector<ActionT> Convert(IndexSequence<I...>) const { + return {ActionT(std::get<I>(actions))...}; } public: @@ -1043,17 +1047,17 @@ struct DoAllAction { template <typename R, typename... Args> operator Action<R(Args...)>() const { // NOLINT struct Op { - std::vector<Action<void(Args...)>> converted; + std::vector<Action<void(NonFinalType<Args>...)>> converted; Action<R(Args...)> last; R operator()(Args... args) const { - auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...); for (auto& a : converted) { - a.Perform(tuple_args); + a.Perform(std::forward_as_tuple(std::forward<Args>(args)...)); } - return last.Perform(tuple_args); + return last.Perform(std::forward_as_tuple(std::forward<Args>(args)...)); } }; - return Op{Convert<Args...>(MakeIndexSequence<sizeof...(Actions) - 1>()), + return Op{Convert<Action<void(NonFinalType<Args>...)>>( + MakeIndexSequence<sizeof...(Actions) - 1>()), std::get<sizeof...(Actions) - 1>(actions)}; } }; @@ -1093,7 +1097,8 @@ struct DoAllAction { typedef internal::IgnoredValue Unused; // Creates an action that does actions a1, a2, ..., sequentially in -// each invocation. +// each invocation. All but the last action will have a readonly view of the +// arguments. template <typename... Action> internal::DoAllAction<typename std::decay<Action>::type...> DoAll( Action&&... action) { diff --git a/googlemock/test/gmock-generated-actions_test.cc b/googlemock/test/gmock-generated-actions_test.cc index ef39dff..6490616 100644 --- a/googlemock/test/gmock-generated-actions_test.cc +++ b/googlemock/test/gmock-generated-actions_test.cc @@ -422,6 +422,33 @@ TEST(DoAllTest, TenActions) { EXPECT_EQ('g', g); } +TEST(DoAllTest, NoArgs) { + bool ran_first = false; + Action<bool()> a = + DoAll([&] { ran_first = true; }, [&] { return ran_first; }); + EXPECT_TRUE(a.Perform({})); +} + +TEST(DoAllTest, MoveOnlyArgs) { + bool ran_first = false; + Action<int(std::unique_ptr<int>)> a = + DoAll(InvokeWithoutArgs([&] { ran_first = true; }), + [](std::unique_ptr<int> p) { return *p; }); + EXPECT_EQ(7, a.Perform(std::make_tuple(std::unique_ptr<int>(new int(7))))); + EXPECT_TRUE(ran_first); +} + +TEST(DoAllTest, ImplicitlyConvertsActionArguments) { + bool ran_first = false; + // Action<void(std::vector<int>)> isn't an + // Action<void(const std::vector<int>&) but can be converted. + Action<void(std::vector<int>)> first = [&] { ran_first = true; }; + Action<int(std::vector<int>)> a = + DoAll(first, [](std::vector<int> arg) { return arg.front(); }); + EXPECT_EQ(7, a.Perform(std::make_tuple(std::vector<int>{7}))); + EXPECT_TRUE(ran_first); +} + // The ACTION*() macros trigger warning C4100 (unreferenced formal // parameter) in MSVC with -W4. Unfortunately they cannot be fixed in // the macro definition, as the warnings are generated when the macro |