summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Jacobs <jacobsa@google.com>2022-04-26 21:39:03 (GMT)
committerCopybara-Service <copybara-worker@google.com>2022-04-26 21:39:37 (GMT)
commitc144d78f8295da3dbae3ad2d5fe66a9a42f8ce74 (patch)
treea7db04a970e8d04908f72c4b4af1613a0f10b156
parente33c2b24ca3e13df961ed369f7ed21e4cfcf9eec (diff)
downloadgoogletest-c144d78f8295da3dbae3ad2d5fe66a9a42f8ce74.zip
googletest-c144d78f8295da3dbae3ad2d5fe66a9a42f8ce74.tar.gz
googletest-c144d78f8295da3dbae3ad2d5fe66a9a42f8ce74.tar.bz2
Support move-only and &&-qualified actions in WithArgs.
PiperOrigin-RevId: 444671005 Change-Id: I7df5f038caf17afb60d4fb35434ff0b656d4c954
-rw-r--r--googlemock/include/gmock/gmock-actions.h57
-rw-r--r--googlemock/test/gmock-actions_test.cc25
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