aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkosak <kosak@google.com>2014-11-17 00:56:52 +0000
committerkosak <kosak@google.com>2014-11-17 00:56:52 +0000
commit3d1c78b2bff05a794b037b99766640f8f2b19855 (patch)
tree765defbcd845a423820fec748cbb48ed51ccc425
parent5b9cbbb16d774bfcb51572d52eda3f7319088e23 (diff)
downloadgoogletest-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.h60
-rw-r--r--include/gmock/gmock-spec-builders.h10
-rw-r--r--test/gmock-actions_test.cc42
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();