Support move-only and &&-qualified actions in WithArgs.
PiperOrigin-RevId: 444671005 Change-Id: I7df5f038caf17afb60d4fb35434ff0b656d4c954
This commit is contained in:
		
				
					committed by
					
						
						Copybara-Service
					
				
			
			
				
	
			
			
			
						parent
						
							e33c2b24ca
						
					
				
				
					commit
					c144d78f82
				
			@@ -1279,17 +1279,60 @@ class IgnoreResultAction {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template <typename InnerAction, size_t... I>
 | 
					template <typename InnerAction, size_t... I>
 | 
				
			||||||
struct WithArgsAction {
 | 
					struct WithArgsAction {
 | 
				
			||||||
  InnerAction action;
 | 
					  InnerAction inner_action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // The inner action could be anything convertible to Action<X>.
 | 
					  // The signature of the function as seen by the inner action, given an out
 | 
				
			||||||
  // We use the conversion operator to detect the signature of the inner Action.
 | 
					  // action with the given result and argument types.
 | 
				
			||||||
  template <typename R, typename... Args>
 | 
					  template <typename R, typename... Args>
 | 
				
			||||||
  operator Action<R(Args...)>() const {  // NOLINT
 | 
					  using InnerSignature =
 | 
				
			||||||
    using TupleType = std::tuple<Args...>;
 | 
					      R(typename std::tuple_element<I, std::tuple<Args...>>::type...);
 | 
				
			||||||
    Action<R(typename std::tuple_element<I, TupleType>::type...)> converted(
 | 
					 | 
				
			||||||
        action);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return [converted](Args... args) -> R {
 | 
					  // 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
 | 
				
			||||||
 | 
					    Action<InnerSignature<R, Args...>> converted(inner_action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return [converted](Args&&... args) -> R {
 | 
				
			||||||
      return converted.Perform(std::forward_as_tuple(
 | 
					      return converted.Perform(std::forward_as_tuple(
 | 
				
			||||||
          std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...))...));
 | 
					          std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...))...));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1444,8 +1444,29 @@ TEST(WithArgsTest, ReturnReference) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
TEST(WithArgsTest, InnerActionWithConversion) {
 | 
					TEST(WithArgsTest, InnerActionWithConversion) {
 | 
				
			||||||
  Action<Derived*()> inner = [] { return nullptr; };
 | 
					  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
 | 
					#if !GTEST_OS_WINDOWS_MOBILE
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user