Add ByMove() modifier for the Return() action. Pull in gtest 695.
This commit is contained in:
		
							parent
							
								
									5b9cbbb16d
								
							
						
					
					
						commit
						3d1c78b2bf
					
				| @ -459,6 +459,14 @@ class ActionAdaptor : public ActionInterface<F1> { | ||||
|   GTEST_DISALLOW_ASSIGN_(ActionAdaptor); | ||||
| }; | ||||
| 
 | ||||
| // Helper struct to specialize ReturnAction to execute a move instead of a copy
 | ||||
| // on return. Useful for move-only types, but could be used on any type.
 | ||||
| template <typename T> | ||||
| struct ByMoveWrapper { | ||||
|   explicit ByMoveWrapper(T value) : payload(move(value)) {} | ||||
|   T payload; | ||||
| }; | ||||
| 
 | ||||
| // Implements the polymorphic Return(x) action, which can be used in
 | ||||
| // any function that returns the type of x, regardless of the argument
 | ||||
| // types.
 | ||||
| @ -489,7 +497,7 @@ class ReturnAction { | ||||
|   // Constructs a ReturnAction object from the value to be returned.
 | ||||
|   // 'value' is passed by value instead of by const reference in order
 | ||||
|   // to allow Return("string literal") to compile.
 | ||||
|   explicit ReturnAction(R value) : value_(value) {} | ||||
|   explicit ReturnAction(R value) : value_(new R(move(value))) {} | ||||
| 
 | ||||
|   // This template type conversion operator allows Return(x) to be
 | ||||
|   // used in ANY function that returns x's type.
 | ||||
| @ -505,14 +513,14 @@ class ReturnAction { | ||||
|     // in the Impl class. But both definitions must be the same.
 | ||||
|     typedef typename Function<F>::Result Result; | ||||
|     GTEST_COMPILE_ASSERT_( | ||||
|         !internal::is_reference<Result>::value, | ||||
|         !is_reference<Result>::value, | ||||
|         use_ReturnRef_instead_of_Return_to_return_a_reference); | ||||
|     return Action<F>(new Impl<F>(value_)); | ||||
|     return Action<F>(new Impl<R, F>(value_)); | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   // Implements the Return(x) action for a particular function type F.
 | ||||
|   template <typename F> | ||||
|   template <typename R_, typename F> | ||||
|   class Impl : public ActionInterface<F> { | ||||
|    public: | ||||
|     typedef typename Function<F>::Result Result; | ||||
| @ -525,20 +533,45 @@ class ReturnAction { | ||||
|     // Result to call.  ImplicitCast_ forces the compiler to convert R to
 | ||||
|     // Result without considering explicit constructors, thus resolving the
 | ||||
|     // ambiguity. value_ is then initialized using its copy constructor.
 | ||||
|     explicit Impl(R value) | ||||
|         : value_(::testing::internal::ImplicitCast_<Result>(value)) {} | ||||
|     explicit Impl(const linked_ptr<R>& value) | ||||
|         : value_(ImplicitCast_<Result>(*value)) {} | ||||
| 
 | ||||
|     virtual Result Perform(const ArgumentTuple&) { return value_; } | ||||
| 
 | ||||
|    private: | ||||
|     GTEST_COMPILE_ASSERT_(!internal::is_reference<Result>::value, | ||||
|     GTEST_COMPILE_ASSERT_(!is_reference<Result>::value, | ||||
|                           Result_cannot_be_a_reference_type); | ||||
|     Result value_; | ||||
| 
 | ||||
|     GTEST_DISALLOW_ASSIGN_(Impl); | ||||
|   }; | ||||
| 
 | ||||
|   R value_; | ||||
|   // Partially specialize for ByMoveWrapper. This version of ReturnAction will
 | ||||
|   // move its contents instead.
 | ||||
|   template <typename R_, typename F> | ||||
|   class Impl<ByMoveWrapper<R_>, F> : public ActionInterface<F> { | ||||
|    public: | ||||
|     typedef typename Function<F>::Result Result; | ||||
|     typedef typename Function<F>::ArgumentTuple ArgumentTuple; | ||||
| 
 | ||||
|     explicit Impl(const linked_ptr<R>& wrapper) | ||||
|         : performed_(false), wrapper_(wrapper) {} | ||||
| 
 | ||||
|     virtual Result Perform(const ArgumentTuple&) { | ||||
|       GTEST_CHECK_(!performed_) | ||||
|           << "A ByMove() action should only be performed once."; | ||||
|       performed_ = true; | ||||
|       return move(wrapper_->payload); | ||||
|     } | ||||
| 
 | ||||
|    private: | ||||
|     bool performed_; | ||||
|     const linked_ptr<R> wrapper_; | ||||
| 
 | ||||
|     GTEST_DISALLOW_ASSIGN_(Impl); | ||||
|   }; | ||||
| 
 | ||||
|   const linked_ptr<R> value_; | ||||
| 
 | ||||
|   GTEST_DISALLOW_ASSIGN_(ReturnAction); | ||||
| }; | ||||
| @ -977,7 +1010,7 @@ Action<To>::Action(const Action<From>& from) | ||||
| // will trigger a compiler error about using array as initializer.
 | ||||
| template <typename R> | ||||
| internal::ReturnAction<R> Return(R value) { | ||||
|   return internal::ReturnAction<R>(value); | ||||
|   return internal::ReturnAction<R>(internal::move(value)); | ||||
| } | ||||
| 
 | ||||
| // Creates an action that returns NULL.
 | ||||
| @ -1004,6 +1037,15 @@ inline internal::ReturnRefOfCopyAction<R> ReturnRefOfCopy(const R& x) { | ||||
|   return internal::ReturnRefOfCopyAction<R>(x); | ||||
| } | ||||
| 
 | ||||
| // Modifies the parent action (a Return() action) to perform a move of the
 | ||||
| // argument instead of a copy.
 | ||||
| // Return(ByMove()) actions can only be executed once and will assert this
 | ||||
| // invariant.
 | ||||
| template <typename R> | ||||
| internal::ByMoveWrapper<R> ByMove(R x) { | ||||
|   return internal::ByMoveWrapper<R>(internal::move(x)); | ||||
| } | ||||
| 
 | ||||
| // Creates an action that does the default action for the give mock function.
 | ||||
| inline internal::DoDefaultAction DoDefault() { | ||||
|   return internal::DoDefaultAction(); | ||||
|  | ||||
| @ -1302,15 +1302,12 @@ template <typename T> | ||||
| class ReferenceOrValueWrapper { | ||||
|  public: | ||||
|   // Constructs a wrapper from the given value/reference.
 | ||||
|   explicit ReferenceOrValueWrapper(T value) | ||||
|       : value_(GTEST_MOVE_(value)) {} | ||||
|   explicit ReferenceOrValueWrapper(T value) : value_(move(value)) {} | ||||
| 
 | ||||
|   // Unwraps and returns the underlying value/reference, exactly as
 | ||||
|   // originally passed. The behavior of calling this more than once on
 | ||||
|   // the same object is unspecified.
 | ||||
|   T Unwrap() { | ||||
|     return GTEST_MOVE_(value_); | ||||
|   } | ||||
|   T Unwrap() { return move(value_); } | ||||
| 
 | ||||
|   // Provides nondestructive access to the underlying value/reference.
 | ||||
|   // Always returns a const reference (more precisely,
 | ||||
| @ -1407,8 +1404,7 @@ class ActionResultHolder : public UntypedActionResultHolderBase { | ||||
|  private: | ||||
|   typedef ReferenceOrValueWrapper<T> Wrapper; | ||||
| 
 | ||||
|   explicit ActionResultHolder(Wrapper result) | ||||
|       : result_(GTEST_MOVE_(result)) {} | ||||
|   explicit ActionResultHolder(Wrapper result) : result_(move(result)) {} | ||||
| 
 | ||||
|   Wrapper result_; | ||||
| 
 | ||||
|  | ||||
| @ -57,6 +57,7 @@ using testing::_; | ||||
| using testing::Action; | ||||
| using testing::ActionInterface; | ||||
| using testing::Assign; | ||||
| using testing::ByMove; | ||||
| using testing::ByRef; | ||||
| using testing::DefaultValue; | ||||
| using testing::DoDefault; | ||||
| @ -638,6 +639,7 @@ class MockClass { | ||||
|   MOCK_METHOD0(Foo, MyClass()); | ||||
| #if GTEST_HAS_STD_UNIQUE_PTR_ | ||||
|   MOCK_METHOD0(MakeUnique, std::unique_ptr<int>()); | ||||
|   MOCK_METHOD0(MakeUniqueBase, std::unique_ptr<Base>()); | ||||
|   MOCK_METHOD0(MakeVectorUnique, std::vector<std::unique_ptr<int>>()); | ||||
| #endif | ||||
| 
 | ||||
| @ -1285,7 +1287,42 @@ std::vector<std::unique_ptr<int>> VectorUniquePtrSource() { | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| TEST(MockMethodTest, CanReturnMoveOnlyValue) { | ||||
| TEST(MockMethodTest, CanReturnMoveOnlyValue_Return) { | ||||
|   MockClass mock; | ||||
|   std::unique_ptr<int> i(new int(19)); | ||||
|   EXPECT_CALL(mock, MakeUnique()).WillOnce(Return(ByMove(std::move(i)))); | ||||
|   EXPECT_CALL(mock, MakeVectorUnique()) | ||||
|       .WillOnce(Return(ByMove(VectorUniquePtrSource()))); | ||||
|   Derived* d = new Derived; | ||||
|   EXPECT_CALL(mock, MakeUniqueBase()) | ||||
|       .WillOnce(Return(ByMove(std::unique_ptr<Derived>(d)))); | ||||
| 
 | ||||
|   std::unique_ptr<int> result1 = mock.MakeUnique(); | ||||
|   EXPECT_EQ(19, *result1); | ||||
| 
 | ||||
|   std::vector<std::unique_ptr<int>> vresult = mock.MakeVectorUnique(); | ||||
|   EXPECT_EQ(1, vresult.size()); | ||||
|   EXPECT_NE(nullptr, vresult[0]); | ||||
|   EXPECT_EQ(7, *vresult[0]); | ||||
| 
 | ||||
|   std::unique_ptr<Base> result2 = mock.MakeUniqueBase(); | ||||
|   EXPECT_EQ(d, result2.get()); | ||||
| } | ||||
| 
 | ||||
| TEST(MockMethodTest, CanReturnMoveOnlyValue_DoAllReturn) { | ||||
|   testing::MockFunction<void()> mock_function; | ||||
|   MockClass mock; | ||||
|   std::unique_ptr<int> i(new int(19)); | ||||
|   EXPECT_CALL(mock_function, Call()); | ||||
|   EXPECT_CALL(mock, MakeUnique()).WillOnce(DoAll( | ||||
|       InvokeWithoutArgs(&mock_function, &testing::MockFunction<void()>::Call), | ||||
|       Return(ByMove(std::move(i))))); | ||||
| 
 | ||||
|   std::unique_ptr<int> result1 = mock.MakeUnique(); | ||||
|   EXPECT_EQ(19, *result1); | ||||
| } | ||||
| 
 | ||||
| TEST(MockMethodTest, CanReturnMoveOnlyValue_Invoke) { | ||||
|   MockClass mock; | ||||
| 
 | ||||
|   // Check default value
 | ||||
| @ -1294,8 +1331,7 @@ TEST(MockMethodTest, CanReturnMoveOnlyValue) { | ||||
|   }); | ||||
|   EXPECT_EQ(42, *mock.MakeUnique()); | ||||
| 
 | ||||
|   EXPECT_CALL(mock, MakeUnique()) | ||||
|       .WillRepeatedly(Invoke(UniquePtrSource)); | ||||
|   EXPECT_CALL(mock, MakeUnique()).WillRepeatedly(Invoke(UniquePtrSource)); | ||||
|   EXPECT_CALL(mock, MakeVectorUnique()) | ||||
|       .WillRepeatedly(Invoke(VectorUniquePtrSource)); | ||||
|   std::unique_ptr<int> result1 = mock.MakeUnique(); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user