diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index a13815733..01ac414bd 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -524,17 +524,14 @@ inline void PrintTo(bool x, ::std::ostream* os) { GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os); -inline void PrintTo(char16_t c, ::std::ostream* os) { - // TODO(b/418738869): Incorrect for values not representing valid codepoints. - // Also see https://github.com/google/googletest/issues/4762. - PrintTo(static_cast(c), os); -} + +// Overloads for the UTF-8 and UTF-16 code unit types. A code unit that +// encodes a code point all by itself is printed with the U+XXXX notation; +// one that does not (any non-ASCII char8_t, and the UTF-16 surrogates) is +// printed as a code unit instead, the way wchar_t is. +GTEST_API_ void PrintTo(char16_t c, ::std::ostream* os); #ifdef __cpp_lib_char8_t -inline void PrintTo(char8_t c, ::std::ostream* os) { - // TODO(b/418738869): Incorrect for values not representing valid codepoints. - // Also see https://github.com/google/googletest/issues/4762. - PrintTo(static_cast(c), os); -} +GTEST_API_ void PrintTo(char8_t c, ::std::ostream* os); #endif // gcc/clang __{u,}int128_t diff --git a/googletest/src/gtest-printers.cc b/googletest/src/gtest-printers.cc index 6d1de6d95..d1ba45eab 100644 --- a/googletest/src/gtest-printers.cc +++ b/googletest/src/gtest-printers.cc @@ -285,6 +285,28 @@ void PrintTo(char32_t c, ::std::ostream* os) { << static_cast(c); } +// char8_t and char16_t hold code units, not code points, so the U+XXXX +// notation only applies to the values that encode a code point on their own. +// The rest -- non-ASCII char8_t, which are always part of a multi-unit UTF-8 +// sequence, and the UTF-16 surrogates -- are printed as code units. +void PrintTo(char16_t c, ::std::ostream* os) { + if (c >= 0xD800 && c <= 0xDFFF) { + PrintCharAndCodeTo(c, os); + } else { + PrintTo(static_cast(c), os); + } +} + +#ifdef __cpp_lib_char8_t +void PrintTo(char8_t c, ::std::ostream* os) { + if (c >= 0x80) { + PrintCharAndCodeTo(c, os); + } else { + PrintTo(static_cast(c), os); + } +} +#endif + // gcc/clang __{u,}int128_t #if defined(__SIZEOF_INT128__) void PrintTo(__uint128_t v, ::std::ostream* os) { diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index 0b11f8e4a..1eb50e186 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -396,12 +396,24 @@ TEST(PrintCharTest, UnsignedChar) { EXPECT_EQ("'b' (98, 0x62)", Print(static_cast('b'))); } -TEST(PrintCharTest, Char16) { EXPECT_EQ("U+0041", Print(u'A')); } +TEST(PrintCharTest, Char16) { + EXPECT_EQ("U+0041", Print(u'A')); + EXPECT_EQ("U+754C", Print(u'界')); + // Surrogates are not code points, so they are printed as code units. + EXPECT_EQ("u'\\xD800' (55296)", Print(static_cast(0xD800))); + EXPECT_EQ("u'\\xDFFF' (57343)", Print(static_cast(0xDFFF))); +} TEST(PrintCharTest, Char32) { EXPECT_EQ("U+0041", Print(U'A')); } #ifdef __cpp_lib_char8_t -TEST(PrintCharTest, Char8) { EXPECT_EQ("U+0041", Print(u8'A')); } +TEST(PrintCharTest, Char8) { + EXPECT_EQ("U+0041", Print(u8'A')); + // Only ASCII code units encode a code point on their own; the rest are + // printed as code units. + EXPECT_EQ("u8'\\x80' (128)", Print(static_cast(0x80))); + EXPECT_EQ("u8'\\xFF' (255)", Print(static_cast(0xFF))); +} #endif // Tests printing other simple, built-in types. @@ -456,7 +468,7 @@ TEST(PrintBuiltInTypeTest, Integer) { #ifdef __cpp_lib_char8_t EXPECT_EQ("U+0000", Print(std::numeric_limits::min())); // char8_t - EXPECT_EQ("U+00FF", + EXPECT_EQ("u8'\\xFF' (255)", Print(std::numeric_limits::max())); // char8_t #endif EXPECT_EQ("U+0000",