mirror of
https://github.com/google/googletest.git
synced 2024-12-28 19:15:24 +08:00
Support mocking methods with move-only return types.
This commit is contained in:
parent
b93d0f10d5
commit
b5c81098a8
@ -163,18 +163,27 @@ class DefaultValue {
|
||||
// Sets the default value for type T; requires T to be
|
||||
// copy-constructable and have a public destructor.
|
||||
static void Set(T x) {
|
||||
delete value_;
|
||||
value_ = new T(x);
|
||||
delete producer_;
|
||||
producer_ = new FixedValueProducer(x);
|
||||
}
|
||||
|
||||
// Provides a factory function to be called to generate the default value.
|
||||
// This method can be used even if T is only move-constructible, but it is not
|
||||
// limited to that case.
|
||||
typedef T (*FactoryFunction)();
|
||||
static void SetFactory(FactoryFunction factory) {
|
||||
delete producer_;
|
||||
producer_ = new FactoryValueProducer(factory);
|
||||
}
|
||||
|
||||
// Unsets the default value for type T.
|
||||
static void Clear() {
|
||||
delete value_;
|
||||
value_ = NULL;
|
||||
delete producer_;
|
||||
producer_ = NULL;
|
||||
}
|
||||
|
||||
// Returns true iff the user has set the default value for type T.
|
||||
static bool IsSet() { return value_ != NULL; }
|
||||
static bool IsSet() { return producer_ != NULL; }
|
||||
|
||||
// Returns true if T has a default return value set by the user or there
|
||||
// exists a built-in default value.
|
||||
@ -183,15 +192,42 @@ class DefaultValue {
|
||||
}
|
||||
|
||||
// Returns the default value for type T if the user has set one;
|
||||
// otherwise returns the built-in default value if there is one;
|
||||
// otherwise aborts the process.
|
||||
// otherwise returns the built-in default value. Requires that Exists()
|
||||
// is true, which ensures that the return value is well-defined.
|
||||
static T Get() {
|
||||
return value_ == NULL ?
|
||||
internal::BuiltInDefaultValue<T>::Get() : *value_;
|
||||
return producer_ == NULL ?
|
||||
internal::BuiltInDefaultValue<T>::Get() : producer_->Produce();
|
||||
}
|
||||
|
||||
private:
|
||||
static const T* value_;
|
||||
class ValueProducer {
|
||||
public:
|
||||
virtual ~ValueProducer() {}
|
||||
virtual T Produce() = 0;
|
||||
};
|
||||
|
||||
class FixedValueProducer : public ValueProducer {
|
||||
public:
|
||||
explicit FixedValueProducer(T value) : value_(value) {}
|
||||
virtual T Produce() { return value_; }
|
||||
|
||||
private:
|
||||
const T value_;
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(FixedValueProducer);
|
||||
};
|
||||
|
||||
class FactoryValueProducer : public ValueProducer {
|
||||
public:
|
||||
explicit FactoryValueProducer(FactoryFunction factory)
|
||||
: factory_(factory) {}
|
||||
virtual T Produce() { return factory_(); }
|
||||
|
||||
private:
|
||||
const FactoryFunction factory_;
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(FactoryValueProducer);
|
||||
};
|
||||
|
||||
static ValueProducer* producer_;
|
||||
};
|
||||
|
||||
// This partial specialization allows a user to set default values for
|
||||
@ -241,7 +277,7 @@ class DefaultValue<void> {
|
||||
|
||||
// Points to the user-set default value for type T.
|
||||
template <typename T>
|
||||
const T* DefaultValue<T>::value_ = NULL;
|
||||
typename DefaultValue<T>::ValueProducer* DefaultValue<T>::producer_ = NULL;
|
||||
|
||||
// Points to the user-set default value for type T&.
|
||||
template <typename T>
|
||||
|
@ -211,7 +211,7 @@ class GTEST_API_ UntypedFunctionMockerBase {
|
||||
// arguments. This function can be safely called from multiple
|
||||
// threads concurrently. The caller is responsible for deleting the
|
||||
// result.
|
||||
const UntypedActionResultHolderBase* UntypedInvokeWith(
|
||||
UntypedActionResultHolderBase* UntypedInvokeWith(
|
||||
const void* untyped_args)
|
||||
GTEST_LOCK_EXCLUDED_(g_gmock_mutex);
|
||||
|
||||
@ -1289,6 +1289,58 @@ class MockSpec {
|
||||
GTEST_DISALLOW_ASSIGN_(MockSpec);
|
||||
}; // class MockSpec
|
||||
|
||||
// Wrapper type for generically holding an ordinary value or lvalue reference.
|
||||
// If T is not a reference type, it must be copyable or movable.
|
||||
// ReferenceOrValueWrapper<T> is movable, and will also be copyable unless
|
||||
// T is a move-only value type (which means that it will always be copyable
|
||||
// if the current platform does not support move semantics).
|
||||
//
|
||||
// The primary template defines handling for values, but function header
|
||||
// comments describe the contract for the whole template (including
|
||||
// specializations).
|
||||
template <typename T>
|
||||
class ReferenceOrValueWrapper {
|
||||
public:
|
||||
// Constructs a wrapper from the given value/reference.
|
||||
explicit ReferenceOrValueWrapper(T value)
|
||||
: value_(GTEST_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_);
|
||||
}
|
||||
|
||||
// Provides nondestructive access to the underlying value/reference.
|
||||
// Always returns a const reference (more precisely,
|
||||
// const RemoveReference<T>&). The behavior of calling this after
|
||||
// calling Unwrap on the same object is unspecified.
|
||||
const T& Peek() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
// Specialization for lvalue reference types. See primary template
|
||||
// for documentation.
|
||||
template <typename T>
|
||||
class ReferenceOrValueWrapper<T&> {
|
||||
public:
|
||||
// Workaround for debatable pass-by-reference lint warning (c-library-team
|
||||
// policy precludes NOLINT in this context)
|
||||
typedef T& reference;
|
||||
explicit ReferenceOrValueWrapper(reference ref)
|
||||
: value_ptr_(&ref) {}
|
||||
T& Unwrap() { return *value_ptr_; }
|
||||
const T& Peek() const { return *value_ptr_; }
|
||||
|
||||
private:
|
||||
T* value_ptr_;
|
||||
};
|
||||
|
||||
// MSVC warns about using 'this' in base member initializer list, so
|
||||
// we need to temporarily disable the warning. We have to do it for
|
||||
// the entire class to suppress the warning, even though it's about
|
||||
@ -1320,23 +1372,16 @@ class UntypedActionResultHolderBase {
|
||||
template <typename T>
|
||||
class ActionResultHolder : public UntypedActionResultHolderBase {
|
||||
public:
|
||||
explicit ActionResultHolder(T a_value) : value_(a_value) {}
|
||||
|
||||
// The compiler-generated copy constructor and assignment operator
|
||||
// are exactly what we need, so we don't need to define them.
|
||||
|
||||
// Returns the held value and deletes this object.
|
||||
T GetValueAndDelete() const {
|
||||
T retval(value_);
|
||||
delete this;
|
||||
return retval;
|
||||
// Returns the held value. Must not be called more than once.
|
||||
T Unwrap() {
|
||||
return result_.Unwrap();
|
||||
}
|
||||
|
||||
// Prints the held value as an action's result to os.
|
||||
virtual void PrintAsActionResult(::std::ostream* os) const {
|
||||
*os << "\n Returns: ";
|
||||
// T may be a reference type, so we don't use UniversalPrint().
|
||||
UniversalPrinter<T>::Print(value_, os);
|
||||
UniversalPrinter<T>::Print(result_.Peek(), os);
|
||||
}
|
||||
|
||||
// Performs the given mock function's default action and returns the
|
||||
@ -1346,8 +1391,8 @@ class ActionResultHolder : public UntypedActionResultHolderBase {
|
||||
const FunctionMockerBase<F>* func_mocker,
|
||||
const typename Function<F>::ArgumentTuple& args,
|
||||
const string& call_description) {
|
||||
return new ActionResultHolder(
|
||||
func_mocker->PerformDefaultAction(args, call_description));
|
||||
return new ActionResultHolder(Wrapper(
|
||||
func_mocker->PerformDefaultAction(args, call_description)));
|
||||
}
|
||||
|
||||
// Performs the given action and returns the result in a new-ed
|
||||
@ -1356,42 +1401,52 @@ class ActionResultHolder : public UntypedActionResultHolderBase {
|
||||
static ActionResultHolder*
|
||||
PerformAction(const Action<F>& action,
|
||||
const typename Function<F>::ArgumentTuple& args) {
|
||||
return new ActionResultHolder(action.Perform(args));
|
||||
return new ActionResultHolder(Wrapper(action.Perform(args)));
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
typedef ReferenceOrValueWrapper<T> Wrapper;
|
||||
|
||||
// T could be a reference type, so = isn't supported.
|
||||
GTEST_DISALLOW_ASSIGN_(ActionResultHolder);
|
||||
explicit ActionResultHolder(Wrapper result)
|
||||
: result_(GTEST_MOVE_(result)) {}
|
||||
|
||||
Wrapper result_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionResultHolder);
|
||||
};
|
||||
|
||||
// Specialization for T = void.
|
||||
template <>
|
||||
class ActionResultHolder<void> : public UntypedActionResultHolderBase {
|
||||
public:
|
||||
void GetValueAndDelete() const { delete this; }
|
||||
void Unwrap() { }
|
||||
|
||||
virtual void PrintAsActionResult(::std::ostream* /* os */) const {}
|
||||
|
||||
// Performs the given mock function's default action and returns NULL;
|
||||
// Performs the given mock function's default action and returns ownership
|
||||
// of an empty ActionResultHolder*.
|
||||
template <typename F>
|
||||
static ActionResultHolder* PerformDefaultAction(
|
||||
const FunctionMockerBase<F>* func_mocker,
|
||||
const typename Function<F>::ArgumentTuple& args,
|
||||
const string& call_description) {
|
||||
func_mocker->PerformDefaultAction(args, call_description);
|
||||
return NULL;
|
||||
return new ActionResultHolder;
|
||||
}
|
||||
|
||||
// Performs the given action and returns NULL.
|
||||
// Performs the given action and returns ownership of an empty
|
||||
// ActionResultHolder*.
|
||||
template <typename F>
|
||||
static ActionResultHolder* PerformAction(
|
||||
const Action<F>& action,
|
||||
const typename Function<F>::ArgumentTuple& args) {
|
||||
action.Perform(args);
|
||||
return NULL;
|
||||
return new ActionResultHolder;
|
||||
}
|
||||
|
||||
private:
|
||||
ActionResultHolder() {}
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionResultHolder);
|
||||
};
|
||||
|
||||
// The base of the function mocker class for the given function type.
|
||||
@ -1526,8 +1581,9 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
|
||||
// threads concurrently.
|
||||
Result InvokeWith(const ArgumentTuple& args)
|
||||
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
|
||||
return static_cast<const ResultHolder*>(
|
||||
this->UntypedInvokeWith(&args))->GetValueAndDelete();
|
||||
scoped_ptr<ResultHolder> holder(
|
||||
DownCast_<ResultHolder*>(this->UntypedInvokeWith(&args)));
|
||||
return holder->Unwrap();
|
||||
}
|
||||
|
||||
// Adds and returns a default action spec for this mock function.
|
||||
|
@ -361,17 +361,30 @@ template <typename T> struct DecayArray<T[]> {
|
||||
typedef const T* type;
|
||||
};
|
||||
|
||||
// Invalid<T>() returns an invalid value of type T. This is useful
|
||||
// Disable MSVC warnings for infinite recursion, since in this case the
|
||||
// the recursion is unreachable.
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4717)
|
||||
#endif
|
||||
|
||||
// Invalid<T>() is usable as an expression of type T, but will terminate
|
||||
// the program with an assertion failure if actually run. This is useful
|
||||
// when a value of type T is needed for compilation, but the statement
|
||||
// will not really be executed (or we don't care if the statement
|
||||
// crashes).
|
||||
template <typename T>
|
||||
inline T Invalid() {
|
||||
return const_cast<typename remove_reference<T>::type&>(
|
||||
*static_cast<volatile typename remove_reference<T>::type*>(NULL));
|
||||
Assert(false, "", -1, "Internal error: attempt to return invalid value");
|
||||
// This statement is unreachable, and would never terminate even if it
|
||||
// could be reached. It is provided only to placate compiler warnings
|
||||
// about missing return statements.
|
||||
return Invalid<T>();
|
||||
}
|
||||
template <>
|
||||
inline void Invalid<void>() {}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// Given a raw type (i.e. having no top-level reference or const
|
||||
// modifier) RawContainer that's either an STL-style container or a
|
||||
|
@ -332,7 +332,7 @@ const char* UntypedFunctionMockerBase::Name() const
|
||||
// Calculates the result of invoking this mock function with the given
|
||||
// arguments, prints it, and returns it. The caller is responsible
|
||||
// for deleting the result.
|
||||
const UntypedActionResultHolderBase*
|
||||
UntypedActionResultHolderBase*
|
||||
UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
|
||||
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
|
||||
if (untyped_expectations_.size() == 0) {
|
||||
@ -370,7 +370,7 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
|
||||
this->UntypedDescribeUninterestingCall(untyped_args, &ss);
|
||||
|
||||
// Calculates the function result.
|
||||
const UntypedActionResultHolderBase* const result =
|
||||
UntypedActionResultHolderBase* const result =
|
||||
this->UntypedPerformDefaultAction(untyped_args, ss.str());
|
||||
|
||||
// Prints the function result.
|
||||
@ -417,7 +417,7 @@ UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args)
|
||||
untyped_expectation->DescribeLocationTo(&loc);
|
||||
}
|
||||
|
||||
const UntypedActionResultHolderBase* const result =
|
||||
UntypedActionResultHolderBase* const result =
|
||||
untyped_action == NULL ?
|
||||
this->UntypedPerformDefaultAction(untyped_args, ss.str()) :
|
||||
this->UntypedPerformAction(untyped_action, untyped_args);
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "gmock/gmock-actions.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "gmock/gmock.h"
|
||||
#include "gmock/internal/gmock-port.h"
|
||||
@ -263,6 +264,21 @@ TEST(DefaultValueDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) {
|
||||
}, "");
|
||||
}
|
||||
|
||||
#if GTEST_LANG_CXX11
|
||||
TEST(DefaultValueDeathTest, GetWorksForMoveOnlyIfSet) {
|
||||
EXPECT_FALSE(DefaultValue<std::unique_ptr<int>>::Exists());
|
||||
EXPECT_DEATH_IF_SUPPORTED({
|
||||
DefaultValue<std::unique_ptr<int>>::Get();
|
||||
}, "");
|
||||
DefaultValue<std::unique_ptr<int>>::SetFactory([] {
|
||||
return std::unique_ptr<int>(new int(42));
|
||||
});
|
||||
EXPECT_TRUE(DefaultValue<std::unique_ptr<int>>::Exists());
|
||||
std::unique_ptr<int> i = DefaultValue<std::unique_ptr<int>>::Get();
|
||||
EXPECT_EQ(42, *i);
|
||||
}
|
||||
#endif // GTEST_LANG_CXX11
|
||||
|
||||
// Tests that DefaultValue<void>::Get() returns void.
|
||||
TEST(DefaultValueTest, GetWorksForVoid) {
|
||||
return DefaultValue<void>::Get();
|
||||
@ -620,6 +636,10 @@ class MockClass {
|
||||
|
||||
MOCK_METHOD1(IntFunc, int(bool flag)); // NOLINT
|
||||
MOCK_METHOD0(Foo, MyClass());
|
||||
#if GTEST_LANG_CXX11
|
||||
MOCK_METHOD0(MakeUnique, std::unique_ptr<int>());
|
||||
MOCK_METHOD0(MakeVectorUnique, std::vector<std::unique_ptr<int>>());
|
||||
#endif
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(MockClass);
|
||||
@ -1253,4 +1273,43 @@ TEST(ByRefTest, PrintsCorrectly) {
|
||||
EXPECT_EQ(expected.str(), actual.str());
|
||||
}
|
||||
|
||||
#if GTEST_LANG_CXX11
|
||||
|
||||
std::unique_ptr<int> UniquePtrSource() {
|
||||
return std::unique_ptr<int>(new int(19));
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<int>> VectorUniquePtrSource() {
|
||||
std::vector<std::unique_ptr<int>> out;
|
||||
out.emplace_back(new int(7));
|
||||
return out;
|
||||
}
|
||||
|
||||
TEST(MockMethodTest, CanReturnMoveOnlyValue) {
|
||||
MockClass mock;
|
||||
|
||||
// Check default value
|
||||
DefaultValue<std::unique_ptr<int>>::SetFactory([] {
|
||||
return std::unique_ptr<int>(new int(42));
|
||||
});
|
||||
EXPECT_EQ(42, *mock.MakeUnique());
|
||||
|
||||
EXPECT_CALL(mock, MakeUnique())
|
||||
.WillRepeatedly(Invoke(UniquePtrSource));
|
||||
EXPECT_CALL(mock, MakeVectorUnique())
|
||||
.WillRepeatedly(Invoke(VectorUniquePtrSource));
|
||||
std::unique_ptr<int> result1 = mock.MakeUnique();
|
||||
EXPECT_EQ(19, *result1);
|
||||
std::unique_ptr<int> result2 = mock.MakeUnique();
|
||||
EXPECT_EQ(19, *result2);
|
||||
EXPECT_NE(result1, result2);
|
||||
|
||||
std::vector<std::unique_ptr<int>> vresult = mock.MakeVectorUnique();
|
||||
EXPECT_EQ(1, vresult.size());
|
||||
EXPECT_NE(nullptr, vresult[0]);
|
||||
EXPECT_EQ(7, *vresult[0]);
|
||||
}
|
||||
|
||||
#endif // GTEST_LANG_CXX11
|
||||
|
||||
} // Unnamed namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user