aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gmock/gmock-actions.h58
-rw-r--r--include/gmock/gmock-spec-builders.h106
-rw-r--r--include/gmock/internal/gmock-internal-utils.h23
-rw-r--r--src/gmock-spec-builders.cc6
-rw-r--r--test/gmock-actions_test.cc59
5 files changed, 208 insertions, 44 deletions
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<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>
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<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.
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 <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
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 <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