diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/gmock/gmock-matchers.h | 152 | ||||
-rw-r--r-- | include/gmock/gmock-printers.h | 48 |
2 files changed, 104 insertions, 96 deletions
diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index 8dba440a..9a1bab24 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -453,6 +453,38 @@ Matcher<T> A(); // and MUST NOT BE USED IN USER CODE!!! namespace internal { +// If the explanation is not empty, prints it to the listener. +// 'listener' must not be NULL. +inline void PrintIfNotEmpty( + const internal::string& explanation, MatchResultListener* listener) { + if (explanation != "") { + *listener << ", " << explanation; + } +} + +// Matches the value against the given matcher, prints the value and explains +// the match result to the listener. Returns the match result. +// 'listener' must not be NULL. +// Value cannot be passed by const reference, because some matchers take a +// non-const argument. +template <typename Value, typename T> +bool MatchPrintAndExplain(Value& value, const Matcher<T>& matcher, + MatchResultListener* listener) { + if (!listener->IsInterested()) { + // If the listener is not interested, we do not need to construct the + // inner explanation. + return matcher.Matches(value); + } + + StringMatchResultListener inner_listener; + const bool match = matcher.MatchAndExplain(value, &inner_listener); + + UniversalPrint(value, listener->stream()); + PrintIfNotEmpty(inner_listener.str(), listener); + + return match; +} + // If the given string is not empty and os is not NULL, wraps the // string inside a pair of parentheses and streams the result to os. inline void StreamInParensAsNeeded(const internal::string& str, @@ -1604,13 +1636,8 @@ class PointeeMatcher { if (GetRawPointer(pointer) == NULL) return false; - StringMatchResultListener inner_listener; - const bool match = matcher_.MatchAndExplain(*pointer, &inner_listener); - const internal::string s = inner_listener.str(); - if (s != "") { - *listener << "points to a value that " << s; - } - return match; + *listener << "which points to "; + return MatchPrintAndExplain(*pointer, matcher_, listener); } private: @@ -1634,12 +1661,12 @@ class FieldMatcher { : field_(field), matcher_(matcher) {} void DescribeTo(::std::ostream* os) const { - *os << "the given field "; + *os << "is an object whose given field "; matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "the given field "; + *os << "is an object whose given field "; matcher_.DescribeNegationTo(os); } @@ -1657,13 +1684,8 @@ class FieldMatcher { // true_type iff the Field() matcher is used to match a pointer. bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj, MatchResultListener* listener) const { - StringMatchResultListener inner_listener; - const bool match = matcher_.MatchAndExplain(obj.*field_, &inner_listener); - const internal::string s = inner_listener.str(); - if (s != "") { - *listener << "the given field " << s; - } - return match; + *listener << "whose given field is "; + return MatchPrintAndExplain(obj.*field_, matcher_, listener); } bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p, @@ -1671,6 +1693,7 @@ class FieldMatcher { if (p == NULL) return false; + *listener << "which points to an object "; // Since *p has a field, it must be a class/struct/union type and // thus cannot be a pointer. Therefore we pass false_type() as // the first argument. @@ -1699,12 +1722,12 @@ class PropertyMatcher { : property_(property), matcher_(matcher) {} void DescribeTo(::std::ostream* os) const { - *os << "the given property "; + *os << "is an object whose given property "; matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "the given property "; + *os << "is an object whose given property "; matcher_.DescribeNegationTo(os); } @@ -1722,14 +1745,11 @@ class PropertyMatcher { // true_type iff the Property() matcher is used to match a pointer. bool MatchAndExplainImpl(false_type /* is_not_pointer */, const Class& obj, MatchResultListener* listener) const { - StringMatchResultListener inner_listener; - const bool match = matcher_.MatchAndExplain((obj.*property_)(), - &inner_listener); - const internal::string s = inner_listener.str(); - if (s != "") { - *listener << "the given property " << s; - } - return match; + *listener << "whose given property is "; + // Cannot pass the return value (for example, int) to MatchPrintAndExplain, + // which takes a non-const reference as argument. + RefToConstProperty result = (obj.*property_)(); + return MatchPrintAndExplain(result, matcher_, listener); } bool MatchAndExplainImpl(true_type /* is_pointer */, const Class* p, @@ -1737,6 +1757,7 @@ class PropertyMatcher { if (p == NULL) return false; + *listener << "which points to an object "; // Since *p has a property method, it must be a class/struct/union // type and thus cannot be a pointer. Therefore we pass // false_type() as the first argument. @@ -1806,26 +1827,22 @@ class ResultOfMatcher { : callable_(callable), matcher_(matcher) {} virtual void DescribeTo(::std::ostream* os) const { - *os << "result of the given callable "; + *os << "is mapped by the given callable to a value that "; matcher_.DescribeTo(os); } virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "result of the given callable "; + *os << "is mapped by the given callable to a value that "; matcher_.DescribeNegationTo(os); } virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const { - StringMatchResultListener inner_listener; - const bool match = matcher_.MatchAndExplain( - CallableTraits<Callable>::template Invoke<T>(callable_, obj), - &inner_listener); - - const internal::string s = inner_listener.str(); - if (s != "") - *listener << "result of the given callable " << s; - - return match; + *listener << "which is mapped by the given callable to "; + // Cannot pass the return value (for example, int) to + // MatchPrintAndExplain, which takes a non-const reference as argument. + ResultType result = + CallableTraits<Callable>::template Invoke<T>(callable_, obj); + return MatchPrintAndExplain(result, matcher_, listener); } private: @@ -2098,39 +2115,50 @@ class PairMatcherImpl : public MatcherInterface<PairType> { // matches second_matcher. virtual bool MatchAndExplain(PairType a_pair, MatchResultListener* listener) const { - StringMatchResultListener listener1; - const bool match1 = first_matcher_.MatchAndExplain(a_pair.first, - &listener1); - internal::string s1 = listener1.str(); - if (s1 != "") { - s1 = "the first field " + s1; + if (!listener->IsInterested()) { + // If the listener is not interested, we don't need to construct the + // explanation. + return first_matcher_.Matches(a_pair.first) && + second_matcher_.Matches(a_pair.second); } - if (!match1) { - *listener << s1; + StringMatchResultListener first_inner_listener; + if (!first_matcher_.MatchAndExplain(a_pair.first, + &first_inner_listener)) { + *listener << "whose first field does not match"; + PrintIfNotEmpty(first_inner_listener.str(), listener); return false; } - - StringMatchResultListener listener2; - const bool match2 = second_matcher_.MatchAndExplain(a_pair.second, - &listener2); - internal::string s2 = listener2.str(); - if (s2 != "") { - s2 = "the second field " + s2; - } - if (!match2) { - *listener << s2; + StringMatchResultListener second_inner_listener; + if (!second_matcher_.MatchAndExplain(a_pair.second, + &second_inner_listener)) { + *listener << "whose second field does not match"; + PrintIfNotEmpty(second_inner_listener.str(), listener); return false; } - - *listener << s1; - if (s1 != "" && s2 != "") { - *listener << ", and "; - } - *listener << s2; + ExplainSuccess(first_inner_listener.str(), second_inner_listener.str(), + listener); return true; } private: + void ExplainSuccess(const internal::string& first_explanation, + const internal::string& second_explanation, + MatchResultListener* listener) const { + *listener << "whose both fields match"; + if (first_explanation != "") { + *listener << ", where the first field is a value " << first_explanation; + } + if (second_explanation != "") { + *listener << ", "; + if (first_explanation != "") { + *listener << "and "; + } else { + *listener << "where "; + } + *listener << "the second field is a value " << second_explanation; + } + } + const Matcher<const FirstType&> first_matcher_; const Matcher<const SecondType&> second_matcher_; diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h index cda3545a..d1cd03ca 100644 --- a/include/gmock/gmock-printers.h +++ b/include/gmock/gmock-printers.h @@ -57,18 +57,20 @@ // // We also provide some convenient wrappers: // -// // Prints a value as the given type to a string. -// string ::testing::internal::UniversalPrinter<T>::PrintToString(value); +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); // // // Prints a value tersely: for a reference type, the referenced -// // value (but not the address) is printed; for a (const) char +// // value (but not the address) is printed; for a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // void ::testing::internal::UniversalTersePrint(const T& value, ostream*); // // // Prints value using the type inferred by the compiler. The difference // // from UniversalTersePrint() is that this function prints both the -// // pointer and the NUL-terminated string for a (const) char pointer. +// // pointer and the NUL-terminated string for a (const or not) char pointer. // void ::testing::internal::UniversalPrint(const T& value, ostream*); // // // Prints the fields of a tuple tersely to a string vector, one @@ -545,14 +547,6 @@ class UniversalPrinter { PrintTo(value, os); } - // A convenient wrapper for Print() that returns the print-out as a - // string. - static string PrintToString(const T& value) { - ::std::stringstream ss; - Print(value, &ss); - return ss.str(); - } - #ifdef _MSC_VER #pragma warning(pop) // Restores the warning state. #endif // _MSC_VER @@ -585,14 +579,6 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // This overload prints a (const) char array compactly. void UniversalPrintArray(const char* begin, size_t len, ::std::ostream* os); -// Prints an array of 'len' elements, starting at address 'begin', to a string. -template <typename T> -string UniversalPrintArrayToString(const T* begin, size_t len) { - ::std::stringstream ss; - UniversalPrintArray(begin, len, &ss); - return ss.str(); -} - // Implements printing an array type T[N]. template <typename T, size_t N> class UniversalPrinter<T[N]> { @@ -602,12 +588,6 @@ class UniversalPrinter<T[N]> { static void Print(const T (&a)[N], ::std::ostream* os) { UniversalPrintArray(a, N, os); } - - // A convenient wrapper for Print() that returns the print-out as a - // string. - static string PrintToString(const T (&a)[N]) { - return UniversalPrintArrayToString(a, N); - } }; // Implements printing a reference type T&. @@ -630,14 +610,6 @@ class UniversalPrinter<T&> { UniversalPrinter<T>::Print(value, os); } - // A convenient wrapper for Print() that returns the print-out as a - // string. - static string PrintToString(const T& value) { - ::std::stringstream ss; - Print(value, &ss); - return ss.str(); - } - #ifdef _MSC_VER #pragma warning(pop) // Restores the warning state. #endif // _MSC_VER @@ -740,6 +712,14 @@ Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { } } // namespace internal + +template <typename T> +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrint(value, &ss); + return ss.str(); +} + } // namespace testing #endif // GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_ |