diff options
-rw-r--r-- | googlemock/include/gmock/gmock-actions.h | 90 | ||||
-rw-r--r-- | googlemock/test/gmock-actions_test.cc | 144 |
2 files changed, 216 insertions, 18 deletions
diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index 90fd2ea..a2784f6 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -360,14 +360,20 @@ class Action { // Constructs a null Action. Needed for storing Action objects in // STL containers. - Action() : impl_(NULL) {} + Action() {} - // Constructs an Action from its implementation. A NULL impl is - // used to represent the "do-default" action. - explicit Action(ActionInterface<F>* impl) : impl_(impl) {} +#if GTEST_LANG_CXX11 + // Construct an Action from a specified callable. + // This cannot take std::function directly, because then Action would not be + // directly constructible from lambda (it would require two conversions). + template <typename G, + typename = typename ::std::enable_if< + ::std::is_constructible<::std::function<F>, G>::value>::type> + Action(G&& fun) : fun_(::std::forward<G>(fun)) {} // NOLINT +#endif - // Copy constructor. - Action(const Action& action) : impl_(action.impl_) {} + // Constructs an Action from its implementation. + explicit Action(ActionInterface<F>* impl) : impl_(impl) {} // This constructor allows us to turn an Action<Func> object into an // Action<F>, as long as F's arguments can be implicitly converted @@ -377,7 +383,13 @@ class Action { explicit Action(const Action<Func>& action); // Returns true iff this is the DoDefault() action. - bool IsDoDefault() const { return impl_.get() == NULL; } + bool IsDoDefault() const { +#if GTEST_LANG_CXX11 + return impl_ == nullptr && fun_ == nullptr; +#else + return impl_ == NULL; +#endif + } // Performs the action. Note that this method is const even though // the corresponding method in ActionInterface is not. The reason @@ -385,14 +397,15 @@ class Action { // another concrete action, not that the concrete action it binds to // cannot change state. (Think of the difference between a const // pointer and a pointer to const.) - Result Perform(const ArgumentTuple& args) const { - internal::Assert( - !IsDoDefault(), __FILE__, __LINE__, - "You are using DoDefault() inside a composite action like " - "DoAll() or WithArgs(). This is not supported for technical " - "reasons. Please instead spell out the default action, or " - "assign the default action to an Action variable and use " - "the variable in various places."); + Result Perform(ArgumentTuple args) const { + if (IsDoDefault()) { + internal::IllegalDoDefault(__FILE__, __LINE__); + } +#if GTEST_LANG_CXX11 + if (fun_ != nullptr) { + return internal::Apply(fun_, ::std::move(args)); + } +#endif return impl_->Perform(args); } @@ -400,6 +413,18 @@ class Action { template <typename F1, typename F2> friend class internal::ActionAdaptor; + template <typename G> + friend class Action; + + // In C++11, Action can be implemented either as a generic functor (through + // std::function), or legacy ActionInterface. In C++98, only ActionInterface + // is available. The invariants are as follows: + // * in C++98, impl_ is null iff this is the default action + // * in C++11, at most one of fun_ & impl_ may be nonnull; both are null iff + // this is the default action +#if GTEST_LANG_CXX11 + ::std::function<F> fun_; +#endif internal::linked_ptr<ActionInterface<F> > impl_; }; @@ -531,6 +556,9 @@ struct ByMoveWrapper { // statement, and conversion of the result of Return to Action<T(U)> is a // good place for that. // +// The real life example of the above scenario happens when an invocation +// of gtl::Container() is passed into Return. +// template <typename R> class ReturnAction { public: @@ -750,7 +778,7 @@ class DoDefaultAction { // This template type conversion operator allows DoDefault() to be // used in any function. template <typename F> - operator Action<F>() const { return Action<F>(NULL); } + operator Action<F>() const { return Action<F>(); } // NOLINT }; // Implements the Assign action to set a given pointer referent to a @@ -886,6 +914,28 @@ class InvokeMethodWithoutArgsAction { GTEST_DISALLOW_ASSIGN_(InvokeMethodWithoutArgsAction); }; +// Implements the InvokeWithoutArgs(callback) action. +template <typename CallbackType> +class InvokeCallbackWithoutArgsAction { + public: + // The c'tor takes ownership of the callback. + explicit InvokeCallbackWithoutArgsAction(CallbackType* callback) + : callback_(callback) { + callback->CheckIsRepeatable(); // Makes sure the callback is permanent. + } + + // This type conversion operator template allows Invoke(callback) to + // be used wherever the callback's return type can be implicitly + // converted to that of the mock function. + template <typename Result, typename ArgumentTuple> + Result Perform(const ArgumentTuple&) const { return callback_->Run(); } + + private: + const internal::linked_ptr<CallbackType> callback_; + + GTEST_DISALLOW_ASSIGN_(InvokeCallbackWithoutArgsAction); +}; + // Implements the IgnoreResult(action) action. template <typename A> class IgnoreResultAction { @@ -1053,7 +1103,13 @@ typedef internal::IgnoredValue Unused; template <typename To> template <typename From> Action<To>::Action(const Action<From>& from) - : impl_(new internal::ActionAdaptor<To, From>(from)) {} + : +#if GTEST_LANG_CXX11 + fun_(from.fun_), +#endif + impl_(from.impl_ == NULL ? NULL + : new internal::ActionAdaptor<To, From>(from)) { +} // Creates an action that returns 'value'. 'value' is passed by value // instead of const reference - otherwise Return("string literal") diff --git a/googlemock/test/gmock-actions_test.cc b/googlemock/test/gmock-actions_test.cc index 4601157..ea6129d 100644 --- a/googlemock/test/gmock-actions_test.cc +++ b/googlemock/test/gmock-actions_test.cc @@ -65,6 +65,7 @@ using testing::ReturnRef; using testing::ReturnRefOfCopy; using testing::SetArgPointee; using testing::SetArgumentPointee; +using testing::Unused; using testing::_; using testing::get; using testing::internal::BuiltInDefaultValue; @@ -705,6 +706,8 @@ class MockClass { MOCK_METHOD0(MakeUniqueBase, std::unique_ptr<Base>()); MOCK_METHOD0(MakeVectorUnique, std::vector<std::unique_ptr<int>>()); MOCK_METHOD1(TakeUnique, int(std::unique_ptr<int>)); + MOCK_METHOD2(TakeUnique, + int(const std::unique_ptr<int>&, std::unique_ptr<int>)); #endif private: @@ -756,7 +759,7 @@ TEST(DoDefaultDeathTest, DiesIfUsedInCompositeAction) { } // Tests that DoDefault() returns the default value set by -// DefaultValue<T>::Set() when it's not overridden by an ON_CALL(). +// DefaultValue<T>::Set() when it's not overriden by an ON_CALL(). TEST(DoDefaultTest, ReturnsUserSpecifiedPerTypeDefaultValueWhenThereIsOne) { DefaultValue<int>::Set(1); MockClass mock; @@ -1411,6 +1414,145 @@ TEST(MockMethodTest, CanReturnMoveOnlyValue_Invoke) { EXPECT_EQ(7, *vresult[0]); } +TEST(MockMethodTest, CanTakeMoveOnlyValue) { + MockClass mock; + auto make = [](int i) { return std::unique_ptr<int>(new int(i)); }; + + EXPECT_CALL(mock, TakeUnique(_)).WillRepeatedly([](std::unique_ptr<int> i) { + return *i; + }); + // DoAll() does not compile, since it would move from its arguments twice. + // EXPECT_CALL(mock, TakeUnique(_, _)) + // .WillRepeatedly(DoAll(Invoke([](std::unique_ptr<int> j) {}), + // Return(1))); + EXPECT_CALL(mock, TakeUnique(testing::Pointee(7))) + .WillOnce(Return(-7)) + .RetiresOnSaturation(); + EXPECT_CALL(mock, TakeUnique(testing::IsNull())) + .WillOnce(Return(-1)) + .RetiresOnSaturation(); + + EXPECT_EQ(5, mock.TakeUnique(make(5))); + EXPECT_EQ(-7, mock.TakeUnique(make(7))); + EXPECT_EQ(7, mock.TakeUnique(make(7))); + EXPECT_EQ(7, mock.TakeUnique(make(7))); + EXPECT_EQ(-1, mock.TakeUnique({})); + + // Some arguments are moved, some passed by reference. + auto lvalue = make(6); + EXPECT_CALL(mock, TakeUnique(_, _)) + .WillOnce([](const std::unique_ptr<int>& i, std::unique_ptr<int> j) { + return *i * *j; + }); + EXPECT_EQ(42, mock.TakeUnique(lvalue, make(7))); + + // The unique_ptr can be saved by the action. + std::unique_ptr<int> saved; + EXPECT_CALL(mock, TakeUnique(_)).WillOnce([&saved](std::unique_ptr<int> i) { + saved = std::move(i); + return 0; + }); + EXPECT_EQ(0, mock.TakeUnique(make(42))); + EXPECT_EQ(42, *saved); +} + #endif // GTEST_HAS_STD_UNIQUE_PTR_ +#if GTEST_LANG_CXX11 +// Tests for std::function based action. + +int Add(int val, int& ref, int* ptr) { // NOLINT + int result = val + ref + *ptr; + ref = 42; + *ptr = 43; + return result; +} + +int Deref(std::unique_ptr<int> ptr) { return *ptr; } + +struct Double { + template <typename T> + T operator()(T t) { return 2 * t; } +}; + +std::unique_ptr<int> UniqueInt(int i) { + return std::unique_ptr<int>(new int(i)); +} + +TEST(FunctorActionTest, ActionFromFunction) { + Action<int(int, int&, int*)> a = &Add; + int x = 1, y = 2, z = 3; + EXPECT_EQ(6, a.Perform(std::forward_as_tuple(x, y, &z))); + EXPECT_EQ(42, y); + EXPECT_EQ(43, z); + + Action<int(std::unique_ptr<int>)> a1 = &Deref; + EXPECT_EQ(7, a1.Perform(std::make_tuple(UniqueInt(7)))); +} + +TEST(FunctorActionTest, ActionFromLambda) { + Action<int(bool, int)> a1 = [](bool b, int i) { return b ? i : 0; }; + EXPECT_EQ(5, a1.Perform(make_tuple(true, 5))); + EXPECT_EQ(0, a1.Perform(make_tuple(false, 5))); + + std::unique_ptr<int> saved; + Action<void(std::unique_ptr<int>)> a2 = [&saved](std::unique_ptr<int> p) { + saved = std::move(p); + }; + a2.Perform(make_tuple(UniqueInt(5))); + EXPECT_EQ(5, *saved); +} + +TEST(FunctorActionTest, PolymorphicFunctor) { + Action<int(int)> ai = Double(); + EXPECT_EQ(2, ai.Perform(make_tuple(1))); + Action<double(double)> ad = Double(); // Double? Double double! + EXPECT_EQ(3.0, ad.Perform(make_tuple(1.5))); +} + +TEST(FunctorActionTest, TypeConversion) { + // Numeric promotions are allowed. + const Action<bool(int)> a1 = [](int i) { return i > 1; }; + const Action<int(bool)> a2 = Action<int(bool)>(a1); + EXPECT_EQ(1, a1.Perform(make_tuple(42))); + EXPECT_EQ(0, a2.Perform(make_tuple(42))); + + // Implicit constructors are allowed. + const Action<bool(std::string)> s1 = [](std::string s) { return !s.empty(); }; + const Action<int(const char*)> s2 = Action<int(const char*)>(s1); + EXPECT_EQ(0, s2.Perform(make_tuple(""))); + EXPECT_EQ(1, s2.Perform(make_tuple("hello"))); + + // Also between the lambda and the action itself. + const Action<bool(std::string)> x = [](Unused) { return 42; }; + EXPECT_TRUE(x.Perform(make_tuple("hello"))); +} + +TEST(FunctorActionTest, UnusedArguments) { + // Verify that users can ignore uninteresting arguments. + Action<int(int, std::unique_ptr<int>, const int&)> a = + [](int i, Unused, Unused) { return 2 * i; }; + EXPECT_EQ(6, a.Perform(make_tuple(3, UniqueInt(7), 9))); +} + +// Test that basic built-in actions work with move-only arguments. +// TODO(rburny): Currently, almost all ActionInterface-based actions will not +// work, even if they only try to use other, copyable arguments. Implement them +// if necessary (but note that DoAll cannot work on non-copyable types anyway - +// so maybe it's better to make users use lambdas instead. +TEST(MoveOnlyArgumentsTest, ReturningActions) { + Action<int(std::unique_ptr<int>)> a = Return(1); + EXPECT_EQ(1, a.Perform(make_tuple(nullptr))); + + a = testing::WithoutArgs([]() { return 7; }); + EXPECT_EQ(7, a.Perform(make_tuple(nullptr))); + + Action<void(std::unique_ptr<int>, int*)> a2 = testing::SetArgPointee<1>(3); + int x = 0; + a2.Perform(make_tuple(nullptr, &x)); + EXPECT_EQ(x, 3); +} + +#endif // GTEST_LANG_CXX11 + } // Unnamed namespace |