diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index cb73ef257..048c32db2 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -111,6 +111,7 @@ #include // NOLINT #include #include +#include #include #include #include @@ -248,8 +249,8 @@ struct StreamPrinter { // ADL (possibly involving implicit conversions). // (Use SFINAE via return type, because it seems GCC < 12 doesn't handle name // lookup properly when we do it in the template parameter list.) - static auto PrintValue(const T& value, - ::std::ostream* os) -> decltype((void)(*os << value)) { + static auto PrintValue(const T& value, ::std::ostream* os) + -> decltype((void)(*os << value)) { // Call streaming operator found by ADL, possibly with implicit conversions // of the arguments. *os << value; @@ -702,44 +703,63 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { } } -// Overloads for ::std::string. -GTEST_API_ void PrintStringTo(const ::std::string& s, ::std::ostream* os); +// Overloads for ::std::string and ::std::string_view +GTEST_API_ void PrintStringTo(::std::string_view s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } +inline void PrintTo(::std::string_view s, ::std::ostream* os) { + PrintStringTo(s, os); +} -// Overloads for ::std::u8string +// Overloads for ::std::u8string and ::std::u8string_view #ifdef __cpp_lib_char8_t -GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os); +GTEST_API_ void PrintU8StringTo(::std::u8string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) { PrintU8StringTo(s, os); } +inline void PrintTo(::std::u8string_view s, ::std::ostream* os) { + PrintU8StringTo(s, os); +} #endif -// Overloads for ::std::u16string -GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os); +// Overloads for ::std::u16string and ::std::u16string_view +GTEST_API_ void PrintU16StringTo(::std::u16string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) { PrintU16StringTo(s, os); } +inline void PrintTo(::std::u16string_view s, ::std::ostream* os) { + PrintU16StringTo(s, os); +} -// Overloads for ::std::u32string -GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os); +// Overloads for ::std::u32string and ::std::u32string_view +GTEST_API_ void PrintU32StringTo(::std::u32string_view s, ::std::ostream* os); inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) { PrintU32StringTo(s, os); } +inline void PrintTo(::std::u32string_view s, ::std::ostream* os) { + PrintU32StringTo(s, os); +} -// Overloads for ::std::wstring. +// Overloads for ::std::wstring and ::std::wstring_view #if GTEST_HAS_STD_WSTRING -GTEST_API_ void PrintWideStringTo(const ::std::wstring& s, ::std::ostream* os); +GTEST_API_ void PrintWideStringTo(::std::wstring_view s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } +inline void PrintTo(::std::wstring_view s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} #endif // GTEST_HAS_STD_WSTRING #if GTEST_INTERNAL_HAS_STRING_VIEW -// Overload for internal::StringView. +// Overload for internal::StringView. Needed for build configurations where +// internal::StringView is an alias for absl::string_view, but absl::string_view +// is a distinct type from std::string_view. +template , int> = 0> inline void PrintTo(internal::StringView sp, ::std::ostream* os) { - PrintTo(::std::string(sp), os); + PrintStringTo(sp, os); } #endif // GTEST_INTERNAL_HAS_STRING_VIEW diff --git a/googletest/src/gtest-printers.cc b/googletest/src/gtest-printers.cc index e3acecba8..b5d8df6d8 100644 --- a/googletest/src/gtest-printers.cc +++ b/googletest/src/gtest-printers.cc @@ -50,7 +50,7 @@ #include #include #include // NOLINT -#include +#include #include #include "gtest/internal/gtest-port.h" @@ -333,14 +333,14 @@ void PrintTo(__int128_t v, ::std::ostream* os) { // 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, the length is len, it may include '\0' characters -// and may not be NUL-terminated. +// The array starts at begin (which may be nullptr) and contains len characters. +// The array may include '\0' characters and may not be NUL-terminated. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat PrintCharsAsStringTo(const CharType* begin, size_t len, ostream* os) { - const char* const quote_prefix = GetCharWidthPrefix(*begin); + const char* const quote_prefix = GetCharWidthPrefix(CharType()); *os << quote_prefix << "\""; bool is_previous_hex = false; CharFormat print_format = kAsIs; @@ -522,7 +522,7 @@ void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { } // anonymous namespace -void PrintStringTo(const ::std::string& s, ostream* os) { +void PrintStringTo(::std::string_view s, ostream* os) { if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { if (GTEST_FLAG_GET(print_utf8)) { ConditionalPrintAsText(s.data(), s.size(), os); @@ -531,21 +531,21 @@ void PrintStringTo(const ::std::string& s, ostream* os) { } #ifdef __cpp_lib_char8_t -void PrintU8StringTo(const ::std::u8string& s, ostream* os) { +void PrintU8StringTo(::std::u8string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif -void PrintU16StringTo(const ::std::u16string& s, ostream* os) { +void PrintU16StringTo(::std::u16string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } -void PrintU32StringTo(const ::std::u32string& s, ostream* os) { +void PrintU32StringTo(::std::u32string_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring& s, ostream* os) { +void PrintWideStringTo(::std::wstring_view s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_STD_WSTRING diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index a016e8a14..6c1a48beb 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,7 @@ #if GTEST_INTERNAL_HAS_STD_SPAN #include // NOLINT -#endif // GTEST_INTERNAL_HAS_STD_SPAN +#endif // GTEST_INTERNAL_HAS_STD_SPAN #if GTEST_INTERNAL_HAS_COMPARE_LIB #include // NOLINT @@ -799,7 +800,7 @@ struct Foo { TEST(PrintPointerTest, MemberVariablePointer) { EXPECT_TRUE(HasPrefix(Print(&Foo::value), Print(sizeof(&Foo::value)) + "-byte object ")); - int Foo::*p = NULL; // NOLINT + int Foo::* p = NULL; // NOLINT EXPECT_TRUE(HasPrefix(Print(p), Print(sizeof(p)) + "-byte object ")); } @@ -926,7 +927,7 @@ TEST(PrintArrayTest, BigArray) { PrintArrayHelper(a)); } -// Tests printing ::string and ::std::string. +// Tests printing ::std::string and ::string_view. // ::std::string. TEST(PrintStringTest, StringInStdNamespace) { @@ -936,6 +937,13 @@ TEST(PrintStringTest, StringInStdNamespace) { Print(str)); } +TEST(PrintStringTest, StringViewInStdNamespace) { + const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; + const ::std::string_view str(s, sizeof(s)); + EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", + Print(str)); +} + TEST(PrintStringTest, StringAmbiguousHex) { // "\x6BANANA" is ambiguous, it can be interpreted as starting with either of: // '\x6', '\x6B', or '\x6BA'. @@ -953,7 +961,7 @@ TEST(PrintStringTest, StringAmbiguousHex) { EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!"))); } -// Tests printing ::std::wstring. +// Tests printing ::std::wstring and ::std::wstring_view. #if GTEST_HAS_STD_WSTRING // ::std::wstring. TEST(PrintWideStringTest, StringInStdNamespace) { @@ -965,6 +973,15 @@ TEST(PrintWideStringTest, StringInStdNamespace) { Print(str)); } +TEST(PrintWideStringTest, StringViewInStdNamespace) { + const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; + const ::std::wstring_view str(s, sizeof(s) / sizeof(wchar_t)); + EXPECT_EQ( + "L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" + "\\xD3\\x576\\x8D3\\xC74D a\\0\"", + Print(str)); +} + TEST(PrintWideStringTest, StringAmbiguousHex) { // same for wide strings. EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12" @@ -983,6 +1000,12 @@ TEST(PrintStringTest, U8String) { EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type. EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str)); } + +TEST(PrintStringTest, U8StringView) { + std::u8string_view str = u8"Hello, 世界"; + EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type. + EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str)); +} #endif TEST(PrintStringTest, U16String) { @@ -991,12 +1014,24 @@ TEST(PrintStringTest, U16String) { EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str)); } +TEST(PrintStringTest, U16StringView) { + std::u16string_view str = u"Hello, 世界"; + EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type. + EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str)); +} + TEST(PrintStringTest, U32String) { std::u32string str = U"Hello, 🗺️"; EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type EXPECT_EQ("U\"Hello, \\x1F5FA\\xFE0F\"", Print(str)); } +TEST(PrintStringTest, U32StringView) { + std::u32string_view str = U"Hello, 🗺️"; + EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type + EXPECT_EQ("U\"Hello, \\x1F5FA\\xFE0F\"", Print(str)); +} + // Tests printing types that support generic streaming (i.e. streaming // to std::basic_ostream for any valid Char and // CharTraits types). @@ -1456,7 +1491,7 @@ TEST(PrintReferenceTest, HandlesMemberFunctionPointer) { // Tests that the universal printer prints a member variable pointer // passed by reference. TEST(PrintReferenceTest, HandlesMemberVariablePointer) { - int Foo::*p = &Foo::value; // NOLINT + int Foo::* p = &Foo::value; // NOLINT EXPECT_TRUE(HasPrefix(PrintByRef(p), "@" + PrintPointer(&p) + " " + Print(sizeof(p)) + "-byte object ")); }