diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 83143510..8b68fc7c 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -459,6 +459,14 @@ class ActionAdaptor : public ActionInterface { 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 +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::Result Result; GTEST_COMPILE_ASSERT_( - !internal::is_reference::value, + !is_reference::value, use_ReturnRef_instead_of_Return_to_return_a_reference); - return Action(new Impl(value_)); + return Action(new Impl(value_)); } private: // Implements the Return(x) action for a particular function type F. - template + template class Impl : public ActionInterface { public: typedef typename Function::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_(value)) {} + explicit Impl(const linked_ptr& value) + : value_(ImplicitCast_(*value)) {} virtual Result Perform(const ArgumentTuple&) { return value_; } private: - GTEST_COMPILE_ASSERT_(!internal::is_reference::value, + GTEST_COMPILE_ASSERT_(!is_reference::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 + class Impl, F> : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const linked_ptr& 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 wrapper_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + const linked_ptr value_; GTEST_DISALLOW_ASSIGN_(ReturnAction); }; @@ -977,7 +1010,7 @@ Action::Action(const Action& from) // will trigger a compiler error about using array as initializer. template internal::ReturnAction Return(R value) { - return internal::ReturnAction(value); + return internal::ReturnAction(internal::move(value)); } // Creates an action that returns NULL. @@ -1004,6 +1037,15 @@ inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { return internal::ReturnRefOfCopyAction(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 +internal::ByMoveWrapper ByMove(R x) { + return internal::ByMoveWrapper(internal::move(x)); +} + // Creates an action that does the default action for the give mock function. inline internal::DoDefaultAction DoDefault() { return internal::DoDefaultAction(); diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 63655b91..61e140e4 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -1302,15 +1302,12 @@ template 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 Wrapper; - explicit ActionResultHolder(Wrapper result) - : result_(GTEST_MOVE_(result)) {} + explicit ActionResultHolder(Wrapper result) : result_(move(result)) {} Wrapper result_; diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 2345a64f..ea09bfc9 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -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()); + MOCK_METHOD0(MakeUniqueBase, std::unique_ptr()); MOCK_METHOD0(MakeVectorUnique, std::vector>()); #endif @@ -1285,7 +1287,42 @@ std::vector> VectorUniquePtrSource() { return out; } -TEST(MockMethodTest, CanReturnMoveOnlyValue) { +TEST(MockMethodTest, CanReturnMoveOnlyValue_Return) { + MockClass mock; + std::unique_ptr 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(d)))); + + std::unique_ptr result1 = mock.MakeUnique(); + EXPECT_EQ(19, *result1); + + std::vector> vresult = mock.MakeVectorUnique(); + EXPECT_EQ(1, vresult.size()); + EXPECT_NE(nullptr, vresult[0]); + EXPECT_EQ(7, *vresult[0]); + + std::unique_ptr result2 = mock.MakeUniqueBase(); + EXPECT_EQ(d, result2.get()); +} + +TEST(MockMethodTest, CanReturnMoveOnlyValue_DoAllReturn) { + testing::MockFunction mock_function; + MockClass mock; + std::unique_ptr i(new int(19)); + EXPECT_CALL(mock_function, Call()); + EXPECT_CALL(mock, MakeUnique()).WillOnce(DoAll( + InvokeWithoutArgs(&mock_function, &testing::MockFunction::Call), + Return(ByMove(std::move(i))))); + + std::unique_ptr 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 result1 = mock.MakeUnique();