From dfa3474d955dd9eef68c748feb4a39e0ca1c03c4 Mon Sep 17 00:00:00 2001 From: maks Date: Sat, 28 Mar 2026 11:58:22 +0100 Subject: [PATCH] Minimize heavy STL headers in GoogleTest and GoogleMock public headers. This change reduces compilation time by replacing heavy headers like and with in public headers. Key changes: - Introduced internal::StreamTo helper functions to handle streaming common types without requiring in headers. - Updated GoogleTest and GoogleMock public headers to use . - Refactored StringMatchResultListener to hide its std::stringstream implementation in gmock-matchers.cc. - Moved non-template PrintTo overloads to .cc files. Fixes https://github.com/google/googletest/issues/4943. --- .../include/gmock/gmock-cardinalities.h | 2 +- googlemock/include/gmock/gmock-matchers.h | 309 +++++++++--------- .../include/gmock/gmock-more-matchers.h | 10 +- .../include/gmock/gmock-spec-builders.h | 50 +-- .../gmock/internal/gmock-internal-utils.h | 1 - .../include/gmock/internal/gmock-port.h | 1 - googlemock/src/gmock-matchers.cc | 21 ++ .../include/gtest/gtest-assertion-result.h | 2 +- googletest/include/gtest/gtest-matchers.h | 24 +- googletest/include/gtest/gtest-message.h | 35 +- googletest/include/gtest/gtest-printers.h | 130 ++++---- googletest/include/gtest/gtest-test-part.h | 1 - googletest/include/gtest/gtest.h | 15 +- .../include/gtest/internal/gtest-param-util.h | 14 +- .../include/gtest/internal/gtest-port.h | 47 ++- .../include/gtest/internal/gtest-string.h | 4 +- googletest/src/gtest-matchers.cc | 7 + googletest/src/gtest-port.cc | 55 ++++ googletest/src/gtest-printers.cc | 39 ++- googletest/src/gtest.cc | 56 +++- googletest/test/googletest-port-test.cc | 2 + 21 files changed, 509 insertions(+), 316 deletions(-) diff --git a/googlemock/include/gmock/gmock-cardinalities.h b/googlemock/include/gmock/gmock-cardinalities.h index c88c00c44..f919b6579 100644 --- a/googlemock/include/gmock/gmock-cardinalities.h +++ b/googlemock/include/gmock/gmock-cardinalities.h @@ -42,7 +42,7 @@ #include #include -#include // NOLINT +#include // NOLINT #include "gmock/internal/gmock-port.h" #include "gtest/gtest.h" diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 2f49371a6..557734560 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -264,8 +264,7 @@ #include #include #include -#include // NOLINT -#include +#include #include #include #include @@ -305,16 +304,17 @@ namespace testing { // A match result listener that stores the explanation in a string. class [[nodiscard]] StringMatchResultListener : public MatchResultListener { public: - StringMatchResultListener() : MatchResultListener(&ss_) {} + StringMatchResultListener(); + ~StringMatchResultListener() override; // Returns the explanation accumulated so far. - std::string str() const { return ss_.str(); } + std::string str() const; // Clears the explanation accumulated so far. - void Clear() { ss_.str(""); } + void Clear(); private: - ::std::stringstream ss_; + const std::unique_ptr< ::std::ostream> ss_; StringMatchResultListener(const StringMatchResultListener&) = delete; StringMatchResultListener& operator=(const StringMatchResultListener&) = @@ -578,12 +578,8 @@ struct Rank1 : Rank0 {}; using HighestRank = Rank1; // If the explanation is not empty, prints it to the ostream. -inline void PrintIfNotEmpty(const std::string& explanation, - ::std::ostream* os) { - if (!explanation.empty() && os != nullptr) { - *os << ", " << explanation; - } -} +GTEST_API_ void PrintIfNotEmpty(const std::string& explanation, + ::std::ostream* os); // Returns true if the given type name is easy to read by a human. // This is used to decide whether printing the type of a value might @@ -657,9 +653,9 @@ class [[nodiscard]] TuplePrefix { const Value& value = std::get(values); StringMatchResultListener listener; if (!matcher.MatchAndExplain(value, &listener)) { - *os << " Expected arg #" << N - 1 << ": "; + ::testing::internal::StreamTo(os, " Expected arg #"); ::testing::internal::StreamTo(os, N - 1); ::testing::internal::StreamTo(os, ": "); std::get(matchers).DescribeTo(os); - *os << "\n Actual: "; + ::testing::internal::StreamTo(os, "\n Actual: "); // We remove the reference in type Value to prevent the // universal printer from printing the address of value, which // isn't interesting to the user most of the time. The @@ -667,7 +663,7 @@ class [[nodiscard]] TuplePrefix { // the address is interesting. internal::UniversalPrint(value, os); PrintIfNotEmpty(listener.str(), os); - *os << "\n"; + ::testing::internal::StreamTo(os, "\n"); } } }; @@ -766,12 +762,12 @@ class [[nodiscard]] AnythingMatcher { bool MatchAndExplain(const T& /* x */, std::ostream* /* listener */) const { return true; } - void DescribeTo(std::ostream* os) const { *os << "is anything"; } + void DescribeTo(std::ostream* os) const { ::testing::internal::StreamTo(os, "is anything"); } void DescribeNegationTo(::std::ostream* os) const { // This is mostly for completeness' sake, as it's not very useful // to write Not(A()). However we cannot completely rule out // such a possibility, and it doesn't hurt to be prepared. - *os << "never matches"; + ::testing::internal::StreamTo(os, "never matches"); } }; @@ -785,8 +781,8 @@ class [[nodiscard]] IsNullMatcher { return p == nullptr; } - void DescribeTo(::std::ostream* os) const { *os << "is NULL"; } - void DescribeNegationTo(::std::ostream* os) const { *os << "isn't NULL"; } + void DescribeTo(::std::ostream* os) const { ::testing::internal::StreamTo(os, "is NULL"); } + void DescribeNegationTo(::std::ostream* os) const { ::testing::internal::StreamTo(os, "isn't NULL"); } }; // Implements the polymorphic NotNull() matcher, which matches any raw or smart @@ -799,8 +795,8 @@ class [[nodiscard]] NotNullMatcher { return p != nullptr; } - void DescribeTo(::std::ostream* os) const { *os << "isn't NULL"; } - void DescribeNegationTo(::std::ostream* os) const { *os << "is NULL"; } + void DescribeTo(::std::ostream* os) const { ::testing::internal::StreamTo(os, "isn't NULL"); } + void DescribeNegationTo(::std::ostream* os) const { ::testing::internal::StreamTo(os, "is NULL"); } }; // Ref(variable) matches any argument that is a reference to @@ -857,12 +853,12 @@ class [[nodiscard]] RefMatcher { } void DescribeTo(::std::ostream* os) const override { - *os << "references the variable "; + ::testing::internal::StreamTo(os, "references the variable "); UniversalPrinter::Print(object_, os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "does not reference the variable "; + ::testing::internal::StreamTo(os, "does not reference the variable "); UniversalPrinter::Print(object_, os); } @@ -962,10 +958,10 @@ class [[nodiscard]] StrEqualityMatcher { private: void DescribeToHelper(bool expect_eq, ::std::ostream* os) const { - *os << (expect_eq ? "is " : "isn't "); - *os << "equal to "; + ::testing::internal::StreamTo(os, (expect_eq ? "is " : "isn't ")); + ::testing::internal::StreamTo(os, "equal to "); if (!case_sensitive_) { - *os << "(ignoring case) "; + ::testing::internal::StreamTo(os, "(ignoring case) "); } UniversalPrint(string_, os); } @@ -1016,12 +1012,12 @@ class [[nodiscard]] HasSubstrMatcher { // Describes what this matcher matches. void DescribeTo(::std::ostream* os) const { - *os << "has substring "; + ::testing::internal::StreamTo(os, "has substring "); UniversalPrint(substring_, os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "has no substring "; + ::testing::internal::StreamTo(os, "has no substring "); UniversalPrint(substring_, os); } @@ -1070,12 +1066,12 @@ class [[nodiscard]] StartsWithMatcher { } void DescribeTo(::std::ostream* os) const { - *os << "starts with "; + ::testing::internal::StreamTo(os, "starts with "); UniversalPrint(prefix_, os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "doesn't start with "; + ::testing::internal::StreamTo(os, "doesn't start with "); UniversalPrint(prefix_, os); } @@ -1124,12 +1120,12 @@ class [[nodiscard]] EndsWithMatcher { } void DescribeTo(::std::ostream* os) const { - *os << "ends with "; + ::testing::internal::StreamTo(os, "ends with "); UniversalPrint(suffix_, os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "doesn't end with "; + ::testing::internal::StreamTo(os, "doesn't end with "); UniversalPrint(suffix_, os); } @@ -1163,12 +1159,12 @@ class [[nodiscard]] WhenBase64UnescapedMatcher { } void DescribeTo(::std::ostream* os) const { - *os << "matches after Base64Unescape "; + ::testing::internal::StreamTo(os, "matches after Base64Unescape "); internal_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "does not match after Base64Unescape "; + ::testing::internal::StreamTo(os, "does not match after Base64Unescape "); internal_matcher_.DescribeTo(os); } @@ -1209,10 +1205,10 @@ class [[nodiscard]] PairMatchBase { return Op()(::std::get<0>(args), ::std::get<1>(args)); } void DescribeTo(::std::ostream* os) const override { - *os << "are " << GetDesc; + ::testing::internal::StreamTo(os, "are "); ::testing::internal::StreamTo(os, GetDesc); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "aren't " << GetDesc; + ::testing::internal::StreamTo(os, "aren't "); ::testing::internal::StreamTo(os, GetDesc); } }; }; @@ -1302,21 +1298,21 @@ class [[nodiscard]] AllOfMatcherImpl : public MatcherInterface { : matchers_(std::move(matchers)) {} void DescribeTo(::std::ostream* os) const override { - *os << "("; + ::testing::internal::StreamTo(os, "("); for (size_t i = 0; i < matchers_.size(); ++i) { - if (i != 0) *os << ") and ("; + if (i != 0) ::testing::internal::StreamTo(os, ") and ("); matchers_[i].DescribeTo(os); } - *os << ")"; + ::testing::internal::StreamTo(os, ")"); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "("; + ::testing::internal::StreamTo(os, "("); for (size_t i = 0; i < matchers_.size(); ++i) { - if (i != 0) *os << ") or ("; + if (i != 0) ::testing::internal::StreamTo(os, ") or ("); matchers_[i].DescribeNegationTo(os); } - *os << ")"; + ::testing::internal::StreamTo(os, ")"); } bool MatchAndExplain(const T& x, @@ -1438,21 +1434,21 @@ class [[nodiscard]] AnyOfMatcherImpl : public MatcherInterface { : matchers_(std::move(matchers)) {} void DescribeTo(::std::ostream* os) const override { - *os << "("; + ::testing::internal::StreamTo(os, "("); for (size_t i = 0; i < matchers_.size(); ++i) { - if (i != 0) *os << ") or ("; + if (i != 0) ::testing::internal::StreamTo(os, ") or ("); matchers_[i].DescribeTo(os); } - *os << ")"; + ::testing::internal::StreamTo(os, ")"); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "("; + ::testing::internal::StreamTo(os, "("); for (size_t i = 0; i < matchers_.size(); ++i) { - if (i != 0) *os << ") and ("; + if (i != 0) ::testing::internal::StreamTo(os, ") and ("); matchers_[i].DescribeNegationTo(os); } - *os << ")"; + ::testing::internal::StreamTo(os, ")"); } bool MatchAndExplain(const T& x, @@ -1600,11 +1596,11 @@ class [[nodiscard]] TrulyMatcher { } void DescribeTo(::std::ostream* os) const { - *os << "satisfies the given predicate"; + ::testing::internal::StreamTo(os, "satisfies the given predicate"); } void DescribeNegationTo(::std::ostream* os) const { - *os << "doesn't satisfy the given predicate"; + ::testing::internal::StreamTo(os, "doesn't satisfy the given predicate"); } private: @@ -1717,8 +1713,8 @@ class [[nodiscard]] IsNanMatcher { return (::std::isnan)(f); } - void DescribeTo(::std::ostream* os) const { *os << "is NaN"; } - void DescribeNegationTo(::std::ostream* os) const { *os << "isn't NaN"; } + void DescribeTo(::std::ostream* os) const { ::testing::internal::StreamTo(os, "is NaN"); } + void DescribeNegationTo(::std::ostream* os) const { ::testing::internal::StreamTo(os, "isn't NaN"); } }; // Implements the polymorphic floating point equality matcher, which matches @@ -1801,14 +1797,16 @@ class [[nodiscard]] FloatingEqMatcher { os->precision(::std::numeric_limits::digits10 + 2); if (FloatingPoint(expected_).is_nan()) { if (nan_eq_nan_) { - *os << "is NaN"; + ::testing::internal::StreamTo(os, "is NaN"); } else { - *os << "never matches"; + ::testing::internal::StreamTo(os, "never matches"); } } else { - *os << "is approximately " << expected_; + ::testing::internal::StreamTo(os, "is approximately "); ::testing::internal::StreamTo(os, expected_); if (HasMaxAbsError()) { - *os << " (absolute error <= " << max_abs_error_ << ")"; + ::testing::internal::StreamTo(os, " (absolute error <= "); + ::testing::internal::StreamTo(os, max_abs_error_); + ::testing::internal::StreamTo(os, ")"); } } os->precision(old_precision); @@ -1820,14 +1818,14 @@ class [[nodiscard]] FloatingEqMatcher { os->precision(::std::numeric_limits::digits10 + 2); if (FloatingPoint(expected_).is_nan()) { if (nan_eq_nan_) { - *os << "isn't NaN"; + ::testing::internal::StreamTo(os, "isn't NaN"); } else { - *os << "is anything"; + ::testing::internal::StreamTo(os, "is anything"); } } else { - *os << "isn't approximately " << expected_; + ::testing::internal::StreamTo(os, "isn't approximately "); ::testing::internal::StreamTo(os, expected_); if (HasMaxAbsError()) { - *os << " (absolute error > " << max_abs_error_ << ")"; + ::testing::internal::StreamTo(os, " (absolute error > "); ::testing::internal::StreamTo(os, max_abs_error_); ::testing::internal::StreamTo(os, ")"); } } // Restore original precision. @@ -1924,10 +1922,10 @@ class [[nodiscard]] FloatingEq2Matcher { } } void DescribeTo(::std::ostream* os) const override { - *os << "are " << GetDesc; + ::testing::internal::StreamTo(os, "are "); ::testing::internal::StreamTo(os, GetDesc); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "aren't " << GetDesc; + ::testing::internal::StreamTo(os, "aren't "); ::testing::internal::StreamTo(os, GetDesc); } private: @@ -1976,12 +1974,12 @@ class [[nodiscard]] PointeeMatcher { : matcher_(MatcherCast(matcher)) {} void DescribeTo(::std::ostream* os) const override { - *os << "points to a value that "; + ::testing::internal::StreamTo(os, "points to a value that "); matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "does not point to a value that "; + ::testing::internal::StreamTo(os, "does not point to a value that "); matcher_.DescribeTo(os); } @@ -2035,12 +2033,12 @@ class [[nodiscard]] PointerMatcher { : matcher_(MatcherCast(matcher)) {} void DescribeTo(::std::ostream* os) const override { - *os << "is a pointer that "; + ::testing::internal::StreamTo(os, "is a pointer that "); matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "is not a pointer that "; + ::testing::internal::StreamTo(os, "is not a pointer that "); matcher_.DescribeTo(os); } @@ -2088,7 +2086,7 @@ class [[nodiscard]] WhenDynamicCastToMatcherBase { private: static void GetCastTypeDescription(::std::ostream* os) { - *os << "when dynamic_cast to " << GetToName() << ", "; + ::testing::internal::StreamTo(os, "when dynamic_cast to "); ::testing::internal::StreamTo(os, GetToName()); ::testing::internal::StreamTo(os, ", "); } }; @@ -2146,12 +2144,12 @@ class [[nodiscard]] FieldMatcher { whose_field_("whose field `" + field_name + "` ") {} void DescribeTo(::std::ostream* os) const { - *os << "is an object " << whose_field_; + ::testing::internal::StreamTo(os, "is an object "); ::testing::internal::StreamTo(os, whose_field_); matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "is an object " << whose_field_; + ::testing::internal::StreamTo(os, "is an object "); ::testing::internal::StreamTo(os, whose_field_); matcher_.DescribeNegationTo(os); } @@ -2213,12 +2211,12 @@ class [[nodiscard]] PropertyMatcher { whose_property_("whose property `" + property_name + "` ") {} void DescribeTo(::std::ostream* os) const { - *os << "is an object " << whose_property_; + ::testing::internal::StreamTo(os, "is an object "); ::testing::internal::StreamTo(os, whose_property_); matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "is an object " << whose_property_; + ::testing::internal::StreamTo(os, "is an object "); ::testing::internal::StreamTo(os, whose_property_); matcher_.DescribeNegationTo(os); } @@ -2333,18 +2331,18 @@ class [[nodiscard]] ResultOfMatcher { void DescribeTo(::std::ostream* os) const override { if (result_description_.empty()) { - *os << "is mapped by the given callable to a value that "; + ::testing::internal::StreamTo(os, "is mapped by the given callable to a value that "); } else { - *os << "whose " << result_description_ << " "; + ::testing::internal::StreamTo(os, "whose "); ::testing::internal::StreamTo(os, result_description_); ::testing::internal::StreamTo(os, " "); } matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { if (result_description_.empty()) { - *os << "is mapped by the given callable to a value that "; + ::testing::internal::StreamTo(os, "is mapped by the given callable to a value that "); } else { - *os << "whose " << result_description_ << " "; + ::testing::internal::StreamTo(os, "whose "); ::testing::internal::StreamTo(os, result_description_); ::testing::internal::StreamTo(os, " "); } matcher_.DescribeNegationTo(os); } @@ -2400,11 +2398,11 @@ class [[nodiscard]] SizeIsMatcher { : size_matcher_(MatcherCast(size_matcher)) {} void DescribeTo(::std::ostream* os) const override { - *os << "has a size that "; + ::testing::internal::StreamTo(os, "has a size that "); size_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "has a size that "; + ::testing::internal::StreamTo(os, "has a size that "); size_matcher_.DescribeNegationTo(os); } @@ -2453,11 +2451,11 @@ class [[nodiscard]] BeginEndDistanceIsMatcher { : distance_matcher_(MatcherCast(distance_matcher)) {} void DescribeTo(::std::ostream* os) const override { - *os << "distance between begin() and end() "; + ::testing::internal::StreamTo(os, "distance between begin() and end() "); distance_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "distance between begin() and end() "; + ::testing::internal::StreamTo(os, "distance between begin() and end() "); distance_matcher_.DescribeNegationTo(os); } @@ -2511,11 +2509,11 @@ class [[nodiscard]] ContainerEqMatcher { : expected_(View::Copy(expected)) {} void DescribeTo(::std::ostream* os) const { - *os << "equals "; + ::testing::internal::StreamTo(os, "equals "); UniversalPrint(expected_, os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "does not equal "; + ::testing::internal::StreamTo(os, "does not equal "); UniversalPrint(expected_, os); } @@ -2537,9 +2535,9 @@ class [[nodiscard]] ContainerEqMatcher { if (internal::ArrayAwareFind(expected_.begin(), expected_.end(), *it) == expected_.end()) { if (printed_header) { - *os << ", "; + ::testing::internal::StreamTo(os, ", "); } else { - *os << "which has these unexpected elements: "; + ::testing::internal::StreamTo(os, "which has these unexpected elements: "); printed_header = true; } UniversalPrint(*it, os); @@ -2553,10 +2551,10 @@ class [[nodiscard]] ContainerEqMatcher { lhs_stl_container.end(), *it) == lhs_stl_container.end()) { if (printed_header2) { - *os << ", "; + ::testing::internal::StreamTo(os, ", "); } else { - *os << (printed_header ? ",\nand" : "which") - << " doesn't have these expected elements: "; + ::testing::internal::StreamTo(os, (printed_header ? ",\nand" : "which")); + ::testing::internal::StreamTo(os, " doesn't have these expected elements: "); printed_header2 = true; } UniversalPrint(*it, os); @@ -2610,12 +2608,12 @@ class [[nodiscard]] WhenSortedByMatcher { : comparator_(comparator), matcher_(matcher) {} void DescribeTo(::std::ostream* os) const override { - *os << "(when sorted) "; + ::testing::internal::StreamTo(os, "(when sorted) "); matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "(when sorted) "; + ::testing::internal::StreamTo(os, "(when sorted) "); matcher_.DescribeNegationTo(os); } @@ -2714,18 +2712,20 @@ class [[nodiscard]] PointwiseMatcher { rhs_(rhs) {} void DescribeTo(::std::ostream* os) const override { - *os << "contains " << rhs_.size() - << " values, where each value and its corresponding value in "; + ::testing::internal::StreamTo(os, "contains "); + ::testing::internal::StreamTo(os, rhs_.size()); + ::testing::internal::StreamTo(os, " values, where each value and its corresponding value in "); UniversalPrinter::Print(rhs_, os); - *os << " "; + ::testing::internal::StreamTo(os, " "); mono_tuple_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "doesn't contain exactly " << rhs_.size() - << " values, or contains a value x at some index i" - << " where x and the i-th value of "; + ::testing::internal::StreamTo(os, "doesn't contain exactly "); + ::testing::internal::StreamTo(os, rhs_.size()); + ::testing::internal::StreamTo(os, " values, or contains a value x at some index i"); + ::testing::internal::StreamTo(os, " where x and the i-th value of "); UniversalPrint(rhs_, os); - *os << " "; + ::testing::internal::StreamTo(os, " "); mono_tuple_matcher_.DescribeNegationTo(os); } @@ -2880,12 +2880,12 @@ class [[nodiscard]] ContainsMatcherImpl // Describes what this matcher does. void DescribeTo(::std::ostream* os) const override { - *os << "contains at least one element that "; + ::testing::internal::StreamTo(os, "contains at least one element that "); this->inner_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "doesn't contain any element that "; + ::testing::internal::StreamTo(os, "doesn't contain any element that "); this->inner_matcher_.DescribeTo(os); } @@ -2919,12 +2919,12 @@ class [[nodiscard]] DistanceFromMatcherImpl : public MatcherInterface { // Describes what this matcher does. void DescribeTo(::std::ostream* os) const override { distance_matcher_.DescribeTo(os); - *os << " away from " << PrintToString(target_); + ::testing::internal::StreamTo(os, " away from "); ::testing::internal::StreamTo(os, PrintToString(target_)); } void DescribeNegationTo(::std::ostream* os) const override { distance_matcher_.DescribeNegationTo(os); - *os << " away from " << PrintToString(target_); + ::testing::internal::StreamTo(os, " away from "); ::testing::internal::StreamTo(os, PrintToString(target_)); } bool MatchAndExplain(V value, MatchResultListener* listener) const override { @@ -2954,12 +2954,12 @@ class [[nodiscard]] EachMatcherImpl : public QuantifierMatcherImpl { // Describes what this matcher does. void DescribeTo(::std::ostream* os) const override { - *os << "only contains elements that "; + ::testing::internal::StreamTo(os, "only contains elements that "); this->inner_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "contains some element that "; + ::testing::internal::StreamTo(os, "contains some element that "); this->inner_matcher_.DescribeNegationTo(os); } @@ -2982,16 +2982,16 @@ class [[nodiscard]] ContainsTimesMatcherImpl count_matcher_(std::move(count_matcher)) {} void DescribeTo(::std::ostream* os) const override { - *os << "quantity of elements that match "; + ::testing::internal::StreamTo(os, "quantity of elements that match "); this->inner_matcher_.DescribeTo(os); - *os << " "; + ::testing::internal::StreamTo(os, " "); count_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "quantity of elements that match "; + ::testing::internal::StreamTo(os, "quantity of elements that match "); this->inner_matcher_.DescribeTo(os); - *os << " "; + ::testing::internal::StreamTo(os, " "); count_matcher_.DescribeNegationTo(os); } @@ -3156,13 +3156,13 @@ class [[nodiscard]] KeyMatcherImpl : public MatcherInterface { // Describes what this matcher does. void DescribeTo(::std::ostream* os) const override { - *os << "has a key that "; + ::testing::internal::StreamTo(os, "has a key that "); inner_matcher_.DescribeTo(os); } // Describes what the negation of this matcher does. void DescribeNegationTo(::std::ostream* os) const override { - *os << "doesn't have a key that "; + ::testing::internal::StreamTo(os, "doesn't have a key that "); inner_matcher_.DescribeTo(os); } @@ -3207,12 +3207,12 @@ class [[nodiscard]] AddressMatcher { : matcher_(MatcherCast
(matcher)) {} void DescribeTo(::std::ostream* os) const override { - *os << "has address that "; + ::testing::internal::StreamTo(os, "has address that "); matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "does not have address that "; + ::testing::internal::StreamTo(os, "does not have address that "); matcher_.DescribeTo(os); } @@ -3247,17 +3247,17 @@ class [[nodiscard]] PairMatcherImpl : public MatcherInterface { // Describes what this matcher does. void DescribeTo(::std::ostream* os) const override { - *os << "has a first field that "; + ::testing::internal::StreamTo(os, "has a first field that "); first_matcher_.DescribeTo(os); - *os << ", and has a second field that "; + ::testing::internal::StreamTo(os, ", and has a second field that "); second_matcher_.DescribeTo(os); } // Describes what the negation of this matcher does. void DescribeNegationTo(::std::ostream* os) const override { - *os << "has a first field that "; + ::testing::internal::StreamTo(os, "has a first field that "); first_matcher_.DescribeNegationTo(os); - *os << ", or has a second field that "; + ::testing::internal::StreamTo(os, ", or has a second field that "); second_matcher_.DescribeNegationTo(os); } @@ -3519,13 +3519,19 @@ class [[nodiscard]] FieldsAreMatcherImpl> void DescribeTo(::std::ostream* os) const override { const char* separator = ""; VariadicExpand( - {(*os << separator << "has field #" << I << " that ", + {(::testing::internal::StreamTo(os, separator), + ::testing::internal::StreamTo(os, "has field #"), + ::testing::internal::StreamTo(os, I), + ::testing::internal::StreamTo(os, " that "), std::get(matchers_).DescribeTo(os), separator = ", and ")...}); } void DescribeNegationTo(::std::ostream* os) const override { const char* separator = ""; - VariadicExpand({(*os << separator << "has field #" << I << " that ", + VariadicExpand({(::testing::internal::StreamTo(os, separator), + ::testing::internal::StreamTo(os, "has field #"), + ::testing::internal::StreamTo(os, I), + ::testing::internal::StreamTo(os, " that "), std::get(matchers_).DescribeNegationTo(os), separator = ", or ")...}); } @@ -3615,17 +3621,17 @@ class [[nodiscard]] ElementsAreMatcherImpl // Describes what this matcher does. void DescribeTo(::std::ostream* os) const override { if (count() == 0) { - *os << "is empty"; + ::testing::internal::StreamTo(os, "is empty"); } else if (count() == 1) { - *os << "has 1 element that "; + ::testing::internal::StreamTo(os, "has 1 element that "); matchers_[0].DescribeTo(os); } else { - *os << "has " << Elements(count()) << " where\n"; + ::testing::internal::StreamTo(os, "has "); ::testing::internal::StreamTo(os, Elements(count())); ::testing::internal::StreamTo(os, " where\n"); for (size_t i = 0; i != count(); ++i) { - *os << "element #" << i << " "; + ::testing::internal::StreamTo(os, "element #"); ::testing::internal::StreamTo(os, i); ::testing::internal::StreamTo(os, " "); matchers_[i].DescribeTo(os); if (i + 1 < count()) { - *os << ",\n"; + ::testing::internal::StreamTo(os, ",\n"); } } } @@ -3634,16 +3640,16 @@ class [[nodiscard]] ElementsAreMatcherImpl // Describes what the negation of this matcher does. void DescribeNegationTo(::std::ostream* os) const override { if (count() == 0) { - *os << "isn't empty"; + ::testing::internal::StreamTo(os, "isn't empty"); return; } - *os << "doesn't have " << Elements(count()) << ", or\n"; + ::testing::internal::StreamTo(os, "doesn't have "); ::testing::internal::StreamTo(os, Elements(count())); ::testing::internal::StreamTo(os, ", or\n"); for (size_t i = 0; i != count(); ++i) { - *os << "element #" << i << " "; + ::testing::internal::StreamTo(os, "element #"); ::testing::internal::StreamTo(os, i); ::testing::internal::StreamTo(os, " "); matchers_[i].DescribeNegationTo(os); if (i + 1 < count()) { - *os << ", or\n"; + ::testing::internal::StreamTo(os, ", or\n"); } } } @@ -4096,9 +4102,9 @@ class [[nodiscard]] BoundSecondMatcher { second_value_(second) {} void DescribeTo(::std::ostream* os) const override { - *os << "and "; + ::testing::internal::StreamTo(os, "and "); UniversalPrint(second_value_, os); - *os << " "; + ::testing::internal::StreamTo(os, " "); mono_tuple2_matcher_.DescribeTo(os); } @@ -4171,12 +4177,12 @@ class [[nodiscard]] OptionalMatcher { : value_matcher_(MatcherCast(value_matcher)) {} void DescribeTo(::std::ostream* os) const override { - *os << "value "; + ::testing::internal::StreamTo(os, "value "); value_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "value "; + ::testing::internal::StreamTo(os, "value "); value_matcher_.DescribeNegationTo(os); } @@ -4244,14 +4250,16 @@ class [[nodiscard]] VariantMatcher { } void DescribeTo(std::ostream* os) const { - *os << "is a variant<> with value of type '" << GetTypeName() - << "' and the value "; + ::testing::internal::StreamTo(os, "is a variant<> with value of type '"); + ::testing::internal::StreamTo(os, GetTypeName()); + ::testing::internal::StreamTo(os, "' and the value "); matcher_.DescribeTo(os); } void DescribeNegationTo(std::ostream* os) const { - *os << "is a variant<> with value of type other than '" << GetTypeName() - << "' or the value "; + ::testing::internal::StreamTo(os, "is a variant<> with value of type other than '"); + ::testing::internal::StreamTo(os, GetTypeName()); + ::testing::internal::StreamTo(os, "' or the value "); matcher_.DescribeNegationTo(os); } @@ -4305,14 +4313,16 @@ class [[nodiscard]] AnyCastMatcher { } void DescribeTo(std::ostream* os) const { - *os << "is an 'any' type with value of type '" << GetTypeName() - << "' and the value "; + ::testing::internal::StreamTo(os, "is an 'any' type with value of type '"); + ::testing::internal::StreamTo(os, GetTypeName()); + ::testing::internal::StreamTo(os, "' and the value "); matcher_.DescribeTo(os); } void DescribeNegationTo(std::ostream* os) const { - *os << "is an 'any' type with value of type other than '" << GetTypeName() - << "' or the value "; + ::testing::internal::StreamTo(os, "is an 'any' type with value of type other than '"); + ::testing::internal::StreamTo(os, GetTypeName()); + ::testing::internal::StreamTo(os, "' or the value "); matcher_.DescribeNegationTo(os); } @@ -4362,13 +4372,13 @@ class [[nodiscard]] ArgsMatcherImpl : public MatcherInterface { } void DescribeTo(::std::ostream* os) const override { - *os << "are a tuple "; + ::testing::internal::StreamTo(os, "are a tuple "); PrintIndices(os); inner_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "are a tuple "; + ::testing::internal::StreamTo(os, "are a tuple "); PrintIndices(os); inner_matcher_.DescribeNegationTo(os); } @@ -4376,7 +4386,7 @@ class [[nodiscard]] ArgsMatcherImpl : public MatcherInterface { private: // Prints the indices of the selected fields. static void PrintIndices(::std::ostream* os) { - *os << "whose fields ("; + ::testing::internal::StreamTo(os, "whose fields ("); const char* sep = ""; // Workaround spurious C4189 on MSVC<=15.7 when k is empty. (void)sep; @@ -4385,9 +4395,12 @@ class [[nodiscard]] ArgsMatcherImpl : public MatcherInterface { // and may have been trying to use the first operation of the comma operator // as a member of the array, so Clang warns that we may have made a mistake. const char* dummy[] = { - "", (static_cast(*os << sep << "#" << k), sep = ", ")...}; + "", (static_cast(::testing::internal::StreamTo(os, sep), + ::testing::internal::StreamTo(os, "#"), + ::testing::internal::StreamTo(os, k)), + sep = ", ")...}; (void)dummy; - *os << ") "; + ::testing::internal::StreamTo(os, ") "); } MonomorphicInnerMatcher inner_matcher_; @@ -5587,12 +5600,12 @@ class [[nodiscard]] WithWhatMatcherImpl { : matcher_(std::move(matcher)) {} void DescribeTo(std::ostream* os) const { - *os << "contains .what() that "; + ::testing::internal::StreamTo(os, "contains .what() that "); matcher_.DescribeTo(os); } void DescribeNegationTo(std::ostream* os) const { - *os << "contains .what() that does not "; + ::testing::internal::StreamTo(os, "contains .what() that does not "); matcher_.DescribeTo(os); } @@ -5653,14 +5666,16 @@ class [[nodiscard]] ExceptionMatcherImpl { : matcher_(std::move(matcher)) {} void DescribeTo(std::ostream* os) const { - *os << "throws an exception which is a " << GetTypeName(); - *os << " which "; + ::testing::internal::StreamTo(os, "throws an exception which is a "); + ::testing::internal::StreamTo(os, GetTypeName()); + ::testing::internal::StreamTo(os, " which "); matcher_.DescribeTo(os); } void DescribeNegationTo(std::ostream* os) const { - *os << "throws an exception which is not a " << GetTypeName(); - *os << " which "; + ::testing::internal::StreamTo(os, "throws an exception which is not a "); + ::testing::internal::StreamTo(os, GetTypeName()); + ::testing::internal::StreamTo(os, " which "); matcher_.DescribeNegationTo(os); } diff --git a/googlemock/include/gmock/gmock-more-matchers.h b/googlemock/include/gmock/gmock-more-matchers.h index 39aad4c1a..e8fbcea41 100644 --- a/googlemock/include/gmock/gmock-more-matchers.h +++ b/googlemock/include/gmock/gmock-more-matchers.h @@ -40,7 +40,7 @@ #ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MORE_MATCHERS_H_ #define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MORE_MATCHERS_H_ -#include +#include #include #include "gmock/gmock-matchers.h" @@ -80,9 +80,13 @@ class [[nodiscard]] IsEmptyMatcher { } // Describes what this matcher matches. - void DescribeTo(std::ostream* os) const { *os << "is empty"; } + void DescribeTo(std::ostream* os) const { + ::testing::internal::StreamTo(os, "is empty"); + } - void DescribeNegationTo(std::ostream* os) const { *os << "isn't empty"; } + void DescribeNegationTo(std::ostream* os) const { + ::testing::internal::StreamTo(os, "isn't empty"); + } }; } // namespace internal diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h index 5cb10c096..f12e87955 100644 --- a/googlemock/include/gmock/gmock-spec-builders.h +++ b/googlemock/include/gmock/gmock-spec-builders.h @@ -65,9 +65,8 @@ #include #include #include -#include +#include #include -#include #include #include #include @@ -698,7 +697,8 @@ class GTEST_API_ ExpectationBase { // Describes the source file location of this expectation. void DescribeLocationTo(::std::ostream* os) const { - *os << FormatFileLocation(file(), line()) << " "; + ::testing::internal::StreamTo(os, FormatFileLocation(file(), line())); + ::testing::internal::StreamTo(os, " "); } // Describes how many times a function call matching this @@ -1084,9 +1084,9 @@ class TypedExpectation : public ExpectationBase { // describes it to the ostream. void MaybeDescribeExtraMatcherTo(::std::ostream* os) override { if (extra_matcher_specified_) { - *os << " Expected args: "; + ::testing::internal::StreamTo(os, " Expected args: "); extra_matcher_.DescribeTo(os); - *os << "\n"; + ::testing::internal::StreamTo(os, "\n"); } } @@ -1140,40 +1140,42 @@ class TypedExpectation : public ExpectationBase { g_gmock_mutex.AssertHeld(); if (is_retired()) { - *os << " Expected: the expectation is active\n" - << " Actual: it is retired\n"; + ::testing::internal::StreamTo(os, " Expected: the expectation is active\n"); + ::testing::internal::StreamTo(os, " Actual: it is retired\n"); } else if (!Matches(args)) { if (!TupleMatches(matchers_, args)) { ExplainMatchFailureTupleTo(matchers_, args, os); } StringMatchResultListener listener; if (!extra_matcher_.MatchAndExplain(args, &listener)) { - *os << " Expected args: "; + ::testing::internal::StreamTo(os, " Expected args: "); extra_matcher_.DescribeTo(os); - *os << "\n Actual: don't match"; + ::testing::internal::StreamTo(os, "\n Actual: don't match"); internal::PrintIfNotEmpty(listener.str(), os); - *os << "\n"; + ::testing::internal::StreamTo(os, "\n"); } } else if (!AllPrerequisitesAreSatisfied()) { - *os << " Expected: all pre-requisites are satisfied\n" - << " Actual: the following immediate pre-requisites " - << "are not satisfied:\n"; + ::testing::internal::StreamTo(os, " Expected: all pre-requisites are satisfied\n"); + ::testing::internal::StreamTo(os, " Actual: the following immediate pre-requisites "); + ::testing::internal::StreamTo(os, "are not satisfied:\n"); ExpectationSet unsatisfied_prereqs; FindUnsatisfiedPrerequisites(&unsatisfied_prereqs); int i = 0; for (ExpectationSet::const_iterator it = unsatisfied_prereqs.begin(); it != unsatisfied_prereqs.end(); ++it) { it->expectation_base()->DescribeLocationTo(os); - *os << "pre-requisite #" << i++ << "\n"; + ::testing::internal::StreamTo(os, "pre-requisite #"); + ::testing::internal::StreamTo(os, i++); + ::testing::internal::StreamTo(os, "\n"); } - *os << " (end of pre-requisites)\n"; + ::testing::internal::StreamTo(os, " (end of pre-requisites)\n"); } else { // This line is here just for completeness' sake. It will never // be executed as currently the ExplainMatchResultTo() function // is called only when the mock function call does NOT match the // expectation. - *os << "The call matches the expectation.\n"; + ::testing::internal::StreamTo(os, "The call matches the expectation.\n"); } } @@ -1602,11 +1604,12 @@ class FunctionMocker final : public UntypedFunctionMockerBase { const OnCallSpec* const spec = FindOnCallSpec(args); if (spec == nullptr) { - *os << (std::is_void::value ? "returning directly.\n" - : "returning default value.\n"); + ::testing::internal::StreamTo(os, (std::is_void::value ? "returning directly.\n" + : "returning default value.\n")); } else { - *os << "taking default action specified at:\n" - << FormatFileLocation(spec->file(), spec->line()) << "\n"; + ::testing::internal::StreamTo(os, "taking default action specified at:\n"); + ::testing::internal::StreamTo(os, FormatFileLocation(spec->file(), spec->line())); + ::testing::internal::StreamTo(os, "\n"); } } @@ -1618,9 +1621,10 @@ class FunctionMocker final : public UntypedFunctionMockerBase { GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { const ArgumentTuple& args = *static_cast(untyped_args); - *os << "Uninteresting mock function call - "; + ::testing::internal::StreamTo(os, "Uninteresting mock function call - "); DescribeDefaultActionTo(args, os); - *os << " Function call: " << Name(); + ::testing::internal::StreamTo(os, " Function call: "); + ::testing::internal::StreamTo(os, Name()); UniversalPrint(args, os); } @@ -1697,7 +1701,7 @@ class FunctionMocker final : public UntypedFunctionMockerBase { ::std::ostream* why) const GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) { g_gmock_mutex.AssertHeld(); - *os << "\nUnexpected mock function call - "; + ::testing::internal::StreamTo(os, "\nUnexpected mock function call - "); DescribeDefaultActionTo(args, os); PrintTriedExpectationsLocked(args, why); } diff --git a/googlemock/include/gmock/internal/gmock-internal-utils.h b/googlemock/include/gmock/internal/gmock-internal-utils.h index 258397a4f..843aeac8b 100644 --- a/googlemock/include/gmock/internal/gmock-internal-utils.h +++ b/googlemock/include/gmock/internal/gmock-internal-utils.h @@ -42,7 +42,6 @@ #include #include -#include // NOLINT #include #include #include diff --git a/googlemock/include/gmock/internal/gmock-port.h b/googlemock/include/gmock/internal/gmock-port.h index 3bf0b818c..d0175de43 100644 --- a/googlemock/include/gmock/internal/gmock-port.h +++ b/googlemock/include/gmock/internal/gmock-port.h @@ -44,7 +44,6 @@ #include #include -#include // Most of the utilities needed for porting Google Mock are also // required for Google Test and are defined in gtest-port.h. diff --git a/googlemock/src/gmock-matchers.cc b/googlemock/src/gmock-matchers.cc index 277add6b6..3a4116288 100644 --- a/googlemock/src/gmock-matchers.cc +++ b/googlemock/src/gmock-matchers.cc @@ -42,8 +42,29 @@ #include namespace testing { + +StringMatchResultListener::StringMatchResultListener() + : MatchResultListener(new ::std::stringstream), + ss_(static_cast< ::std::stringstream*>(stream())) {} + +StringMatchResultListener::~StringMatchResultListener() = default; + +std::string StringMatchResultListener::str() const { + return static_cast(stream())->str(); +} + +void StringMatchResultListener::Clear() { + static_cast< ::std::stringstream*>(stream())->str(""); +} + namespace internal { +void PrintIfNotEmpty(const std::string& explanation, ::std::ostream* os) { + if (explanation != "" && os != nullptr) { + *os << "\n " << explanation; + } +} + // Returns the description for a matcher defined using the MATCHER*() // macro where the user-supplied description string is "", if // 'negation' is false; otherwise returns the description of the diff --git a/googletest/include/gtest/gtest-assertion-result.h b/googletest/include/gtest/gtest-assertion-result.h index 52a6d62c7..7e4d695fc 100644 --- a/googletest/include/gtest/gtest-assertion-result.h +++ b/googletest/include/gtest/gtest-assertion-result.h @@ -39,7 +39,7 @@ #define GOOGLETEST_INCLUDE_GTEST_GTEST_ASSERTION_RESULT_H_ #include -#include +#include #include #include diff --git a/googletest/include/gtest/gtest-matchers.h b/googletest/include/gtest/gtest-matchers.h index 6d2ab14d2..f0d96a334 100644 --- a/googletest/include/gtest/gtest-matchers.h +++ b/googletest/include/gtest/gtest-matchers.h @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include @@ -88,12 +88,12 @@ class [[nodiscard]] MatchResultListener { // is NULL. template MatchResultListener& operator<<(const T& x) { - if (stream_ != nullptr) *stream_ << x; + if (stream_ != nullptr) internal::StreamTo(stream_, x); return *this; } // Returns the underlying ostream. - ::std::ostream* stream() { return stream_; } + ::std::ostream* stream() const { return stream_; } // Returns true if and only if the listener is interested in an explanation // of the match result. A matcher's MatchAndExplain() method can use @@ -129,11 +129,7 @@ class GTEST_API_ [[nodiscard]] MatcherDescriberInterface { // You are not required to override this when implementing // MatcherInterface, but it is highly advised so that your matcher // can produce good error messages. - virtual void DescribeNegationTo(::std::ostream* os) const { - *os << "not ("; - DescribeTo(os); - *os << ")"; - } + virtual void DescribeNegationTo(::std::ostream* os) const; }; // The implementation of a matcher. @@ -801,11 +797,11 @@ class [[nodiscard]] ImplicitCastEqMatcher { } void DescribeTo(std::ostream* os) const { - *os << "is equal to "; + internal::StreamTo(os, "is equal to "); UniversalPrint(rhs(), os); } void DescribeNegationTo(std::ostream* os) const { - *os << "isn't equal to "; + internal::StreamTo(os, "isn't equal to "); UniversalPrint(rhs(), os); } @@ -857,13 +853,15 @@ class [[nodiscard]] MatchesRegexMatcher { } void DescribeTo(::std::ostream* os) const { - *os << (full_match_ ? "matches" : "contains") << " regular expression "; + internal::StreamTo(os, full_match_ ? "matches" : "contains"); + internal::StreamTo(os, " regular expression "); UniversalPrinter::Print(regex_->pattern(), os); } void DescribeNegationTo(::std::ostream* os) const { - *os << "doesn't " << (full_match_ ? "match" : "contain") - << " regular expression "; + internal::StreamTo(os, "doesn't "); + internal::StreamTo(os, full_match_ ? "match" : "contain"); + internal::StreamTo(os, " regular expression "); UniversalPrinter::Print(regex_->pattern(), os); } diff --git a/googletest/include/gtest/gtest-message.h b/googletest/include/gtest/gtest-message.h index 448ac6b7e..42d121f90 100644 --- a/googletest/include/gtest/gtest-message.h +++ b/googletest/include/gtest/gtest-message.h @@ -50,8 +50,7 @@ #include #include -#include -#include +#include #include #include "gtest/internal/gtest-port.h" @@ -109,18 +108,24 @@ class GTEST_API_ Message { Message(); // Copy constructor. - Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT - *ss_ << msg.GetString(); - } + Message(const Message& msg); + + // Destructor. + ~Message(); // Constructs a Message from a C-string. - explicit Message(const char* str) : ss_(new ::std::stringstream) { - *ss_ << str; - } + explicit Message(const char* str); // Streams a non-pointer value to this object. If building a version of // GoogleTest with ABSL, this overload is only enabled if the value does not // have an AbslStringify definition. + Message& operator<<(const char* s); + Message& operator<<(const std::string& s); + Message& operator<<(int n); + Message& operator<<(long n); + Message& operator<<(double n); + Message& operator<<(const void* p); + template < typename T #ifdef GTEST_HAS_ABSL @@ -179,12 +184,7 @@ class GTEST_API_ Message { // as "(null)". template inline Message& operator<<(T* const& pointer) { // NOLINT - if (pointer == nullptr) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - return *this; + return (*this << static_cast(pointer)); } // Since the basic IO manipulators are overloaded for both narrow @@ -193,10 +193,7 @@ class GTEST_API_ Message { // templatized version above. Without this definition, streaming // endl or other basic IO manipulators to Message will confuse the // compiler. - Message& operator<<(BasicNarrowIoManip val) { - *ss_ << val; - return *this; - } + Message& operator<<(BasicNarrowIoManip val); // Instead of 1/0, we want to see true/false for bool values. Message& operator<<(bool b) { return *this << (b ? "true" : "false"); } @@ -220,7 +217,7 @@ class GTEST_API_ Message { private: // We'll hold the text streamed to this object here. - const std::unique_ptr< ::std::stringstream> ss_; + const std::unique_ptr< ::std::ostream> ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index d1704bb75..b2d2c2201 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -108,7 +108,7 @@ #include #include #include -#include // NOLINT +#include #include #include #include @@ -135,11 +135,30 @@ #endif // GTEST_INTERNAL_HAS_COMPARE_LIB namespace testing { +class Message; // Definitions in the internal* namespaces are subject to change without notice. // DO NOT USE THEM IN USER CODE! namespace internal { +GTEST_API_ ::std::string PrintToStringWithPrinter( + const void* value, void (*printer)(::std::ostream*, const void*)); + +GTEST_API_ void StreamTo(::std::ostream* os, char c); +GTEST_API_ void StreamTo(::std::ostream* os, const char* s); +GTEST_API_ void StreamTo(::std::ostream* os, const std::string& s); +GTEST_API_ void StreamTo(::std::ostream* os, const void* p); +GTEST_API_ void StreamTo(::std::ostream* os, bool b); +GTEST_API_ void StreamTo(::std::ostream* os, float f); +GTEST_API_ void StreamTo(::std::ostream* os, double d); +GTEST_API_ void StreamTo(::std::ostream* os, int n); +GTEST_API_ void StreamTo(::std::ostream* os, unsigned int n); +GTEST_API_ void StreamTo(::std::ostream* os, long n); +GTEST_API_ void StreamTo(::std::ostream* os, unsigned long n); +GTEST_API_ void StreamTo(::std::ostream* os, long long n); +GTEST_API_ void StreamTo(::std::ostream* os, unsigned long long n); +GTEST_API_ void StreamTo(::std::ostream* os, const Message& msg); + template void UniversalPrint(const T& value, ::std::ostream* os); @@ -171,17 +190,17 @@ struct ContainerPrinter { IsStdSpan::value>::type> static void PrintValue(const T& container, std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. - *os << '{'; + StreamTo(os, '{'); size_t count = 0; for (auto&& elem : container) { if (count > 0) { - *os << ','; + StreamTo(os, ','); if (count == kMaxCount) { // Enough has been printed. - *os << " ..."; + StreamTo(os, " ..."); break; } } - *os << ' '; + StreamTo(os, ' '); // We cannot call PrintTo(elem, os) here as PrintTo() doesn't // handle `elem` being a native array. internal::UniversalPrint(elem, os); @@ -189,9 +208,9 @@ struct ContainerPrinter { } if (count > 0) { - *os << ' '; + StreamTo(os, ' '); } - *os << '}'; + StreamTo(os, '}'); } }; @@ -206,12 +225,12 @@ struct FunctionPointerPrinter { std::is_function::value>::type> static void PrintValue(T* p, ::std::ostream* os) { if (p == nullptr) { - *os << "NULL"; + StreamTo(os, "NULL"); } else { // T is a function type, so '*os << p' doesn't do what we want // (it just prints p as bool). We want to print p as a const // void*. - *os << reinterpret_cast(p); + StreamTo(os, reinterpret_cast(p)); } } }; @@ -220,12 +239,12 @@ struct PointerPrinter { template static void PrintValue(T* p, ::std::ostream* os) { if (p == nullptr) { - *os << "NULL"; + StreamTo(os, "NULL"); } else { // T is not a function type. We just call << to print p, // relying on ADL to pick up user-defined << for their pointer // types, if any. - *os << p; + StreamTo(os, p); } } }; @@ -273,7 +292,9 @@ struct ProtobufPrinter { if (pretty_str.length() > kProtobufOneLinerMaxLength) { pretty_str = "\n" + value.DebugString(); } - *os << ("<" + pretty_str + ">"); + StreamTo(os, "<"); + StreamTo(os, pretty_str); + StreamTo(os, ">"); } }; @@ -286,7 +307,7 @@ struct ConvertibleToIntegerPrinter { // T is not an enum, printing it as an integer is the best we can do // given that it has no user-defined printer. static void PrintValue(internal::BiggestInt value, ::std::ostream* os) { - *os << value; + StreamTo(os, value); } }; @@ -304,7 +325,7 @@ struct ConvertibleToAbslStringifyPrinter { typename = typename std::enable_if< absl::HasAbslStringify::value>::type> // NOLINT static void PrintValue(const T& value, ::std::ostream* os) { - *os << absl::StrCat(value); + StreamTo(os, absl::StrCat(value)); } }; #endif // GTEST_HAS_ABSL @@ -328,7 +349,7 @@ struct RawBytesPrinter { struct FallbackPrinter { template static void PrintValue(const T&, ::std::ostream* os) { - *os << "(incomplete type)"; + StreamTo(os, "(incomplete type)"); } }; @@ -511,7 +532,7 @@ inline void PrintTo(char c, ::std::ostream* os) { // Overloads for other simple built-in types. inline void PrintTo(bool x, ::std::ostream* os) { - *os << (x ? "true" : "false"); + StreamTo(os, x ? "true" : "false"); } // Overload for wchar_t type. @@ -624,19 +645,8 @@ int AppropriateResolution(FloatType val) { return full; } -inline void PrintTo(float f, ::std::ostream* os) { - auto old_precision = os->precision(); - os->precision(AppropriateResolution(f)); - *os << f; - os->precision(old_precision); -} - -inline void PrintTo(double d, ::std::ostream* os) { - auto old_precision = os->precision(); - os->precision(AppropriateResolution(d)); - *os << d; - os->precision(old_precision); -} +GTEST_API_ void PrintTo(float f, ::std::ostream* os); +GTEST_API_ void PrintTo(double d, ::std::ostream* os); // Overloads for C strings. GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); @@ -784,10 +794,12 @@ inline const void* VoidifyPointer(volatile const void* p) { template void PrintSmartPointer(const Ptr& ptr, std::ostream* os, char) { if (ptr == nullptr) { - *os << "(nullptr)"; + StreamTo(os, "(nullptr)"); } else { // We can't print the value. Just print the pointer.. - *os << "(" << (VoidifyPointer)(ptr.get()) << ")"; + StreamTo(os, "("); + StreamTo(os, (VoidifyPointer)(ptr.get())); + StreamTo(os, ")"); } } template ::value>::type> void PrintSmartPointer(const Ptr& ptr, std::ostream* os, int) { if (ptr == nullptr) { - *os << "(nullptr)"; + StreamTo(os, "(nullptr)"); } else { - *os << "(ptr = " << (VoidifyPointer)(ptr.get()) << ", value = "; + StreamTo(os, "(ptr = "); + StreamTo(os, (VoidifyPointer)(ptr.get())); + StreamTo(os, ", value = "); UniversalPrinter::Print(*ptr, os); - *os << ")"; + StreamTo(os, ")"); } } @@ -861,7 +875,7 @@ void PrintTupleTo(const T& t, std::integral_constant, GTEST_INTENTIONAL_CONST_COND_PUSH_() if (I > 1) { GTEST_INTENTIONAL_CONST_COND_POP_() - *os << ", "; + StreamTo(os, ", "); } UniversalPrinter::type>::Print( std::get(t), os); @@ -923,9 +937,10 @@ class [[nodiscard]] UniversalPrinter { public: static void Print(const std::any& value, ::std::ostream* os) { if (value.has_value()) { - *os << "value of type " << GetTypeName(value); + StreamTo(os, "value of type "); + StreamTo(os, GetTypeName(value)); } else { - *os << "no value"; + StreamTo(os, "no value"); } } @@ -945,20 +960,20 @@ template class [[nodiscard]] UniversalPrinter> { public: static void Print(const std::optional& value, ::std::ostream* os) { - *os << '('; + StreamTo(os, '('); if (!value) { - *os << "nullopt"; + StreamTo(os, "nullopt"); } else { UniversalPrint(*value, os); } - *os << ')'; + StreamTo(os, ')'); } }; template <> class [[nodiscard]] UniversalPrinter { public: - static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; } + static void Print(std::nullopt_t, ::std::ostream* os) { StreamTo(os, "(nullopt)"); } }; // Printer for std::variant @@ -966,17 +981,20 @@ template class [[nodiscard]] UniversalPrinter> { public: static void Print(const std::variant& value, ::std::ostream* os) { - *os << '('; + StreamTo(os, '('); std::visit(Visitor{os, value.index()}, value); - *os << ')'; + StreamTo(os, ')'); } private: struct Visitor { template void operator()(const U& u) const { - *os << "'" << GetTypeName() << "(index = " << index - << ")' with value "; + StreamTo(os, "'"); + StreamTo(os, GetTypeName()); + StreamTo(os, "(index = "); + StreamTo(os, index); + StreamTo(os, ")' with value "); UniversalPrint(u, os); } ::std::ostream* os; @@ -989,9 +1007,9 @@ class [[nodiscard]] UniversalPrinter> { template void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { if (len == 0) { - *os << "{}"; + StreamTo(os, "{}"); } else { - *os << "{ "; + StreamTo(os, "{ "); const size_t kThreshold = 18; const size_t kChunkSize = 8; // If the array has more than kThreshold elements, we'll have to @@ -1001,10 +1019,10 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { PrintRawArrayTo(begin, len, os); } else { PrintRawArrayTo(begin, kChunkSize, os); - *os << ", ..., "; + StreamTo(os, ", ..., "); PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); } - *os << " }"; + StreamTo(os, " }"); } } // This overload prints a (const) char array compactly. @@ -1051,7 +1069,9 @@ class [[nodiscard]] UniversalPrinter { static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here // as static_cast doesn't compile when T is a function type. - *os << "@" << reinterpret_cast(&value) << " "; + StreamTo(os, "@"); + StreamTo(os, reinterpret_cast(&value)); + StreamTo(os, " "); // Then prints the value itself. UniversalPrint(value, os); @@ -1097,7 +1117,7 @@ class [[nodiscard]] UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { if (str == nullptr) { - *os << "NULL"; + StreamTo(os, "NULL"); } else { UniversalPrint(std::string(str), os); } @@ -1113,7 +1133,7 @@ class [[nodiscard]] UniversalTersePrinter { public: static void Print(const char8_t* str, ::std::ostream* os) { if (str == nullptr) { - *os << "NULL"; + StreamTo(os, "NULL"); } else { UniversalPrint(::std::u8string(str), os); } @@ -1129,7 +1149,7 @@ class [[nodiscard]] UniversalTersePrinter { public: static void Print(const char16_t* str, ::std::ostream* os) { if (str == nullptr) { - *os << "NULL"; + StreamTo(os, "NULL"); } else { UniversalPrint(::std::u16string(str), os); } @@ -1144,7 +1164,7 @@ class [[nodiscard]] UniversalTersePrinter { public: static void Print(const char32_t* str, ::std::ostream* os) { if (str == nullptr) { - *os << "NULL"; + StreamTo(os, "NULL"); } else { UniversalPrint(::std::u32string(str), os); } @@ -1160,7 +1180,7 @@ class [[nodiscard]] UniversalTersePrinter { public: static void Print(const wchar_t* str, ::std::ostream* os) { if (str == nullptr) { - *os << "NULL"; + StreamTo(os, "NULL"); } else { UniversalPrint(::std::wstring(str), os); } diff --git a/googletest/include/gtest/gtest-test-part.h b/googletest/include/gtest/gtest-test-part.h index ce1e21945..578cd099d 100644 --- a/googletest/include/gtest/gtest-test-part.h +++ b/googletest/include/gtest/gtest-test-part.h @@ -35,7 +35,6 @@ #define GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #include -#include #include #include #include diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index 4218adebd..f0e2403be 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -53,9 +53,8 @@ #include #include #include -#include +#include #include -#include #include #include #include @@ -1589,17 +1588,9 @@ AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, return AssertionSuccess(); } - ::std::stringstream lhs_ss; - lhs_ss.precision(std::numeric_limits::digits10 + 2); - lhs_ss << lhs_value; - - ::std::stringstream rhs_ss; - rhs_ss.precision(std::numeric_limits::digits10 + 2); - rhs_ss << rhs_value; - return EqFailure(lhs_expression, rhs_expression, - StringStreamToString(&lhs_ss), StringStreamToString(&rhs_ss), - false); + (Message() << lhs_value).GetString(), + (Message() << rhs_value).GetString(), false); } // Helper function for implementing ASSERT_NEAR. diff --git a/googletest/include/gtest/internal/gtest-param-util.h b/googletest/include/gtest/internal/gtest-param-util.h index 716779346..d70b771cc 100644 --- a/googletest/include/gtest/internal/gtest-param-util.h +++ b/googletest/include/gtest/internal/gtest-param-util.h @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include @@ -250,7 +250,7 @@ class [[nodiscard]] RangeGenerator : public ParamGeneratorInterface { // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " - << "from different generators." << std::endl; + << "from different generators." << "\n"; const int other_index = CheckedDowncastToActualType(&other)->index_; return index_ == other_index; @@ -347,7 +347,7 @@ class [[nodiscard]] ValuesInIteratorRangeGenerator // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " - << "from different generators." << std::endl; + << "from different generators." << "\n"; return iterator_ == CheckedDowncastToActualType(&other)->iterator_; } @@ -586,11 +586,11 @@ class [[nodiscard]] ParameterizedTestSuiteInfo << "Parameterized test name '" << param_name << "' is invalid (contains spaces, dashes, or any " "non-alphanumeric characters other than underscores), in " - << file << " line " << line << "" << std::endl; + << file << " line " << line << "" << "\n"; GTEST_CHECK_(test_param_names.count(param_name) == 0) << "Duplicate parameterized test name '" << param_name << "', in " - << file << " line " << line << std::endl; + << file << " line " << line << "\n"; if (!test_info->test_base_name.empty()) { test_name.append(test_info->test_base_name).append("/"); @@ -882,7 +882,7 @@ class [[nodiscard]] CartesianProductGenerator // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " - << "from different generators." << std::endl; + << "from different generators." << "\n"; const IteratorImpl* typed_other = CheckedDowncastToActualType(&other); @@ -1004,7 +1004,7 @@ class [[nodiscard]] ParamGeneratorConverter // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " - << "from different generators." << std::endl; + << "from different generators." << "\n"; const ParamIterator other_it = CheckedDowncastToActualType(&other)->it_; return it_ == other_it; diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h index b607e0ade..d59a8e467 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -289,11 +289,10 @@ #include // #include // Guarded by GTEST_IS_THREADSAFE below #include -#include +#include #include #include #include -#include #include // #include // Guarded by GTEST_IS_THREADSAFE below #include @@ -1046,7 +1045,19 @@ class GTEST_API_ [[nodiscard]] GTestLog { // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); - ::std::ostream& GetStream() { return ::std::cerr; } + GTestLog& operator<<(const char* message); + GTestLog& operator<<(const std::string& message); + GTestLog& operator<<(int error_code); + GTestLog& operator<<(const void* pointer); + GTestLog& operator<<(::std::ostream& (*manipulator)(::std::ostream&)); + + template + GTestLog& operator<<(const T& val) { + GetStream() << val; + return *this; + } + + ::std::ostream& GetStream(); private: const GTestLogSeverity severity_; @@ -1059,8 +1070,7 @@ class GTEST_API_ [[nodiscard]] GTestLog { #define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ - __FILE__, __LINE__) \ - .GetStream() + __FILE__, __LINE__) inline void LogToStderr() {} inline void FlushInfoLog() { fflush(nullptr); } @@ -1683,28 +1693,14 @@ class [[nodiscard]] ThreadLocal : public ThreadLocalBase { class [[nodiscard]] MutexBase { public: // Acquires this mutex. - void lock() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); - owner_ = pthread_self(); - has_owner_ = true; - } + void lock(); // Releases this mutex. - void unlock() { - // Since the lock is being released the owner_ field should no longer be - // considered valid. We don't protect writing to has_owner_ here, as it's - // the caller's responsibility to ensure that the current thread holds the - // mutex when this is called. - has_owner_ = false; - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); - } + void unlock(); // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. - void AssertHeld() const { - GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) - << "The current thread is not holding the mutex @" << this; - } + void AssertHeld() const; // A static mutex may be used before main() is entered. It may even // be used before the dynamic initialization stage. Therefore we @@ -1740,11 +1736,8 @@ class [[nodiscard]] MutexBase { // shares its API with MutexBase otherwise. class [[nodiscard]] Mutex : public MutexBase { public: - Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); - has_owner_ = false; - } - ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } + Mutex(); + ~Mutex(); private: Mutex(const Mutex&) = delete; diff --git a/googletest/include/gtest/internal/gtest-string.h b/googletest/include/gtest/internal/gtest-string.h index 2363034fc..d11aef11f 100644 --- a/googletest/include/gtest/internal/gtest-string.h +++ b/googletest/include/gtest/internal/gtest-string.h @@ -51,7 +51,7 @@ #include #include -#include +#include #include #include "gtest/internal/gtest-port.h" @@ -170,7 +170,7 @@ class GTEST_API_ [[nodiscard]] String { // Gets the content of the stringstream's buffer as an std::string. Each '\0' // character in the buffer is replaced with "\\0". -GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); +GTEST_API_ std::string StringStreamToString(::std::ostream* stream); } // namespace internal } // namespace testing diff --git a/googletest/src/gtest-matchers.cc b/googletest/src/gtest-matchers.cc index 7e3bcc0cf..b153d9018 100644 --- a/googletest/src/gtest-matchers.cc +++ b/googletest/src/gtest-matchers.cc @@ -34,6 +34,7 @@ #include "gtest/gtest-matchers.h" +#include #include #include "gtest/internal/gtest-internal.h" @@ -41,6 +42,12 @@ namespace testing { +void MatcherDescriberInterface::DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; +} + // Constructs a matcher that matches a const std::string& whose value is // equal to s. Matcher::Matcher(const std::string& s) { *this = Eq(s); } diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc index d34a693e4..74eb065bf 100644 --- a/googletest/src/gtest-port.cc +++ b/googletest/src/gtest-port.cc @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -1065,6 +1066,60 @@ GTestLog::~GTestLog() { } } +::std::ostream& GTestLog::GetStream() { return ::std::cerr; } + +GTestLog& GTestLog::operator<<(const char* message) { + GetStream() << message; + return *this; +} + +GTestLog& GTestLog::operator<<(const std::string& message) { + GetStream() << message; + return *this; +} + +GTestLog& GTestLog::operator<<(int error_code) { + GetStream() << error_code; + return *this; +} + +GTestLog& GTestLog::operator<<(const void* pointer) { + GetStream() << pointer; + return *this; +} + +GTestLog& GTestLog::operator<<(::std::ostream& (*manipulator)(::std::ostream&)) { + GetStream() << manipulator; + return *this; +} + +#if GTEST_HAS_PTHREAD + +void MutexBase::lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + has_owner_ = true; +} + +void MutexBase::unlock() { + has_owner_ = false; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); +} + +void MutexBase::AssertHeld() const { + GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) + << "The current thread is not holding the mutex @" << this; +} + +Mutex::Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); + has_owner_ = false; +} + +Mutex::~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } + +#endif // GTEST_HAS_PTHREAD + #if GTEST_HAS_STREAM_REDIRECTION // Disable Microsoft deprecation warnings for POSIX functions called from diff --git a/googletest/src/gtest-printers.cc b/googletest/src/gtest-printers.cc index f65573077..1b0f06c35 100644 --- a/googletest/src/gtest-printers.cc +++ b/googletest/src/gtest-printers.cc @@ -41,8 +41,9 @@ // defines Foo. #include "gtest/gtest-printers.h" +#include "gtest/gtest-message.h" -#include +#include #include #include @@ -331,6 +332,20 @@ void PrintTo(__int128_t v, ::std::ostream* os) { } #endif // __SIZEOF_INT128__ +void PrintTo(float f, ::std::ostream* os) { + auto old_precision = os->precision(); + os->precision(AppropriateResolution(f)); + *os << f; + os->precision(old_precision); +} + +void PrintTo(double d, ::std::ostream* os) { + auto old_precision = os->precision(); + os->precision(AppropriateResolution(d)); + *os << d; + os->precision(old_precision); +} + // Prints the given array of characters to the ostream. CharType must be either // char, char8_t, char16_t, char32_t, or wchar_t. // The array starts at begin (which may be nullptr) and contains len characters. @@ -550,6 +565,28 @@ void PrintWideStringTo(::std::wstring_view s, ostream* os) { } #endif // GTEST_HAS_STD_WSTRING +std::string PrintToStringWithPrinter( + const void* value, void (*printer)(::std::ostream*, const void*)) { + ::std::stringstream ss; + printer(&ss, value); + return ss.str(); +} + +void StreamTo(::std::ostream* os, char c) { *os << c; } +void StreamTo(::std::ostream* os, const char* s) { *os << s; } +void StreamTo(::std::ostream* os, const std::string& s) { *os << s; } +void StreamTo(::std::ostream* os, const void* p) { *os << p; } +void StreamTo(::std::ostream* os, bool b) { *os << (b ? "true" : "false"); } +void StreamTo(::std::ostream* os, float f) { *os << f; } +void StreamTo(::std::ostream* os, double d) { *os << d; } +void StreamTo(::std::ostream* os, int n) { *os << n; } +void StreamTo(::std::ostream* os, unsigned int n) { *os << n; } +void StreamTo(::std::ostream* os, long n) { *os << n; } +void StreamTo(::std::ostream* os, unsigned long n) { *os << n; } +void StreamTo(::std::ostream* os, long long n) { *os << n; } +void StreamTo(::std::ostream* os, unsigned long long n) { *os << n; } +void StreamTo(::std::ostream* os, const Message& msg) { *os << msg.GetString(); } + } // namespace internal } // namespace testing diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 8a3801807..acf998972 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -1336,6 +1336,58 @@ Message::Message() : ss_(new ::std::stringstream) { *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } +// Copy constructor. +Message::Message(const Message& msg) : ss_(new ::std::stringstream) { + *ss_ << msg.GetString(); +} + +// Destructor. +Message::~Message() = default; + +// Constructs a Message from a C-string. +Message::Message(const char* str) : ss_(new ::std::stringstream) { + *ss_ << str; +} + +Message& Message::operator<<(const char* s) { + *ss_ << (s == nullptr ? "(null)" : s); + return *this; +} + +Message& Message::operator<<(const std::string& s) { + *ss_ << s; + return *this; +} + +Message& Message::operator<<(int n) { + *ss_ << n; + return *this; +} + +Message& Message::operator<<(long n) { + *ss_ << n; + return *this; +} + +Message& Message::operator<<(double n) { + *ss_ << n; + return *this; +} + +Message& Message::operator<<(const void* p) { + if (p == nullptr) { + *ss_ << "(null)"; + } else { + *ss_ << p; + } + return *this; +} + +Message& Message::operator<<(::std::ostream& (*val)(::std::ostream&)) { + *ss_ << val; + return *this; +} + // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& Message::operator<<(const wchar_t* wide_c_str) { @@ -2286,8 +2338,8 @@ std::string String::FormatByte(unsigned char value) { // Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. -std::string StringStreamToString(::std::stringstream* ss) { - const ::std::string& str = ss->str(); +std::string StringStreamToString(::std::ostream* ss) { + const ::std::string& str = static_cast(ss)->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); diff --git a/googletest/test/googletest-port-test.cc b/googletest/test/googletest-port-test.cc index 24fcd9d93..0315c36d9 100644 --- a/googletest/test/googletest-port-test.cc +++ b/googletest/test/googletest-port-test.cc @@ -30,6 +30,8 @@ // This file tests the internal cross-platform support utilities. #include +#include + #include "gtest/internal/gtest-port.h" #ifdef GTEST_OS_MAC