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);
|
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
|
// Implements the polymorphic Return(x) action, which can be used in
|
||||||
// any function that returns the type of x, regardless of the argument
|
// any function that returns the type of x, regardless of the argument
|
||||||
// types.
|
// types.
|
||||||
@ -489,7 +497,7 @@ class ReturnAction {
|
|||||||
// Constructs a ReturnAction object from the value to be returned.
|
// Constructs a ReturnAction object from the value to be returned.
|
||||||
// 'value' is passed by value instead of by const reference in order
|
// 'value' is passed by value instead of by const reference in order
|
||||||
// to allow Return("string literal") to compile.
|
// 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
|
// This template type conversion operator allows Return(x) to be
|
||||||
// used in ANY function that returns x's type.
|
// 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.
|
// in the Impl class. But both definitions must be the same.
|
||||||
typedef typename Function<F>::Result Result;
|
typedef typename Function<F>::Result Result;
|
||||||
GTEST_COMPILE_ASSERT_(
|
GTEST_COMPILE_ASSERT_(
|
||||||
!internal::is_reference<Result>::value,
|
!is_reference<Result>::value,
|
||||||
use_ReturnRef_instead_of_Return_to_return_a_reference);
|
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:
|
private:
|
||||||
// Implements the Return(x) action for a particular function type F.
|
// Implements the Return(x) action for a particular function type F.
|
||||||
template <typename F>
|
template <typename R_, typename F>
|
||||||
class Impl : public ActionInterface<F> {
|
class Impl : public ActionInterface<F> {
|
||||||
public:
|
public:
|
||||||
typedef typename Function<F>::Result Result;
|
typedef typename Function<F>::Result Result;
|
||||||
@ -525,20 +533,45 @@ class ReturnAction {
|
|||||||
// Result to call. ImplicitCast_ forces the compiler to convert R to
|
// Result to call. ImplicitCast_ forces the compiler to convert R to
|
||||||
// Result without considering explicit constructors, thus resolving the
|
// Result without considering explicit constructors, thus resolving the
|
||||||
// ambiguity. value_ is then initialized using its copy constructor.
|
// ambiguity. value_ is then initialized using its copy constructor.
|
||||||
explicit Impl(R value)
|
explicit Impl(const linked_ptr<R>& value)
|
||||||
: value_(::testing::internal::ImplicitCast_<Result>(value)) {}
|
: value_(ImplicitCast_<Result>(*value)) {}
|
||||||
|
|
||||||
virtual Result Perform(const ArgumentTuple&) { return value_; }
|
virtual Result Perform(const ArgumentTuple&) { return value_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GTEST_COMPILE_ASSERT_(!internal::is_reference<Result>::value,
|
GTEST_COMPILE_ASSERT_(!is_reference<Result>::value,
|
||||||
Result_cannot_be_a_reference_type);
|
Result_cannot_be_a_reference_type);
|
||||||
Result value_;
|
Result value_;
|
||||||
|
|
||||||
GTEST_DISALLOW_ASSIGN_(Impl);
|
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);
|
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.
|
// will trigger a compiler error about using array as initializer.
|
||||||
template <typename R>
|
template <typename R>
|
||||||
internal::ReturnAction<R> Return(R value) {
|
internal::ReturnAction<R> Return(R value) {
|
||||||
return internal::ReturnAction<R>(value);
|
return internal::ReturnAction<R>(internal::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an action that returns NULL.
|
// Creates an action that returns NULL.
|
||||||
@ -1004,6 +1037,15 @@ inline internal::ReturnRefOfCopyAction<R> ReturnRefOfCopy(const R& x) {
|
|||||||
return internal::ReturnRefOfCopyAction<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.
|
// Creates an action that does the default action for the give mock function.
|
||||||
inline internal::DoDefaultAction DoDefault() {
|
inline internal::DoDefaultAction DoDefault() {
|
||||||
return internal::DoDefaultAction();
|
return internal::DoDefaultAction();
|
||||||
|
@ -1302,15 +1302,12 @@ template <typename T>
|
|||||||
class ReferenceOrValueWrapper {
|
class ReferenceOrValueWrapper {
|
||||||
public:
|
public:
|
||||||
// Constructs a wrapper from the given value/reference.
|
// Constructs a wrapper from the given value/reference.
|
||||||
explicit ReferenceOrValueWrapper(T value)
|
explicit ReferenceOrValueWrapper(T value) : value_(move(value)) {}
|
||||||
: value_(GTEST_MOVE_(value)) {}
|
|
||||||
|
|
||||||
// Unwraps and returns the underlying value/reference, exactly as
|
// Unwraps and returns the underlying value/reference, exactly as
|
||||||
// originally passed. The behavior of calling this more than once on
|
// originally passed. The behavior of calling this more than once on
|
||||||
// the same object is unspecified.
|
// the same object is unspecified.
|
||||||
T Unwrap() {
|
T Unwrap() { return move(value_); }
|
||||||
return GTEST_MOVE_(value_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provides nondestructive access to the underlying value/reference.
|
// Provides nondestructive access to the underlying value/reference.
|
||||||
// Always returns a const reference (more precisely,
|
// Always returns a const reference (more precisely,
|
||||||
@ -1407,8 +1404,7 @@ class ActionResultHolder : public UntypedActionResultHolderBase {
|
|||||||
private:
|
private:
|
||||||
typedef ReferenceOrValueWrapper<T> Wrapper;
|
typedef ReferenceOrValueWrapper<T> Wrapper;
|
||||||
|
|
||||||
explicit ActionResultHolder(Wrapper result)
|
explicit ActionResultHolder(Wrapper result) : result_(move(result)) {}
|
||||||
: result_(GTEST_MOVE_(result)) {}
|
|
||||||
|
|
||||||
Wrapper result_;
|
Wrapper result_;
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ using testing::_;
|
|||||||
using testing::Action;
|
using testing::Action;
|
||||||
using testing::ActionInterface;
|
using testing::ActionInterface;
|
||||||
using testing::Assign;
|
using testing::Assign;
|
||||||
|
using testing::ByMove;
|
||||||
using testing::ByRef;
|
using testing::ByRef;
|
||||||
using testing::DefaultValue;
|
using testing::DefaultValue;
|
||||||
using testing::DoDefault;
|
using testing::DoDefault;
|
||||||
@ -638,6 +639,7 @@ class MockClass {
|
|||||||
MOCK_METHOD0(Foo, MyClass());
|
MOCK_METHOD0(Foo, MyClass());
|
||||||
#if GTEST_HAS_STD_UNIQUE_PTR_
|
#if GTEST_HAS_STD_UNIQUE_PTR_
|
||||||
MOCK_METHOD0(MakeUnique, std::unique_ptr<int>());
|
MOCK_METHOD0(MakeUnique, std::unique_ptr<int>());
|
||||||
|
MOCK_METHOD0(MakeUniqueBase, std::unique_ptr<Base>());
|
||||||
MOCK_METHOD0(MakeVectorUnique, std::vector<std::unique_ptr<int>>());
|
MOCK_METHOD0(MakeVectorUnique, std::vector<std::unique_ptr<int>>());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1285,7 +1287,42 @@ std::vector<std::unique_ptr<int>> VectorUniquePtrSource() {
|
|||||||
return out;
|
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;
|
MockClass mock;
|
||||||
|
|
||||||
// Check default value
|
// Check default value
|
||||||
@ -1294,8 +1331,7 @@ TEST(MockMethodTest, CanReturnMoveOnlyValue) {
|
|||||||
});
|
});
|
||||||
EXPECT_EQ(42, *mock.MakeUnique());
|
EXPECT_EQ(42, *mock.MakeUnique());
|
||||||
|
|
||||||
EXPECT_CALL(mock, MakeUnique())
|
EXPECT_CALL(mock, MakeUnique()).WillRepeatedly(Invoke(UniquePtrSource));
|
||||||
.WillRepeatedly(Invoke(UniquePtrSource));
|
|
||||||
EXPECT_CALL(mock, MakeVectorUnique())
|
EXPECT_CALL(mock, MakeVectorUnique())
|
||||||
.WillRepeatedly(Invoke(VectorUniquePtrSource));
|
.WillRepeatedly(Invoke(VectorUniquePtrSource));
|
||||||
std::unique_ptr<int> result1 = mock.MakeUnique();
|
std::unique_ptr<int> result1 = mock.MakeUnique();
|
||||||
|
Loading…
Reference in New Issue
Block a user