aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@8415998a-534a-0410-bf83-d39667b30386>2009-05-13 23:38:40 +0000
committerzhanyong.wan <zhanyong.wan@8415998a-534a-0410-bf83-d39667b30386>2009-05-13 23:38:40 +0000
commitc6a412397bc98f120d5e79d4a64e3972854b5af3 (patch)
treef36e9c70faf270aa9f4516110345e01778088e87
parent18490653e80d484b4650d8799184fd1e021efc7b (diff)
downloadgoogletest-c6a412397bc98f120d5e79d4a64e3972854b5af3.tar.gz
googletest-c6a412397bc98f120d5e79d4a64e3972854b5af3.tar.bz2
googletest-c6a412397bc98f120d5e79d4a64e3972854b5af3.zip
Adds more tests for using SetArgumentPointee with protobufs; works around a compiler bug on Symbian that gmock-printers.h triggers; reduces template code bloat in gmock-matchers.h; avoids RTTI when it's disabled.
-rw-r--r--include/gmock/gmock-matchers.h291
-rw-r--r--include/gmock/gmock-printers.h64
-rw-r--r--include/gmock/internal/gmock-port.h2
-rw-r--r--test/gmock-actions_test.cc64
4 files changed, 245 insertions, 176 deletions
diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h
index 5700fb25..bf049d45 100644
--- a/include/gmock/gmock-matchers.h
+++ b/include/gmock/gmock-matchers.h
@@ -960,10 +960,35 @@ GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "not equal to");
#undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
-// TODO(vladl@google.com): Move Impl outside of NotMatcher and rename it
-// NotMatcherImpl to reduce compilation overhead and the size of the binary.
-// This also applies to BothOfMatcher::Impl and EitherOfMatcher::Impl.
-//
+// Implements the Not(...) matcher for a particular argument type T.
+// We do not nest it inside the NotMatcher class template, as that
+// will prevent different instantiations of NotMatcher from sharing
+// the same NotMatcherImpl<T> class.
+template <typename T>
+class NotMatcherImpl : public MatcherInterface<T> {
+ public:
+ explicit NotMatcherImpl(const Matcher<T>& matcher)
+ : matcher_(matcher) {}
+
+ virtual bool Matches(T x) const {
+ return !matcher_.Matches(x);
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ matcher_.DescribeNegationTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ matcher_.DescribeTo(os);
+ }
+
+ virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
+ matcher_.ExplainMatchResultTo(x, os);
+ }
+ private:
+ const Matcher<T> matcher_;
+};
+
// Implements the Not(m) matcher, which matches a value that doesn't
// match matcher m.
template <typename InnerMatcher>
@@ -975,36 +1000,72 @@ class NotMatcher {
// to match any type m can match.
template <typename T>
operator Matcher<T>() const {
- return Matcher<T>(new Impl<T>(matcher_));
+ return Matcher<T>(new NotMatcherImpl<T>(SafeMatcherCast<T>(matcher_)));
}
private:
- // Implements the Not(...) matcher for a particular argument type T.
- template <typename T>
- class Impl : public MatcherInterface<T> {
- public:
- explicit Impl(InnerMatcher matcher)
- : matcher_(SafeMatcherCast<T>(matcher)) {}
+ InnerMatcher matcher_;
+};
- virtual bool Matches(T x) const {
- return !matcher_.Matches(x);
- }
+// Implements the AllOf(m1, m2) matcher for a particular argument type
+// T. We do not nest it inside the BothOfMatcher class template, as
+// that will prevent different instantiations of BothOfMatcher from
+// sharing the same BothOfMatcherImpl<T> class.
+template <typename T>
+class BothOfMatcherImpl : public MatcherInterface<T> {
+ public:
+ BothOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2)
+ : matcher1_(matcher1), matcher2_(matcher2) {}
- virtual void DescribeTo(::std::ostream* os) const {
- matcher_.DescribeNegationTo(os);
- }
+ virtual bool Matches(T x) const {
+ return matcher1_.Matches(x) && matcher2_.Matches(x);
+ }
- virtual void DescribeNegationTo(::std::ostream* os) const {
- matcher_.DescribeTo(os);
- }
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "(";
+ matcher1_.DescribeTo(os);
+ *os << ") and (";
+ matcher2_.DescribeTo(os);
+ *os << ")";
+ }
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- matcher_.ExplainMatchResultTo(x, os);
- }
- private:
- const Matcher<T> matcher_;
- };
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "not ";
+ DescribeTo(os);
+ }
- InnerMatcher matcher_;
+ virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
+ if (Matches(x)) {
+ // When both matcher1_ and matcher2_ match x, we need to
+ // explain why *both* of them match.
+ ::std::stringstream ss1;
+ matcher1_.ExplainMatchResultTo(x, &ss1);
+ const internal::string s1 = ss1.str();
+
+ ::std::stringstream ss2;
+ matcher2_.ExplainMatchResultTo(x, &ss2);
+ const internal::string s2 = ss2.str();
+
+ if (s1 == "") {
+ *os << s2;
+ } else {
+ *os << s1;
+ if (s2 != "") {
+ *os << "; " << s2;
+ }
+ }
+ } else {
+ // Otherwise we only need to explain why *one* of them fails
+ // to match.
+ if (!matcher1_.Matches(x)) {
+ matcher1_.ExplainMatchResultTo(x, os);
+ } else {
+ matcher2_.ExplainMatchResultTo(x, os);
+ }
+ }
+ }
+ private:
+ const Matcher<T> matcher1_;
+ const Matcher<T> matcher2_;
};
// Used for implementing the AllOf(m_1, ..., m_n) matcher, which
@@ -1020,72 +1081,73 @@ class BothOfMatcher {
// both Matcher1 and Matcher2 can match.
template <typename T>
operator Matcher<T>() const {
- return Matcher<T>(new Impl<T>(matcher1_, matcher2_));
+ return Matcher<T>(new BothOfMatcherImpl<T>(SafeMatcherCast<T>(matcher1_),
+ SafeMatcherCast<T>(matcher2_)));
}
private:
- // Implements the AllOf(m1, m2) matcher for a particular argument
- // type T.
- template <typename T>
- class Impl : public MatcherInterface<T> {
- public:
- Impl(Matcher1 matcher1, Matcher2 matcher2)
- : matcher1_(SafeMatcherCast<T>(matcher1)),
- matcher2_(SafeMatcherCast<T>(matcher2)) {}
+ Matcher1 matcher1_;
+ Matcher2 matcher2_;
+};
- virtual bool Matches(T x) const {
- return matcher1_.Matches(x) && matcher2_.Matches(x);
- }
+// Implements the AnyOf(m1, m2) matcher for a particular argument type
+// T. We do not nest it inside the AnyOfMatcher class template, as
+// that will prevent different instantiations of AnyOfMatcher from
+// sharing the same EitherOfMatcherImpl<T> class.
+template <typename T>
+class EitherOfMatcherImpl : public MatcherInterface<T> {
+ public:
+ EitherOfMatcherImpl(const Matcher<T>& matcher1, const Matcher<T>& matcher2)
+ : matcher1_(matcher1), matcher2_(matcher2) {}
- virtual void DescribeTo(::std::ostream* os) const {
- *os << "(";
- matcher1_.DescribeTo(os);
- *os << ") and (";
- matcher2_.DescribeTo(os);
- *os << ")";
- }
+ virtual bool Matches(T x) const {
+ return matcher1_.Matches(x) || matcher2_.Matches(x);
+ }
- virtual void DescribeNegationTo(::std::ostream* os) const {
- *os << "not ";
- DescribeTo(os);
- }
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "(";
+ matcher1_.DescribeTo(os);
+ *os << ") or (";
+ matcher2_.DescribeTo(os);
+ *os << ")";
+ }
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- if (Matches(x)) {
- // When both matcher1_ and matcher2_ match x, we need to
- // explain why *both* of them match.
- ::std::stringstream ss1;
- matcher1_.ExplainMatchResultTo(x, &ss1);
- const internal::string s1 = ss1.str();
-
- ::std::stringstream ss2;
- matcher2_.ExplainMatchResultTo(x, &ss2);
- const internal::string s2 = ss2.str();
-
- if (s1 == "") {
- *os << s2;
- } else {
- *os << s1;
- if (s2 != "") {
- *os << "; " << s2;
- }
- }
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "not ";
+ DescribeTo(os);
+ }
+
+ virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
+ if (Matches(x)) {
+ // If either matcher1_ or matcher2_ matches x, we just need
+ // to explain why *one* of them matches.
+ if (matcher1_.Matches(x)) {
+ matcher1_.ExplainMatchResultTo(x, os);
} else {
- // Otherwise we only need to explain why *one* of them fails
- // to match.
- if (!matcher1_.Matches(x)) {
- matcher1_.ExplainMatchResultTo(x, os);
- } else {
- matcher2_.ExplainMatchResultTo(x, os);
+ matcher2_.ExplainMatchResultTo(x, os);
+ }
+ } else {
+ // Otherwise we need to explain why *neither* matches.
+ ::std::stringstream ss1;
+ matcher1_.ExplainMatchResultTo(x, &ss1);
+ const internal::string s1 = ss1.str();
+
+ ::std::stringstream ss2;
+ matcher2_.ExplainMatchResultTo(x, &ss2);
+ const internal::string s2 = ss2.str();
+
+ if (s1 == "") {
+ *os << s2;
+ } else {
+ *os << s1;
+ if (s2 != "") {
+ *os << "; " << s2;
}
}
}
- private:
- const Matcher<T> matcher1_;
- const Matcher<T> matcher2_;
- };
-
- Matcher1 matcher1_;
- Matcher2 matcher2_;
+ }
+ private:
+ const Matcher<T> matcher1_;
+ const Matcher<T> matcher2_;
};
// Used for implementing the AnyOf(m_1, ..., m_n) matcher, which
@@ -1102,69 +1164,10 @@ class EitherOfMatcher {
// both Matcher1 and Matcher2 can match.
template <typename T>
operator Matcher<T>() const {
- return Matcher<T>(new Impl<T>(matcher1_, matcher2_));
+ return Matcher<T>(new EitherOfMatcherImpl<T>(SafeMatcherCast<T>(matcher1_),
+ SafeMatcherCast<T>(matcher2_)));
}
private:
- // Implements the AnyOf(m1, m2) matcher for a particular argument
- // type T.
- template <typename T>
- class Impl : public MatcherInterface<T> {
- public:
- Impl(Matcher1 matcher1, Matcher2 matcher2)
- : matcher1_(SafeMatcherCast<T>(matcher1)),
- matcher2_(SafeMatcherCast<T>(matcher2)) {}
-
- virtual bool Matches(T x) const {
- return matcher1_.Matches(x) || matcher2_.Matches(x);
- }
-
- virtual void DescribeTo(::std::ostream* os) const {
- *os << "(";
- matcher1_.DescribeTo(os);
- *os << ") or (";
- matcher2_.DescribeTo(os);
- *os << ")";
- }
-
- virtual void DescribeNegationTo(::std::ostream* os) const {
- *os << "not ";
- DescribeTo(os);
- }
-
- virtual void ExplainMatchResultTo(T x, ::std::ostream* os) const {
- if (Matches(x)) {
- // If either matcher1_ or matcher2_ matches x, we just need
- // to explain why *one* of them matches.
- if (matcher1_.Matches(x)) {
- matcher1_.ExplainMatchResultTo(x, os);
- } else {
- matcher2_.ExplainMatchResultTo(x, os);
- }
- } else {
- // Otherwise we need to explain why *neither* matches.
- ::std::stringstream ss1;
- matcher1_.ExplainMatchResultTo(x, &ss1);
- const internal::string s1 = ss1.str();
-
- ::std::stringstream ss2;
- matcher2_.ExplainMatchResultTo(x, &ss2);
- const internal::string s2 = ss2.str();
-
- if (s1 == "") {
- *os << s2;
- } else {
- *os << s1;
- if (s2 != "") {
- *os << "; " << s2;
- }
- }
- }
- }
- private:
- const Matcher<T> matcher1_;
- const Matcher<T> matcher2_;
- };
-
Matcher1 matcher1_;
Matcher2 matcher2_;
};
diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h
index bbe44c38..6997a6c1 100644
--- a/include/gmock/gmock-printers.h
+++ b/include/gmock/gmock-printers.h
@@ -211,7 +211,9 @@ class UniversalPrinter;
// Used to print an STL-style container when the user doesn't define
// a PrintTo() for it.
template <typename C>
-void DefaultPrintTo(IsContainer, const C& container, ::std::ostream* os) {
+void DefaultPrintTo(IsContainer /* dummy */,
+ false_type /* is not a pointer */,
+ const C& container, ::std::ostream* os) {
const size_t kMaxCount = 32; // The maximum number of elements to print.
*os << '{';
size_t count = 0;
@@ -234,9 +236,31 @@ void DefaultPrintTo(IsContainer, const C& container, ::std::ostream* os) {
*os << '}';
}
-// Used to print a value when the user doesn't define PrintTo() for it.
+// Used to print a pointer that is neither a char pointer nor a member
+// pointer, when the user doesn't define PrintTo() for it. (A member
+// variable pointer or member function pointer doesn't really point to
+// a location in the address space. Their representation is
+// implementation-defined. Therefore they will be printed as raw
+// bytes.)
template <typename T>
-void DefaultPrintTo(IsNotContainer, const T& value, ::std::ostream* os) {
+void DefaultPrintTo(IsNotContainer /* dummy */,
+ true_type /* is a pointer */,
+ T* p, ::std::ostream* os) {
+ if (p == NULL) {
+ *os << "NULL";
+ } else {
+ // We cannot use implicit_cast or static_cast here, as they don't
+ // work when p is a function pointer.
+ *os << reinterpret_cast<const void*>(p);
+ }
+}
+
+// Used to print a non-container, non-pointer value when the user
+// doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+ false_type /* is not a pointer */,
+ const T& value, ::std::ostream* os) {
::testing_internal::DefaultPrintNonContainerTo(value, os);
}
@@ -253,10 +277,11 @@ void DefaultPrintTo(IsNotContainer, const T& value, ::std::ostream* os) {
// wants).
template <typename T>
void PrintTo(const T& value, ::std::ostream* os) {
- // DefaultPrintTo() is overloaded. The type of its first argument
- // determines which version will be picked. If T is an STL-style
- // container, the version for container will be called. Otherwise
- // the generic version will be called.
+ // DefaultPrintTo() is overloaded. The type of its first two
+ // arguments determine which version will be picked. If T is an
+ // STL-style container, the version for container will be called; if
+ // T is a pointer, the pointer version will be called; otherwise the
+ // generic version will be called.
//
// Note that we check for container types here, prior to we check
// for protocol message types in our operator<<. The rationale is:
@@ -267,7 +292,14 @@ void PrintTo(const T& value, ::std::ostream* os) {
// incompatible with Google Mock's format for the container
// elements; therefore we check for container types here to ensure
// that our format is used.
- DefaultPrintTo(IsContainerTest<T>(0), value, os);
+ //
+ // The second argument of DefaultPrintTo() is needed to bypass a bug
+ // in Symbian's C++ compiler that prevents it from picking the right
+ // overload between:
+ //
+ // PrintTo(const T& x, ...);
+ // PrintTo(T* x, ...);
+ DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
}
// The following list of PrintTo() overloads tells
@@ -323,22 +355,6 @@ inline void PrintTo(wchar_t* s, ::std::ostream* os) {
}
#endif
-// Overload for pointers that are neither char pointers nor member
-// pointers. (A member variable pointer or member function pointer
-// doesn't really points to a location in the address space. Their
-// representation is implementation-defined. Therefore they will be
-// printed as raw bytes.)
-template <typename T>
-void PrintTo(T* p, ::std::ostream* os) {
- if (p == NULL) {
- *os << "NULL";
- } else {
- // We cannot use implicit_cast or static_cast here, as they don't
- // work when p is a function pointer.
- *os << reinterpret_cast<const void*>(p);
- }
-}
-
// Overload for C arrays. Multi-dimensional arrays are printed
// properly.
diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h
index d242c8e4..75be9edd 100644
--- a/include/gmock/internal/gmock-port.h
+++ b/include/gmock/internal/gmock-port.h
@@ -162,7 +162,9 @@ inline To down_cast(From* f) { // so we only accept pointers
implicit_cast<From*, To>(0);
}
+#if GTEST_HAS_RTTI
assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
+#endif
return static_cast<To>(f);
}
diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc
index e4939e1a..24462609 100644
--- a/test/gmock-actions_test.cc
+++ b/test/gmock-actions_test.cc
@@ -646,16 +646,15 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointee) {
#if GMOCK_HAS_PROTOBUF_
-// Tests that SetArgumentPointee<N>(proto_buffer) sets the variable
-// pointed to by the N-th (0-based) argument to proto_buffer.
+// Tests that SetArgumentPointee<N>(proto_buffer) sets the v1 protobuf
+// variable pointed to by the N-th (0-based) argument to proto_buffer.
TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProtoBufferType) {
- typedef void MyFunction(bool, TestMessage*);
TestMessage* const msg = new TestMessage;
msg->set_member("yes");
TestMessage orig_msg;
orig_msg.CopyFrom(*msg);
- Action<MyFunction> a = SetArgumentPointee<1>(*msg);
+ Action<void(bool, TestMessage*)> a = SetArgumentPointee<1>(*msg);
// SetArgumentPointee<N>(proto_buffer) makes a copy of proto_buffer
// s.t. the action works even when the original proto_buffer has
// died. We ensure this behavior by deleting msg before using the
@@ -668,18 +667,41 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProtoBufferType) {
EXPECT_TRUE(orig_msg.Equals(dest));
}
-// Tests that SetArgumentPointee<N>(proto2_buffer) sets the variable
-// pointed to by the N-th (0-based) argument to proto2_buffer.
+// Tests that SetArgumentPointee<N>(proto_buffer) sets the
+// ::ProtocolMessage variable pointed to by the N-th (0-based)
+// argument to proto_buffer.
+TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProtoBufferBaseType) {
+ TestMessage* const msg = new TestMessage;
+ msg->set_member("yes");
+ TestMessage orig_msg;
+ orig_msg.CopyFrom(*msg);
+
+ Action<void(bool, ::ProtocolMessage*)> a = SetArgumentPointee<1>(*msg);
+ // SetArgumentPointee<N>(proto_buffer) makes a copy of proto_buffer
+ // s.t. the action works even when the original proto_buffer has
+ // died. We ensure this behavior by deleting msg before using the
+ // action.
+ delete msg;
+
+ TestMessage dest;
+ ::ProtocolMessage* const dest_base = &dest;
+ EXPECT_FALSE(orig_msg.Equals(dest));
+ a.Perform(make_tuple(true, dest_base));
+ EXPECT_TRUE(orig_msg.Equals(dest));
+}
+
+// Tests that SetArgumentPointee<N>(proto2_buffer) sets the v2
+// protobuf variable pointed to by the N-th (0-based) argument to
+// proto2_buffer.
TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferType) {
using testing::internal::FooMessage;
- typedef void MyFunction(bool, FooMessage*);
FooMessage* const msg = new FooMessage;
msg->set_int_field(2);
msg->set_string_field("hi");
FooMessage orig_msg;
orig_msg.CopyFrom(*msg);
- Action<MyFunction> a = SetArgumentPointee<1>(*msg);
+ Action<void(bool, FooMessage*)> a = SetArgumentPointee<1>(*msg);
// SetArgumentPointee<N>(proto2_buffer) makes a copy of
// proto2_buffer s.t. the action works even when the original
// proto2_buffer has died. We ensure this behavior by deleting msg
@@ -693,6 +715,32 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferType) {
EXPECT_EQ("hi", dest.string_field());
}
+// Tests that SetArgumentPointee<N>(proto2_buffer) sets the
+// proto2::Message variable pointed to by the N-th (0-based) argument
+// to proto2_buffer.
+TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferBaseType) {
+ using testing::internal::FooMessage;
+ FooMessage* const msg = new FooMessage;
+ msg->set_int_field(2);
+ msg->set_string_field("hi");
+ FooMessage orig_msg;
+ orig_msg.CopyFrom(*msg);
+
+ Action<void(bool, ::proto2::Message*)> a = SetArgumentPointee<1>(*msg);
+ // SetArgumentPointee<N>(proto2_buffer) makes a copy of
+ // proto2_buffer s.t. the action works even when the original
+ // proto2_buffer has died. We ensure this behavior by deleting msg
+ // before using the action.
+ delete msg;
+
+ FooMessage dest;
+ dest.set_int_field(0);
+ ::proto2::Message* const dest_base = &dest;
+ a.Perform(make_tuple(true, dest_base));
+ EXPECT_EQ(2, dest.int_field());
+ EXPECT_EQ("hi", dest.string_field());
+}
+
#endif // GMOCK_HAS_PROTOBUF_
// Tests that SetArrayArgument<N>(first, last) sets the elements of the array