aboutsummaryrefslogtreecommitdiffstats
path: root/googlemock
diff options
context:
space:
mode:
authorGennadiy Civil <misterg@google.com>2018-04-06 09:50:01 -0400
committerGennadiy Civil <misterg@google.com>2018-04-06 09:50:01 -0400
commit88fc7d7552ead9d9c224b06bf0d2c1f17e21d612 (patch)
tree832ecade1c5bda02cfead76c97a4036642dade92 /googlemock
parentbee1d13fcc71b1c0d557fd71498015408ba506f8 (diff)
downloadgoogletest-88fc7d7552ead9d9c224b06bf0d2c1f17e21d612.tar.gz
googletest-88fc7d7552ead9d9c224b06bf0d2c1f17e21d612.tar.bz2
googletest-88fc7d7552ead9d9c224b06bf0d2c1f17e21d612.zip
merging gmock-actions 2
Diffstat (limited to 'googlemock')
-rw-r--r--googlemock/include/gmock/gmock-actions.h90
-rw-r--r--googlemock/test/gmock-actions_test.cc144
2 files changed, 216 insertions, 18 deletions
diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h
index 90fd2ea6..a2784f63 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 46011570..ea6129d7 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