aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvladlosev <vladlosev@8415998a-534a-0410-bf83-d39667b30386>2009-11-18 00:09:28 +0000
committervladlosev <vladlosev@8415998a-534a-0410-bf83-d39667b30386>2009-11-18 00:09:28 +0000
commita070cbd91c2a8bfe7caed64e31387312a1c5df5a (patch)
tree048a0d8d6d709491210b43bd66bc2f987b88833b
parent2871bb4d34117aad6e3c30e9fa094c06bece51fc (diff)
downloadgoogletest-a070cbd91c2a8bfe7caed64e31387312a1c5df5a.tar.gz
googletest-a070cbd91c2a8bfe7caed64e31387312a1c5df5a.tar.bz2
googletest-a070cbd91c2a8bfe7caed64e31387312a1c5df5a.zip
Enables gmock's implicit_cast to work with source types that
-rw-r--r--include/gmock/gmock-actions.h37
-rw-r--r--test/gmock-actions_test.cc47
2 files changed, 81 insertions, 3 deletions
diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h
index 7f21a7d4..214b2912 100644
--- a/include/gmock/gmock-actions.h
+++ b/include/gmock/gmock-actions.h
@@ -310,7 +310,7 @@ class Action {
// This constructor allows us to turn an Action<Func> object into an
// Action<F>, as long as F's arguments can be implicitly converted
- // to Func's and Func's return type cann be implicitly converted to
+ // to Func's and Func's return type can be implicitly converted to
// F's.
template <typename Func>
explicit Action(const Action<Func>& action);
@@ -425,6 +425,27 @@ class ActionAdaptor : public ActionInterface<F1> {
// Implements the polymorphic Return(x) action, which can be used in
// any function that returns the type of x, regardless of the argument
// types.
+//
+// Note: The value passed into Return must be converted into
+// Function<F>::Result when this action is cast to Action<F> rather than
+// when that action is performed. This is important in scenarios like
+//
+// MOCK_METHOD1(Method, T(U));
+// ...
+// {
+// Foo foo;
+// X x(&foo);
+// EXPECT_CALL(mock, Method(_)).WillOnce(Return(x));
+// }
+//
+// In the example above the variable x holds reference to foo which leaves
+// scope and gets destroyed. If copying X just copies a reference to foo,
+// that copy will be left with a hanging reference. If conversion to T
+// makes a copy of foo, the above code is safe. To support that scenario, we
+// need to make sure that the type conversion happens inside the EXPECT_CALL
+// statement, and conversion of the result of Return to Action<T(U)> is a
+// good place for that.
+//
template <typename R>
class ReturnAction {
public:
@@ -459,12 +480,22 @@ class ReturnAction {
typedef typename Function<F>::Result Result;
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
- explicit Impl(R value) : value_(value) {}
+ // The implicit cast is necessary when Result has more than one
+ // single-argument constructor (e.g. Result is std::vector<int>) and R
+ // has a type conversion operator template. In that case, value_(value)
+ // won't compile as the compiler doesn't known which constructor of
+ // Result to call. implicit_cast forces the compiler to convert R to
+ // Result without considering explicit constructors, thus resolving the
+ // ambiguity. value_ is then initialized using its copy constructor.
+ explicit Impl(R value)
+ : value_(::testing::internal::implicit_cast<Result>(value)) {}
virtual Result Perform(const ArgumentTuple&) { return value_; }
private:
- R value_;
+ GMOCK_COMPILE_ASSERT_(!internal::is_reference<Result>::value,
+ Result_cannot_be_a_reference_type);
+ Result value_;
};
R value_;
diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc
index d3d96c6d..e2b1d052 100644
--- a/test/gmock-actions_test.cc
+++ b/test/gmock-actions_test.cc
@@ -515,6 +515,53 @@ TEST(ReturnTest, IsCovariant) {
EXPECT_EQ(&derived, ret.Perform(make_tuple()));
}
+// Tests that the type of the value passed into Return is converted into T
+// when the action is cast to Action<T(...)> rather than when the action is
+// performed. See comments on testing::internal::ReturnAction in
+// gmock-actions.h for more information.
+class FromType {
+ public:
+ FromType(bool* converted) : converted_(converted) {}
+ bool* converted() const { return converted_; }
+
+ private:
+ bool* const converted_;
+};
+
+class ToType {
+ public:
+ ToType(const FromType& x) { *x.converted() = true; }
+};
+
+TEST(ReturnTest, ConvertsArgumentWhenConverted) {
+ bool converted = false;
+ FromType x(&converted);
+ Action<ToType()> action(Return(x));
+ EXPECT_TRUE(converted) << "Return must convert its argument in its own "
+ << "conversion operator.";
+ converted = false;
+ action.Perform(tuple<>());
+ EXPECT_FALSE(converted) << "Action must NOT convert its argument "
+ << "when performed." ;
+}
+
+// We do not support non-const type conversions on Symbian. See
+// definition of implicit_cast in gmock-port.h for more information.
+#if !GTEST_OS_SYMBIAN
+class DestinationType {};
+
+class SourceType {
+ public:
+ // Note: a non-const typecast operator.
+ operator DestinationType() { return DestinationType(); }
+};
+
+TEST(ReturnTest, CanConvertArgumentUsingNonConstTypeCastOperator) {
+ SourceType s;
+ Action<DestinationType()> action(Return(s));
+}
+#endif // !GTEST_OS_SYMBIAN
+
// Tests that ReturnNull() returns NULL in a pointer-returning function.
TEST(ReturnNullTest, WorksInPointerReturningFunction) {
const Action<int*()> a1 = ReturnNull();