diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 7e9708ec..d08152a8 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -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::Get() : *value_; + return producer_ == NULL ? + internal::BuiltInDefaultValue::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 { // Points to the user-set default value for type T. template -const T* DefaultValue::value_ = NULL; +typename DefaultValue::ValueProducer* DefaultValue::producer_ = NULL; // Points to the user-set default value for type T&. template diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 312fbe87..63655b91 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -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 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 +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&). 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 +class ReferenceOrValueWrapper { + 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 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::Print(value_, os); + UniversalPrinter::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* func_mocker, const typename Function::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& action, const typename Function::ArgumentTuple& args) { - return new ActionResultHolder(action.Perform(args)); + return new ActionResultHolder(Wrapper(action.Perform(args))); } private: - T value_; + typedef ReferenceOrValueWrapper 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 : 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 static ActionResultHolder* PerformDefaultAction( const FunctionMockerBase* func_mocker, const typename Function::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 static ActionResultHolder* PerformAction( const Action& action, const typename Function::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( - this->UntypedInvokeWith(&args))->GetValueAndDelete(); + scoped_ptr holder( + DownCast_(this->UntypedInvokeWith(&args))); + return holder->Unwrap(); } // Adds and returns a default action spec for this mock function. diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index e12b7d7d..2f530d4e 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -361,17 +361,30 @@ template struct DecayArray { typedef const T* type; }; -// Invalid() 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() 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 inline T Invalid() { - return const_cast::type&>( - *static_cast::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(); } -template <> -inline void Invalid() {} + +#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 diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index cefb580f..a74f9e57 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -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); diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 8cd77e20..115a9020 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -36,6 +36,7 @@ #include "gmock/gmock-actions.h" #include #include +#include #include #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>::Exists()); + EXPECT_DEATH_IF_SUPPORTED({ + DefaultValue>::Get(); + }, ""); + DefaultValue>::SetFactory([] { + return std::unique_ptr(new int(42)); + }); + EXPECT_TRUE(DefaultValue>::Exists()); + std::unique_ptr i = DefaultValue>::Get(); + EXPECT_EQ(42, *i); +} +#endif // GTEST_LANG_CXX11 + // Tests that DefaultValue::Get() returns void. TEST(DefaultValueTest, GetWorksForVoid) { return DefaultValue::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()); + MOCK_METHOD0(MakeVectorUnique, std::vector>()); +#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 UniquePtrSource() { + return std::unique_ptr(new int(19)); +} + +std::vector> VectorUniquePtrSource() { + std::vector> out; + out.emplace_back(new int(7)); + return out; +} + +TEST(MockMethodTest, CanReturnMoveOnlyValue) { + MockClass mock; + + // Check default value + DefaultValue>::SetFactory([] { + return std::unique_ptr(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 result1 = mock.MakeUnique(); + EXPECT_EQ(19, *result1); + std::unique_ptr result2 = mock.MakeUnique(); + EXPECT_EQ(19, *result2); + EXPECT_NE(result1, result2); + + std::vector> vresult = mock.MakeVectorUnique(); + EXPECT_EQ(1, vresult.size()); + EXPECT_NE(nullptr, vresult[0]); + EXPECT_EQ(7, *vresult[0]); +} + +#endif // GTEST_LANG_CXX11 + } // Unnamed namespace