diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 9fe19644..ddaaef24 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -584,6 +584,55 @@ class ReturnRefAction { GTEST_DISALLOW_ASSIGN_(ReturnRefAction); }; +// Implements the polymorphic ReturnRefOfCopy(x) action, which can be +// used in any function that returns a reference to the type of x, +// regardless of the argument types. +template +class ReturnRefOfCopyAction { + public: + // Constructs a ReturnRefOfCopyAction object from the reference to + // be returned. + explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT + + // This template type conversion operator allows ReturnRefOfCopy(x) to be + // used in ANY function that returns a reference to x's type. + template + operator Action() const { + typedef typename Function::Result Result; + // Asserts that the function return type is a reference. This + // catches the user error of using ReturnRefOfCopy(x) when Return(x) + // should be used, and generates some helpful error message. + GTEST_COMPILE_ASSERT_( + internal::is_reference::value, + use_Return_instead_of_ReturnRefOfCopy_to_return_a_value); + return Action(new Impl(value_)); + } + + private: + // Implements the ReturnRefOfCopy(x) action for a particular function type F. + template + class Impl : public ActionInterface { + public: + typedef typename Function::Result Result; + typedef typename Function::ArgumentTuple ArgumentTuple; + + explicit Impl(const T& value) : value_(value) {} // NOLINT + + virtual Result Perform(const ArgumentTuple&) { + return value_; + } + + private: + T value_; + + GTEST_DISALLOW_ASSIGN_(Impl); + }; + + const T value_; + + GTEST_DISALLOW_ASSIGN_(ReturnRefOfCopyAction); +}; + // Implements the DoDefault() action for a particular function type F. template class MonomorphicDoDefaultActionImpl : public ActionInterface { @@ -948,6 +997,14 @@ inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT return internal::ReturnRefAction(x); } +// Creates an action that returns the reference to a copy of the +// argument. The copy is created when the action is constructed and +// lives as long as the action. +template +inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { + return internal::ReturnRefOfCopyAction(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-more-actions.h b/include/gmock/gmock-more-actions.h index 6d686cd1..c60557e6 100644 --- a/include/gmock/gmock-more-actions.h +++ b/include/gmock/gmock-more-actions.h @@ -195,6 +195,9 @@ ACTION_TEMPLATE(DeleteArg, delete ::std::tr1::get(args); } +// This action returns the value pointed to by 'pointer'. +ACTION_P(ReturnPointee, pointer) { return *pointer; } + // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 8391e5fe..50cc6f98 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -68,6 +68,7 @@ using testing::PolymorphicAction; using testing::Return; using testing::ReturnNull; using testing::ReturnRef; +using testing::ReturnRefOfCopy; using testing::SetArgumentPointee; #if !GTEST_OS_WINDOWS_MOBILE @@ -584,6 +585,30 @@ TEST(ReturnRefTest, IsCovariant) { EXPECT_EQ(&derived, &a.Perform(make_tuple())); } +// Tests that ReturnRefOfCopy(v) works for reference types. +TEST(ReturnRefOfCopyTest, WorksForReference) { + int n = 42; + const Action ret = ReturnRefOfCopy(n); + + EXPECT_NE(&n, &ret.Perform(make_tuple())); + EXPECT_EQ(42, ret.Perform(make_tuple())); + + n = 43; + EXPECT_NE(&n, &ret.Perform(make_tuple())); + EXPECT_EQ(42, ret.Perform(make_tuple())); +} + +// Tests that ReturnRefOfCopy(v) is covariant. +TEST(ReturnRefOfCopyTest, IsCovariant) { + Base base; + Derived derived; + Action a = ReturnRefOfCopy(base); + EXPECT_NE(&base, &a.Perform(make_tuple())); + + a = ReturnRefOfCopy(derived); + EXPECT_NE(&derived, &a.Perform(make_tuple())); +} + // Tests that DoDefault() does the default action for the mock method. class MyClass {}; diff --git a/test/gmock-more-actions_test.cc b/test/gmock-more-actions_test.cc index b3b17d33..be7b1273 100644 --- a/test/gmock-more-actions_test.cc +++ b/test/gmock-more-actions_test.cc @@ -57,6 +57,7 @@ using testing::DeleteArg; using testing::Invoke; using testing::Return; using testing::ReturnArg; +using testing::ReturnPointee; using testing::SaveArg; using testing::SetArgReferee; using testing::SetArgumentPointee; @@ -664,5 +665,14 @@ TEST(SetArrayArgumentTest, SetsTheNthArrayWithIteratorArgument) { EXPECT_EQ(letters, s); } +TEST(ReturnPointeeTest, Works) { + int n = 42; + const Action a = ReturnPointee(&n); + EXPECT_EQ(42, a.Perform(make_tuple())); + + n = 43; + EXPECT_EQ(43, a.Perform(make_tuple())); +} + } // namespace gmock_generated_actions_test } // namespace testing