diff options
author | Aaron Jacobs <jacobsa@google.com> | 2022-04-26 21:39:03 (GMT) |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2022-04-26 21:39:37 (GMT) |
commit | c144d78f8295da3dbae3ad2d5fe66a9a42f8ce74 (patch) | |
tree | a7db04a970e8d04908f72c4b4af1613a0f10b156 /googlemock | |
parent | e33c2b24ca3e13df961ed369f7ed21e4cfcf9eec (diff) | |
download | googletest-c144d78f8295da3dbae3ad2d5fe66a9a42f8ce74.zip googletest-c144d78f8295da3dbae3ad2d5fe66a9a42f8ce74.tar.gz googletest-c144d78f8295da3dbae3ad2d5fe66a9a42f8ce74.tar.bz2 |
Support move-only and &&-qualified actions in WithArgs.
PiperOrigin-RevId: 444671005
Change-Id: I7df5f038caf17afb60d4fb35434ff0b656d4c954
Diffstat (limited to 'googlemock')
-rw-r--r-- | googlemock/include/gmock/gmock-actions.h | 57 | ||||
-rw-r--r-- | googlemock/test/gmock-actions_test.cc | 25 |
2 files changed, 73 insertions, 9 deletions
diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index ecc72d5..5836f17 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -1279,17 +1279,60 @@ class IgnoreResultAction { template <typename InnerAction, size_t... I> struct WithArgsAction { - InnerAction action; + InnerAction inner_action; - // The inner action could be anything convertible to Action<X>. - // We use the conversion operator to detect the signature of the inner Action. + // The signature of the function as seen by the inner action, given an out + // action with the given result and argument types. template <typename R, typename... Args> + using InnerSignature = + R(typename std::tuple_element<I, std::tuple<Args...>>::type...); + + // Rather than a call operator, we must define conversion operators to + // particular action types. This is necessary for embedded actions like + // DoDefault(), which rely on an action conversion operators rather than + // providing a call operator because even with a particular set of arguments + // they don't have a fixed return type. + + template <typename R, typename... Args, + typename std::enable_if< + std::is_convertible< + InnerAction, + // Unfortunately we can't use the InnerSignature alias here; + // MSVC complains about the I parameter pack not being + // expanded (error C3520) despite it being expanded in the + // type alias. + OnceAction<R(typename std::tuple_element< + I, std::tuple<Args...>>::type...)>>::value, + int>::type = 0> + operator OnceAction<R(Args...)>() && { // NOLINT + struct OA { + OnceAction<InnerSignature<R, Args...>> inner_action; + + R operator()(Args&&... args) && { + return std::move(inner_action) + .Call(std::get<I>( + std::forward_as_tuple(std::forward<Args>(args)...))...); + } + }; + + return OA{std::move(inner_action)}; + } + + template <typename R, typename... Args, + typename std::enable_if< + std::is_convertible< + const InnerAction&, + // Unfortunately we can't use the InnerSignature alias here; + // MSVC complains about the I parameter pack not being + // expanded (error C3520) despite it being expanded in the + // type alias. + Action<R(typename std::tuple_element< + I, std::tuple<Args...>>::type...)>>::value, + int>::type = 0> operator Action<R(Args...)>() const { // NOLINT - using TupleType = std::tuple<Args...>; - Action<R(typename std::tuple_element<I, TupleType>::type...)> converted( - action); + Action<InnerSignature<R, Args...>> converted(inner_action); - return [converted](Args... args) -> R { + return [converted](Args&&... args) -> R { return converted.Perform(std::forward_as_tuple( std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...))...)); }; diff --git a/googlemock/test/gmock-actions_test.cc b/googlemock/test/gmock-actions_test.cc index e41845e..a33358a 100644 --- a/googlemock/test/gmock-actions_test.cc +++ b/googlemock/test/gmock-actions_test.cc @@ -1444,8 +1444,29 @@ TEST(WithArgsTest, ReturnReference) { TEST(WithArgsTest, InnerActionWithConversion) { Action<Derived*()> inner = [] { return nullptr; }; - Action<Base*(double)> a = testing::WithoutArgs(inner); - EXPECT_EQ(nullptr, a.Perform(std::make_tuple(1.1))); + + MockFunction<Base*(double)> mock; + EXPECT_CALL(mock, Call) + .WillOnce(WithoutArgs(inner)) + .WillRepeatedly(WithoutArgs(inner)); + + EXPECT_EQ(nullptr, mock.AsStdFunction()(1.1)); + EXPECT_EQ(nullptr, mock.AsStdFunction()(1.1)); +} + +// It should be possible to use an &&-qualified inner action as long as the +// whole shebang is used as an rvalue with WillOnce. +TEST(WithArgsTest, RefQualifiedInnerAction) { + struct SomeAction { + int operator()(const int arg) && { + EXPECT_EQ(17, arg); + return 19; + } + }; + + MockFunction<int(int, int)> mock; + EXPECT_CALL(mock, Call).WillOnce(WithArg<1>(SomeAction{})); + EXPECT_EQ(19, mock.AsStdFunction()(0, 17)); } #if !GTEST_OS_WINDOWS_MOBILE |