gmock-actions: add support for move-only values to Return.
`Return(x)` can now be used directly with `WillOnce` (the only place it makes sense in the type system), without using `ByMove`. PiperOrigin-RevId: 448380066 Change-Id: Ia71cc60ccbc3b99720662731a2d309735a5ce7c8
This commit is contained in:
		
				
					committed by
					
						
						Copybara-Service
					
				
			
			
				
	
			
			
			
						parent
						
							8a011b8a38
						
					
				
				
					commit
					5126f71661
				
			@@ -878,6 +878,17 @@ class ReturnAction final {
 | 
				
			|||||||
 public:
 | 
					 public:
 | 
				
			||||||
  explicit ReturnAction(R value) : value_(std::move(value)) {}
 | 
					  explicit ReturnAction(R value) : value_(std::move(value)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename U, typename... Args,
 | 
				
			||||||
 | 
					            typename = typename std::enable_if<conjunction<
 | 
				
			||||||
 | 
					                // See the requirements documented on Return.
 | 
				
			||||||
 | 
					                negation<std::is_same<void, U>>,  //
 | 
				
			||||||
 | 
					                negation<std::is_reference<U>>,   //
 | 
				
			||||||
 | 
					                std::is_convertible<R, U>,        //
 | 
				
			||||||
 | 
					                std::is_move_constructible<U>>::value>::type>
 | 
				
			||||||
 | 
					  operator OnceAction<U(Args...)>() && {  // NOLINT
 | 
				
			||||||
 | 
					    return Impl<U>(std::move(value_));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename U, typename... Args,
 | 
					  template <typename U, typename... Args,
 | 
				
			||||||
            typename = typename std::enable_if<conjunction<
 | 
					            typename = typename std::enable_if<conjunction<
 | 
				
			||||||
                // See the requirements documented on Return.
 | 
					                // See the requirements documented on Return.
 | 
				
			||||||
@@ -894,9 +905,17 @@ class ReturnAction final {
 | 
				
			|||||||
  template <typename U>
 | 
					  template <typename U>
 | 
				
			||||||
  class Impl final {
 | 
					  class Impl final {
 | 
				
			||||||
   public:
 | 
					   public:
 | 
				
			||||||
 | 
					    // The constructor used when the return value is allowed to move from the
 | 
				
			||||||
 | 
					    // input value (i.e. we are converting to OnceAction).
 | 
				
			||||||
 | 
					    explicit Impl(R&& input_value)
 | 
				
			||||||
 | 
					        : state_(new State(std::move(input_value))) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The constructor used when the return value is not allowed to move from
 | 
				
			||||||
 | 
					    // the input value (i.e. we are converting to Action).
 | 
				
			||||||
    explicit Impl(const R& input_value) : state_(new State(input_value)) {}
 | 
					    explicit Impl(const R& input_value) : state_(new State(input_value)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    U operator()() const { return state_->value; }
 | 
					    U operator()() && { return std::move(state_->value); }
 | 
				
			||||||
 | 
					    U operator()() const& { return state_->value; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   private:
 | 
					   private:
 | 
				
			||||||
    // We put our state on the heap so that the compiler-generated copy/move
 | 
					    // We put our state on the heap so that the compiler-generated copy/move
 | 
				
			||||||
@@ -923,6 +942,18 @@ class ReturnAction final {
 | 
				
			|||||||
            // explicit constructor from R.
 | 
					            // explicit constructor from R.
 | 
				
			||||||
            value(ImplicitCast_<U>(internal::as_const(input_value))) {}
 | 
					            value(ImplicitCast_<U>(internal::as_const(input_value))) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // As above, but for the case where we're moving from the ReturnAction
 | 
				
			||||||
 | 
					      // object because it's being used as a OnceAction.
 | 
				
			||||||
 | 
					      explicit State(R&& input_value_in)
 | 
				
			||||||
 | 
					          : input_value(std::move(input_value_in)),
 | 
				
			||||||
 | 
					            // For the same reason as above we make an implicit conversion to U
 | 
				
			||||||
 | 
					            // before initializing the value.
 | 
				
			||||||
 | 
					            //
 | 
				
			||||||
 | 
					            // Unlike above we provide the input value as an rvalue to the
 | 
				
			||||||
 | 
					            // implicit conversion because this is a OnceAction: it's fine if it
 | 
				
			||||||
 | 
					            // wants to consume the input value.
 | 
				
			||||||
 | 
					            value(ImplicitCast_<U>(std::move(input_value))) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // A copy of the value originally provided by the user. We retain this in
 | 
					      // A copy of the value originally provided by the user. We retain this in
 | 
				
			||||||
      // addition to the value of the mock function's result type below in case
 | 
					      // addition to the value of the mock function's result type below in case
 | 
				
			||||||
      // the latter is a reference-like type. See the std::string_view example
 | 
					      // the latter is a reference-like type. See the std::string_view example
 | 
				
			||||||
@@ -1740,18 +1771,19 @@ internal::WithArgsAction<typename std::decay<InnerAction>::type> WithoutArgs(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Creates an action that returns a value.
 | 
					// Creates an action that returns a value.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// R must be copy-constructible. The returned type can be used as an
 | 
					// The returned type can be used with a mock function returning a non-void,
 | 
				
			||||||
// Action<U(Args...)> for any type U where all of the following are true:
 | 
					// non-reference type U as follows:
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//  *  U is not void.
 | 
					//  *  If R is convertible to U and U is move-constructible, then the action can
 | 
				
			||||||
//  *  U is not a reference type. (Use ReturnRef instead.)
 | 
					//     be used with WillOnce.
 | 
				
			||||||
//  *  U is copy-constructible.
 | 
					 | 
				
			||||||
//  *  const R& is convertible to U.
 | 
					 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// The Action<U(Args)...> object contains the R value from which the U return
 | 
					//  *  If const R& is convertible to U and U is copy-constructible, then the
 | 
				
			||||||
// value is constructed (a copy of the argument to Return). This means that the
 | 
					//     action can be used with both WillOnce and WillRepeatedly.
 | 
				
			||||||
// R value will survive at least until the mock object's expectations are
 | 
					//
 | 
				
			||||||
// cleared or the mock object is destroyed, meaning that U can be a
 | 
					// The mock expectation contains the R value from which the U return value is
 | 
				
			||||||
 | 
					// constructed (a move/copy of the argument to Return). This means that the R
 | 
				
			||||||
 | 
					// value will survive at least until the mock object's expectations are cleared
 | 
				
			||||||
 | 
					// or the mock object is destroyed, meaning that U can safely be a
 | 
				
			||||||
// reference-like type such as std::string_view:
 | 
					// reference-like type such as std::string_view:
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//     // The mock function returns a view of a copy of the string fed to
 | 
					//     // The mock function returns a view of a copy of the string fed to
 | 
				
			||||||
@@ -1794,6 +1826,8 @@ inline internal::ReturnRefOfCopyAction<R> ReturnRefOfCopy(const R& x) {
 | 
				
			|||||||
  return internal::ReturnRefOfCopyAction<R>(x);
 | 
					  return internal::ReturnRefOfCopyAction<R>(x);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DEPRECATED: use Return(x) directly with WillOnce.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
// Modifies the parent action (a Return() action) to perform a move of the
 | 
					// Modifies the parent action (a Return() action) to perform a move of the
 | 
				
			||||||
// argument instead of a copy.
 | 
					// argument instead of a copy.
 | 
				
			||||||
// Return(ByMove()) actions can only be executed once and will assert this
 | 
					// Return(ByMove()) actions can only be executed once and will assert this
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,7 @@
 | 
				
			|||||||
#include "gmock/gmock-actions.h"
 | 
					#include "gmock/gmock-actions.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
#include <iterator>
 | 
					#include <iterator>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
@@ -709,6 +710,24 @@ TEST(ReturnTest, PrefersConversionOperator) {
 | 
				
			|||||||
  EXPECT_THAT(mock.AsStdFunction()(), Field(&Out::x, 19));
 | 
					  EXPECT_THAT(mock.AsStdFunction()(), Field(&Out::x, 19));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// It should be possible to use Return(R) with a mock function result type U
 | 
				
			||||||
 | 
					// that is convertible from const R& but *not* R (such as
 | 
				
			||||||
 | 
					// std::reference_wrapper). This should work for both WillOnce and
 | 
				
			||||||
 | 
					// WillRepeatedly.
 | 
				
			||||||
 | 
					TEST(ReturnTest, ConversionRequiresConstLvalueReference) {
 | 
				
			||||||
 | 
					  using R = int;
 | 
				
			||||||
 | 
					  using U = std::reference_wrapper<const int>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static_assert(std::is_convertible<const R&, U>::value, "");
 | 
				
			||||||
 | 
					  static_assert(!std::is_convertible<R, U>::value, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MockFunction<U()> mock;
 | 
				
			||||||
 | 
					  EXPECT_CALL(mock, Call).WillOnce(Return(17)).WillRepeatedly(Return(19));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_EQ(17, mock.AsStdFunction()());
 | 
				
			||||||
 | 
					  EXPECT_EQ(19, mock.AsStdFunction()());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Return(x) should not be usable with a mock function result type that's
 | 
					// Return(x) should not be usable with a mock function result type that's
 | 
				
			||||||
// implicitly convertible from decltype(x) but requires a non-const lvalue
 | 
					// implicitly convertible from decltype(x) but requires a non-const lvalue
 | 
				
			||||||
// reference to the input. It doesn't make sense for the conversion operator to
 | 
					// reference to the input. It doesn't make sense for the conversion operator to
 | 
				
			||||||
@@ -731,32 +750,33 @@ TEST(ReturnTest, ConversionRequiresMutableLvalueReference) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // It shouldn't be possible to use the result of Return(std::string) in a
 | 
					  // It shouldn't be possible to use the result of Return(std::string) in a
 | 
				
			||||||
  // context where an S is needed.
 | 
					  // context where an S is needed.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Here too we disable the assertion for MSVC, since its incorrect
 | 
				
			||||||
 | 
					  // implementation of is_convertible causes our SFINAE to be wrong.
 | 
				
			||||||
  using RA = decltype(Return(std::string()));
 | 
					  using RA = decltype(Return(std::string()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static_assert(!std::is_convertible<RA, Action<S()>>::value, "");
 | 
					  static_assert(!std::is_convertible<RA, Action<S()>>::value, "");
 | 
				
			||||||
 | 
					#ifndef _MSC_VER
 | 
				
			||||||
  static_assert(!std::is_convertible<RA, OnceAction<S()>>::value, "");
 | 
					  static_assert(!std::is_convertible<RA, OnceAction<S()>>::value, "");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Return(x) should not be usable with a mock function result type that's
 | 
					TEST(ReturnTest, MoveOnlyResultType) {
 | 
				
			||||||
// implicitly convertible from decltype(x) but requires an rvalue reference to
 | 
					  // Return should support move-only result types when used with WillOnce.
 | 
				
			||||||
// the input. We don't yet support handing over the value for consumption.
 | 
					  {
 | 
				
			||||||
TEST(ReturnTest, ConversionRequiresRvalueReference) {
 | 
					    MockFunction<std::unique_ptr<int>()> mock;
 | 
				
			||||||
  // Set up a type that is implicitly convertible from std::string&& and
 | 
					    EXPECT_CALL(mock, Call)
 | 
				
			||||||
  // `const std::string&&`, but not `const std::string&`.
 | 
					        // NOLINTNEXTLINE
 | 
				
			||||||
  struct S {
 | 
					        .WillOnce(Return(std::unique_ptr<int>(new int(17))));
 | 
				
			||||||
    S(std::string&&) {}        // NOLINT
 | 
					 | 
				
			||||||
    S(const std::string&&) {}  // NOLINT
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static_assert(std::is_convertible<std::string, S>::value, "");
 | 
					    EXPECT_THAT(mock.AsStdFunction()(), Pointee(17));
 | 
				
			||||||
  static_assert(!std::is_convertible<const std::string&, S>::value, "");
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // It shouldn't be possible to use the result of Return(std::string) in a
 | 
					  // The result of Return should not be convertible to Action (so it can't be
 | 
				
			||||||
  // context where an S is needed.
 | 
					  // used with WillRepeatedly).
 | 
				
			||||||
  using RA = decltype(Return(std::string()));
 | 
					  static_assert(!std::is_convertible<decltype(Return(std::unique_ptr<int>())),
 | 
				
			||||||
 | 
					                                     Action<std::unique_ptr<int>()>>::value,
 | 
				
			||||||
  static_assert(!std::is_convertible<RA, Action<S()>>::value, "");
 | 
					                "");
 | 
				
			||||||
  static_assert(!std::is_convertible<RA, OnceAction<S()>>::value, "");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Tests that Return(v) is covaraint.
 | 
					// Tests that Return(v) is covaraint.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user