diff options
| author | kosak <kosak@google.com> | 2014-11-17 00:56:52 +0000 | 
|---|---|---|
| committer | kosak <kosak@google.com> | 2014-11-17 00:56:52 +0000 | 
| commit | 3d1c78b2bff05a794b037b99766640f8f2b19855 (patch) | |
| tree | 765defbcd845a423820fec748cbb48ed51ccc425 | |
| parent | 5b9cbbb16d774bfcb51572d52eda3f7319088e23 (diff) | |
| download | googletest-3d1c78b2bff05a794b037b99766640f8f2b19855.tar.gz googletest-3d1c78b2bff05a794b037b99766640f8f2b19855.tar.bz2 googletest-3d1c78b2bff05a794b037b99766640f8f2b19855.zip | |
Add ByMove() modifier for the Return() action. Pull in gtest 695.
| -rw-r--r-- | include/gmock/gmock-actions.h | 60 | ||||
| -rw-r--r-- | include/gmock/gmock-spec-builders.h | 10 | ||||
| -rw-r--r-- | test/gmock-actions_test.cc | 42 | 
3 files changed, 93 insertions, 19 deletions
| 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<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(); 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 <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_; 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<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(); | 
