Merge pull request #4317 from mrfeod:patch-1
PiperOrigin-RevId: 550585850
Change-Id: I727f74aeb6f1da5bbbf5a5f49f06c4cfea40a73b
diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h
index 1ba5178..d1766e6 100644
--- a/googletest/include/gtest/gtest-printers.h
+++ b/googletest/include/gtest/gtest-printers.h
@@ -43,6 +43,9 @@
// 1. foo::PrintTo(const T&, ostream*)
// 2. operator<<(ostream&, const T&) defined in either foo or the
// global namespace.
+// * Prefer AbslStringify(..) to operator<<(..), per https://abseil.io/tips/215.
+// * Define foo::PrintTo(..) if the type already has AbslStringify(..), but an
+// alternative presentation in test results is of interest.
//
// However if T is an STL-style container then it is printed element-wise
// unless foo::PrintTo(const T&, ostream*) is defined. Note that
@@ -112,6 +115,10 @@
#include <utility>
#include <vector>
+#ifdef GTEST_HAS_ABSL
+#include "absl/strings/internal/has_absl_stringify.h"
+#include "absl/strings/str_cat.h"
+#endif // GTEST_HAS_ABSL
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-port.h"
@@ -260,6 +267,18 @@
#endif
};
+#ifdef GTEST_HAS_ABSL
+struct ConvertibleToAbslStringifyPrinter {
+ template <
+ typename T,
+ typename = typename std::enable_if<
+ absl::strings_internal::HasAbslStringify<T>::value>::type> // NOLINT
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ *os << absl::StrCat(value);
+ }
+};
+#endif // GTEST_HAS_ABSL
+
// Prints the given number of bytes in the given object to the given
// ostream.
GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
@@ -308,6 +327,9 @@
using Printer = typename FindFirstPrinter<
T, void, ContainerPrinter, FunctionPointerPrinter, PointerPrinter,
ProtobufPrinter,
+#ifdef GTEST_HAS_ABSL
+ ConvertibleToAbslStringifyPrinter,
+#endif // GTEST_HAS_ABSL
internal_stream_operator_without_lexical_name_lookup::StreamPrinter,
ConvertibleToIntegerPrinter, ConvertibleToStringViewPrinter,
RawBytesPrinter, FallbackPrinter>::type;
diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h
index 514b1cc..656df26 100644
--- a/googletest/include/gtest/internal/gtest-port.h
+++ b/googletest/include/gtest/internal/gtest-port.h
@@ -1146,47 +1146,6 @@
return x;
}
-// When you upcast (that is, cast a pointer from type Foo to type
-// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts
-// always succeed. When you downcast (that is, cast a pointer from
-// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
-// how do you know the pointer is really of type SubclassOfFoo? It
-// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
-// when you downcast, you should use this macro. In debug mode, we
-// use dynamic_cast<> to double-check the downcast is legal (we die
-// if it's not). In normal mode, we do the efficient static_cast<>
-// instead. Thus, it's important to test in debug mode to make sure
-// the cast is legal!
-// This is the only place in the code we should use dynamic_cast<>.
-// In particular, you SHOULDN'T be using dynamic_cast<> in order to
-// do RTTI (eg code like this:
-// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
-// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
-// You should design the code some other way not to need this.
-//
-// This relatively ugly name is intentional. It prevents clashes with
-// similar functions users may have (e.g., down_cast). The internal
-// namespace alone is not enough because the function can be found by ADL.
-template <typename To, typename From> // use like this: DownCast_<T*>(foo);
-inline To DownCast_(From* f) { // so we only accept pointers
- // Ensures that To is a sub-type of From *. This test is here only
- // for compile-time type checking, and has no overhead in an
- // optimized build at run-time, as it will be optimized away
- // completely.
- GTEST_INTENTIONAL_CONST_COND_PUSH_()
- if (false) {
- GTEST_INTENTIONAL_CONST_COND_POP_()
- const To to = nullptr;
- ::testing::internal::ImplicitCast_<From*>(to);
- }
-
-#if GTEST_HAS_RTTI
- // RTTI: debug mode only!
- GTEST_CHECK_(f == nullptr || dynamic_cast<To>(f) != nullptr);
-#endif
- return static_cast<To>(f);
-}
-
// Downcasts the pointer of type Base to Derived.
// Derived must be a subclass of Base. The parameter MUST
// point to a class of type Derived, not any subclass of it.
diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc
index f44f29a..bee0ca4 100644
--- a/googletest/test/googletest-printers-test.cc
+++ b/googletest/test/googletest-printers-test.cc
@@ -55,6 +55,10 @@
#include "gtest/gtest-printers.h"
#include "gtest/gtest.h"
+#ifdef GTEST_HAS_ABSL
+#include "absl/strings/str_format.h"
+#endif
+
// Some user-defined types for testing the universal value printer.
// An anonymous enum type.
@@ -119,6 +123,19 @@
os << "StreamableInGlobal*";
}
+#ifdef GTEST_HAS_ABSL
+// A user-defined type with AbslStringify
+struct Point {
+ template <typename Sink>
+ friend void AbslStringify(Sink& sink, const Point& p) {
+ absl::Format(&sink, "(%d, %d)", p.x, p.y);
+ }
+
+ int x = 10;
+ int y = 20;
+};
+#endif
+
namespace foo {
// A user-defined unprintable type in a user namespace.
@@ -317,6 +334,11 @@
EXPECT_EQ("invalid", Print(static_cast<EnumWithPrintTo>(0)));
}
+#ifdef GTEST_HAS_ABSL
+// Tests printing a class that defines AbslStringify
+TEST(PrintClassTest, AbslStringify) { EXPECT_EQ("(10, 20)", Print(Point())); }
+#endif
+
// Tests printing a class implicitly convertible to BiggestInt.
TEST(PrintClassTest, BiggestIntConvertible) {
@@ -1636,6 +1658,12 @@
EXPECT_STREQ("StreamableInGlobal", PrintToString(r).c_str());
}
+#ifdef GTEST_HAS_ABSL
+TEST(PrintToStringTest, AbslStringify) {
+ EXPECT_PRINT_TO_STRING_(Point(), "(10, 20)");
+}
+#endif
+
TEST(IsValidUTF8Test, IllFormedUTF8) {
// The following test strings are ill-formed UTF-8 and are printed
// as hex only (or ASCII, in case of ASCII bytes) because IsValidUTF8() is