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 class. +template +class NotMatcherImpl : public MatcherInterface { + public: + explicit NotMatcherImpl(const Matcher& 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 matcher_; +}; + // Implements the Not(m) matcher, which matches a value that doesn't // match matcher m. template @@ -975,38 +1000,74 @@ class NotMatcher { // to match any type m can match. template operator Matcher() const { - return Matcher(new Impl(matcher_)); + return Matcher(new NotMatcherImpl(SafeMatcherCast(matcher_))); } private: - // Implements the Not(...) matcher for a particular argument type T. - template - class Impl : public MatcherInterface { - public: - explicit Impl(InnerMatcher matcher) - : matcher_(SafeMatcherCast(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 matcher_; - }; - InnerMatcher matcher_; }; +// 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 class. +template +class BothOfMatcherImpl : public MatcherInterface { + public: + BothOfMatcherImpl(const Matcher& matcher1, const Matcher& matcher2) + : matcher1_(matcher1), matcher2_(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 << ") and ("; + 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)) { + // 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 matcher1_; + const Matcher matcher2_; +}; + // Used for implementing the AllOf(m_1, ..., m_n) matcher, which // matches a value that matches all of the matchers m_1, ..., and m_n. template @@ -1020,72 +1081,73 @@ class BothOfMatcher { // both Matcher1 and Matcher2 can match. template operator Matcher() const { - return Matcher(new Impl(matcher1_, matcher2_)); + return Matcher(new BothOfMatcherImpl(SafeMatcherCast(matcher1_), + SafeMatcherCast(matcher2_))); } private: - // Implements the AllOf(m1, m2) matcher for a particular argument - // type T. - template - class Impl : public MatcherInterface { - public: - Impl(Matcher1 matcher1, Matcher2 matcher2) - : matcher1_(SafeMatcherCast(matcher1)), - matcher2_(SafeMatcherCast(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 class. +template +class EitherOfMatcherImpl : public MatcherInterface { + public: + EitherOfMatcherImpl(const Matcher& matcher1, const Matcher& 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(); + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not "; + DescribeTo(os); + } - ::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 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 matcher1_; - const Matcher matcher2_; - }; - - Matcher1 matcher1_; - Matcher2 matcher2_; + } + private: + const Matcher matcher1_; + const Matcher 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 operator Matcher() const { - return Matcher(new Impl(matcher1_, matcher2_)); + return Matcher(new EitherOfMatcherImpl(SafeMatcherCast(matcher1_), + SafeMatcherCast(matcher2_))); } private: - // Implements the AnyOf(m1, m2) matcher for a particular argument - // type T. - template - class Impl : public MatcherInterface { - public: - Impl(Matcher1 matcher1, Matcher2 matcher2) - : matcher1_(SafeMatcherCast(matcher1)), - matcher2_(SafeMatcherCast(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 matcher1_; - const Matcher 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 -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 -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(p); + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template +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 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(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(0), is_pointer(), 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 -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(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(0); } +#if GTEST_HAS_RTTI assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! +#endif return static_cast(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(proto_buffer) sets the variable -// pointed to by the N-th (0-based) argument to proto_buffer. +// Tests that SetArgumentPointee(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 a = SetArgumentPointee<1>(*msg); + Action a = SetArgumentPointee<1>(*msg); // SetArgumentPointee(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(proto2_buffer) sets the variable -// pointed to by the N-th (0-based) argument to proto2_buffer. +// Tests that SetArgumentPointee(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 a = SetArgumentPointee<1>(*msg); + // SetArgumentPointee(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(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 a = SetArgumentPointee<1>(*msg); + Action a = SetArgumentPointee<1>(*msg); // SetArgumentPointee(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(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 a = SetArgumentPointee<1>(*msg); + // SetArgumentPointee(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(first, last) sets the elements of the array