Googletest export
Print std::u8string, std::u16string, and std::u32string as string literals Previously, these types were printed as "{ U+123, U+456, U+789 }". However, printed output in that form is difficult to compare against any literals that might be defined in code. Instead, just treat these types like std::string and std::wstring, escaping non-ASCII characters with a hexadecimal escape sequence. The tests have also been updated to cover the new functionality: as a bonus, the tests now also pass with the MSVC toolchain. Internally, the code has been reorganized to primarily operate in terms of char32_t, under the assumption that char32_t will always be at least as big as wchar_t. While that assumption is currently true, perhaps it won't be in the future... PiperOrigin-RevId: 364033132
This commit is contained in:
parent
3ff1e8b98a
commit
1a8ecf1813
@ -43,6 +43,14 @@ config_setting(
|
||||
constraint_values = ["@platforms//os:windows"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "msvc_compiler",
|
||||
flag_values = {
|
||||
"@bazel_tools//tools/cpp:compiler": "msvc-cl",
|
||||
},
|
||||
visibility = [":__subpackages__"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "has_absl",
|
||||
values = {"define": "absl=1"},
|
||||
|
@ -81,6 +81,8 @@ macro(config_compiler_and_linker)
|
||||
# Suppress "unreachable code" warning
|
||||
# http://stackoverflow.com/questions/3232669 explains the issue.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4702")
|
||||
# Ensure MSVC treats source files as UTF-8 encoded.
|
||||
set(cxx_base_flags "${cxx_base_flags} -utf-8")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(cxx_base_flags "-Wall -Wshadow -Werror -Wconversion")
|
||||
set(cxx_exception_flags "-fexceptions")
|
||||
|
@ -505,24 +505,21 @@ inline void PrintTo(unsigned char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
#ifdef __cpp_char8_t
|
||||
inline void PrintTo(const char8_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
// Overloads for u8 strings.
|
||||
void PrintTo(const char8_t* s, ::std::ostream* os);
|
||||
inline void PrintTo(char8_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
PrintTo(ImplicitCast_<const char8_t*>(s), os);
|
||||
}
|
||||
#endif
|
||||
inline void PrintTo(const char16_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
// Overloads for u16 strings.
|
||||
void PrintTo(const char16_t* s, ::std::ostream* os);
|
||||
inline void PrintTo(char16_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(const char32_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
PrintTo(ImplicitCast_<const char16_t*>(s), os);
|
||||
}
|
||||
// Overloads for u32 strings.
|
||||
void PrintTo(const char32_t* s, ::std::ostream* os);
|
||||
inline void PrintTo(char32_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
PrintTo(ImplicitCast_<const char32_t*>(s), os);
|
||||
}
|
||||
|
||||
// MSVC can be configured to define wchar_t as a typedef of unsigned
|
||||
@ -558,6 +555,26 @@ inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::std::u8string
|
||||
#ifdef __cpp_char8_t
|
||||
GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) {
|
||||
PrintU8StringTo(s, os);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Overloads for ::std::u16string
|
||||
GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) {
|
||||
PrintU16StringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::std::u32string
|
||||
GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) {
|
||||
PrintU32StringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::std::wstring.
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
|
||||
@ -805,6 +822,20 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
|
||||
GTEST_API_ void UniversalPrintArray(
|
||||
const char* begin, size_t len, ::std::ostream* os);
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
// This overload prints a (const) char8_t array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(const char8_t* begin, size_t len,
|
||||
::std::ostream* os);
|
||||
#endif
|
||||
|
||||
// This overload prints a (const) char16_t array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(const char16_t* begin, size_t len,
|
||||
::std::ostream* os);
|
||||
|
||||
// This overload prints a (const) char32_t array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(const char32_t* begin, size_t len,
|
||||
::std::ostream* os);
|
||||
|
||||
// This overload prints a (const) wchar_t array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(
|
||||
const wchar_t* begin, size_t len, ::std::ostream* os);
|
||||
@ -877,12 +908,55 @@ class UniversalTersePrinter<const char*> {
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<char*> {
|
||||
class UniversalTersePrinter<char*> : public UniversalTersePrinter<const char*> {
|
||||
};
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
template <>
|
||||
class UniversalTersePrinter<const char8_t*> {
|
||||
public:
|
||||
static void Print(char* str, ::std::ostream* os) {
|
||||
UniversalTersePrinter<const char*>::Print(str, os);
|
||||
static void Print(const char8_t* str, ::std::ostream* os) {
|
||||
if (str == nullptr) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(::std::u8string(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<char8_t*>
|
||||
: public UniversalTersePrinter<const char8_t*> {};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
class UniversalTersePrinter<const char16_t*> {
|
||||
public:
|
||||
static void Print(const char16_t* str, ::std::ostream* os) {
|
||||
if (str == nullptr) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(::std::u16string(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<char16_t*>
|
||||
: public UniversalTersePrinter<const char16_t*> {};
|
||||
|
||||
template <>
|
||||
class UniversalTersePrinter<const char32_t*> {
|
||||
public:
|
||||
static void Print(const char32_t* str, ::std::ostream* os) {
|
||||
if (str == nullptr) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(::std::u32string(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<char32_t*>
|
||||
: public UniversalTersePrinter<const char32_t*> {};
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
template <>
|
||||
|
@ -1936,6 +1936,19 @@ inline bool IsUpper(char ch) {
|
||||
inline bool IsXDigit(char ch) {
|
||||
return isxdigit(static_cast<unsigned char>(ch)) != 0;
|
||||
}
|
||||
#ifdef __cpp_char8_t
|
||||
inline bool IsXDigit(char8_t ch) {
|
||||
return isxdigit(static_cast<unsigned char>(ch)) != 0;
|
||||
}
|
||||
#endif
|
||||
inline bool IsXDigit(char16_t ch) {
|
||||
const unsigned char low_byte = static_cast<unsigned char>(ch);
|
||||
return ch == low_byte && isxdigit(low_byte) != 0;
|
||||
}
|
||||
inline bool IsXDigit(char32_t ch) {
|
||||
const unsigned char low_byte = static_cast<unsigned char>(ch);
|
||||
return ch == low_byte && isxdigit(low_byte) != 0;
|
||||
}
|
||||
inline bool IsXDigit(wchar_t ch) {
|
||||
const unsigned char low_byte = static_cast<unsigned char>(ch);
|
||||
return ch == low_byte && isxdigit(low_byte) != 0;
|
||||
|
@ -42,12 +42,16 @@
|
||||
// defines Foo.
|
||||
|
||||
#include "gtest/gtest-printers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <cwchar>
|
||||
#include <ostream> // NOLINT
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "src/gtest-internal-inl.h"
|
||||
|
||||
@ -103,6 +107,16 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
|
||||
*os << ">";
|
||||
}
|
||||
|
||||
// Helpers for widening a character to char32_t. Since the standard does not
|
||||
// specify if char / wchar_t is signed or unsigned, it is important to first
|
||||
// convert it to the unsigned type of the same width before widening it to
|
||||
// char32_t.
|
||||
template <typename CharType>
|
||||
char32_t ToChar32(CharType in) {
|
||||
return static_cast<char32_t>(
|
||||
static_cast<typename std::make_unsigned<CharType>::type>(in));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace internal {
|
||||
@ -131,18 +145,15 @@ enum CharFormat {
|
||||
// Returns true if c is a printable ASCII character. We test the
|
||||
// value of c directly instead of calling isprint(), which is buggy on
|
||||
// Windows Mobile.
|
||||
inline bool IsPrintableAscii(wchar_t c) {
|
||||
return 0x20 <= c && c <= 0x7E;
|
||||
}
|
||||
inline bool IsPrintableAscii(char32_t c) { return 0x20 <= c && c <= 0x7E; }
|
||||
|
||||
// Prints a wide or narrow char c as a character literal without the
|
||||
// quotes, escaping it when necessary; returns how c was formatted.
|
||||
// The template argument UnsignedChar is the unsigned version of Char,
|
||||
// which is the type of c.
|
||||
template <typename UnsignedChar, typename Char>
|
||||
// Prints c (of type char, char8_t, char16_t, char32_t, or wchar_t) as a
|
||||
// character literal without the quotes, escaping it when necessary; returns how
|
||||
// c was formatted.
|
||||
template <typename Char>
|
||||
static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
||||
wchar_t w_c = static_cast<wchar_t>(c);
|
||||
switch (w_c) {
|
||||
const char32_t u_c = ToChar32(c);
|
||||
switch (u_c) {
|
||||
case L'\0':
|
||||
*os << "\\0";
|
||||
break;
|
||||
@ -174,13 +185,12 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
||||
*os << "\\v";
|
||||
break;
|
||||
default:
|
||||
if (IsPrintableAscii(w_c)) {
|
||||
if (IsPrintableAscii(u_c)) {
|
||||
*os << static_cast<char>(c);
|
||||
return kAsIs;
|
||||
} else {
|
||||
ostream::fmtflags flags = os->flags();
|
||||
*os << "\\x" << std::hex << std::uppercase
|
||||
<< static_cast<int>(static_cast<UnsignedChar>(c));
|
||||
*os << "\\x" << std::hex << std::uppercase << static_cast<int>(u_c);
|
||||
os->flags(flags);
|
||||
return kHexEscape;
|
||||
}
|
||||
@ -188,9 +198,9 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
||||
return kSpecialEscape;
|
||||
}
|
||||
|
||||
// Prints a wchar_t c as if it's part of a string literal, escaping it when
|
||||
// Prints a char32_t c as if it's part of a string literal, escaping it when
|
||||
// necessary; returns how c was formatted.
|
||||
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
||||
static CharFormat PrintAsStringLiteralTo(char32_t c, ostream* os) {
|
||||
switch (c) {
|
||||
case L'\'':
|
||||
*os << "'";
|
||||
@ -199,26 +209,68 @@ static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
||||
*os << "\\\"";
|
||||
return kSpecialEscape;
|
||||
default:
|
||||
return PrintAsCharLiteralTo<wchar_t>(c, os);
|
||||
return PrintAsCharLiteralTo(c, os);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* GetCharWidthPrefix(char) {
|
||||
return "";
|
||||
}
|
||||
|
||||
static const char* GetCharWidthPrefix(signed char) {
|
||||
return "";
|
||||
}
|
||||
|
||||
static const char* GetCharWidthPrefix(unsigned char) {
|
||||
return "";
|
||||
}
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
static const char* GetCharWidthPrefix(char8_t) {
|
||||
return "u8";
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char* GetCharWidthPrefix(char16_t) {
|
||||
return "u";
|
||||
}
|
||||
|
||||
static const char* GetCharWidthPrefix(char32_t) {
|
||||
return "U";
|
||||
}
|
||||
|
||||
static const char* GetCharWidthPrefix(wchar_t) {
|
||||
return "L";
|
||||
}
|
||||
|
||||
// Prints a char c as if it's part of a string literal, escaping it when
|
||||
// necessary; returns how c was formatted.
|
||||
static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
|
||||
return PrintAsStringLiteralTo(
|
||||
static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
|
||||
return PrintAsStringLiteralTo(ToChar32(c), os);
|
||||
}
|
||||
|
||||
// Prints a wide or narrow character c and its code. '\0' is printed
|
||||
// as "'\\0'", other unprintable characters are also properly escaped
|
||||
// using the standard C++ escape sequence. The template argument
|
||||
// UnsignedChar is the unsigned version of Char, which is the type of c.
|
||||
template <typename UnsignedChar, typename Char>
|
||||
#ifdef __cpp_char8_t
|
||||
static CharFormat PrintAsStringLiteralTo(char8_t c, ostream* os) {
|
||||
return PrintAsStringLiteralTo(ToChar32(c), os);
|
||||
}
|
||||
#endif
|
||||
|
||||
static CharFormat PrintAsStringLiteralTo(char16_t c, ostream* os) {
|
||||
return PrintAsStringLiteralTo(ToChar32(c), os);
|
||||
}
|
||||
|
||||
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
||||
return PrintAsStringLiteralTo(ToChar32(c), os);
|
||||
}
|
||||
|
||||
// Prints a character c (of type char, char8_t, char16_t, char32_t, or wchar_t)
|
||||
// and its code. '\0' is printed as "'\\0'", other unprintable characters are
|
||||
// also properly escaped using the standard C++ escape sequence.
|
||||
template <typename Char>
|
||||
void PrintCharAndCodeTo(Char c, ostream* os) {
|
||||
// First, print c as a literal in the most readable form we can find.
|
||||
*os << ((sizeof(c) > 1) ? "L'" : "'");
|
||||
const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
|
||||
*os << GetCharWidthPrefix(c) << "'";
|
||||
const CharFormat format = PrintAsCharLiteralTo(c, os);
|
||||
*os << "'";
|
||||
|
||||
// To aid user debugging, we also print c's code in decimal, unless
|
||||
@ -239,26 +291,21 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
void PrintTo(unsigned char c, ::std::ostream* os) {
|
||||
PrintCharAndCodeTo<unsigned char>(c, os);
|
||||
}
|
||||
void PrintTo(signed char c, ::std::ostream* os) {
|
||||
PrintCharAndCodeTo<unsigned char>(c, os);
|
||||
}
|
||||
void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
|
||||
void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
|
||||
|
||||
// Prints a wchar_t as a symbol if it is printable or as its internal
|
||||
// code otherwise and also as its code. L'\0' is printed as "L'\\0'".
|
||||
void PrintTo(wchar_t wc, ostream* os) {
|
||||
PrintCharAndCodeTo<wchar_t>(wc, os);
|
||||
}
|
||||
void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); }
|
||||
|
||||
// TODO(dcheng): Consider making this delegate to PrintCharAndCodeTo() as well.
|
||||
void PrintTo(char32_t c, ::std::ostream* os) {
|
||||
*os << std::hex << "U+" << std::uppercase << std::setfill('0') << std::setw(4)
|
||||
<< static_cast<uint32_t>(c);
|
||||
}
|
||||
|
||||
// Prints the given array of characters to the ostream. CharType must be either
|
||||
// char or wchar_t.
|
||||
// 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.
|
||||
template <typename CharType>
|
||||
@ -268,8 +315,8 @@ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
||||
static CharFormat PrintCharsAsStringTo(
|
||||
const CharType* begin, size_t len, ostream* os) {
|
||||
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
|
||||
*os << kQuoteBegin;
|
||||
const char* const quote_prefix = GetCharWidthPrefix(*begin);
|
||||
*os << quote_prefix << "\"";
|
||||
bool is_previous_hex = false;
|
||||
CharFormat print_format = kAsIs;
|
||||
for (size_t index = 0; index < len; ++index) {
|
||||
@ -278,7 +325,7 @@ static CharFormat PrintCharsAsStringTo(
|
||||
// Previous character is of '\x..' form and this character can be
|
||||
// interpreted as another hexadecimal digit in its number. Break string to
|
||||
// disambiguate.
|
||||
*os << "\" " << kQuoteBegin;
|
||||
*os << "\" " << quote_prefix << "\"";
|
||||
}
|
||||
is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
|
||||
// Remember if any characters required hex escaping.
|
||||
@ -324,22 +371,57 @@ void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
// Prints a (const) char8_t array of 'len' elements, starting at address
|
||||
// 'begin'.
|
||||
void UniversalPrintArray(const char8_t* begin, size_t len, ostream* os) {
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Prints a (const) char16_t array of 'len' elements, starting at address
|
||||
// 'begin'.
|
||||
void UniversalPrintArray(const char16_t* begin, size_t len, ostream* os) {
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
|
||||
// Prints a (const) char32_t array of 'len' elements, starting at address
|
||||
// 'begin'.
|
||||
void UniversalPrintArray(const char32_t* begin, size_t len, ostream* os) {
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
|
||||
// Prints a (const) wchar_t array of 'len' elements, starting at address
|
||||
// 'begin'.
|
||||
void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
|
||||
// Prints the given C string to the ostream.
|
||||
void PrintTo(const char* s, ostream* os) {
|
||||
namespace {
|
||||
|
||||
// Prints a null-terminated C-style string to the ostream.
|
||||
template <typename Char>
|
||||
void PrintCStringTo(const Char* s, ostream* os) {
|
||||
if (s == nullptr) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
||||
PrintCharsAsStringTo(s, strlen(s), os);
|
||||
PrintCharsAsStringTo(s, std::char_traits<Char>::length(s), os);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void PrintTo(const char* s, ostream* os) { PrintCStringTo(s, os); }
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
void PrintTo(const char8_t* s, ostream* os) { PrintCStringTo(s, os); }
|
||||
#endif
|
||||
|
||||
void PrintTo(const char16_t* s, ostream* os) { PrintCStringTo(s, os); }
|
||||
|
||||
void PrintTo(const char32_t* s, ostream* os) { PrintCStringTo(s, os); }
|
||||
|
||||
// MSVC compiler can be configured to define whar_t as a typedef
|
||||
// of unsigned short. Defining an overload for const wchar_t* in that case
|
||||
// would cause pointers to unsigned shorts be printed as wide strings,
|
||||
@ -348,14 +430,7 @@ void PrintTo(const char* s, ostream* os) {
|
||||
// wchar_t is implemented as a native type.
|
||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
// Prints the given wide C string to the ostream.
|
||||
void PrintTo(const wchar_t* s, ostream* os) {
|
||||
if (s == nullptr) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
||||
PrintCharsAsStringTo(s, wcslen(s), os);
|
||||
}
|
||||
}
|
||||
void PrintTo(const wchar_t* s, ostream* os) { PrintCStringTo(s, os); }
|
||||
#endif // wchar_t is native
|
||||
|
||||
namespace {
|
||||
@ -433,6 +508,20 @@ void PrintStringTo(const ::std::string& s, ostream* os) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
void PrintU8StringTo(const ::std::u8string& s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
#endif
|
||||
|
||||
void PrintU16StringTo(const ::std::u16string& s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
|
||||
void PrintU32StringTo(const ::std::u32string& s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
|
@ -83,6 +83,10 @@ cc_test(
|
||||
copts = select({
|
||||
"//:windows": ["-DGTEST_USE_OWN_TR1_TUPLE=0"],
|
||||
"//conditions:default": ["-DGTEST_USE_OWN_TR1_TUPLE=1"],
|
||||
}) + select({
|
||||
# Ensure MSVC treats source files as UTF-8 encoded.
|
||||
"//:msvc_compiler": ["-utf-8"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
includes = [
|
||||
"googletest",
|
||||
|
@ -493,6 +493,92 @@ TEST(PrintCStringTest, EscapesProperly) {
|
||||
Print(p));
|
||||
}
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
// const char8_t*.
|
||||
TEST(PrintU8StringTest, Const) {
|
||||
const char8_t* p = u8"界";
|
||||
EXPECT_EQ(PrintPointer(p) + " pointing to u8\"\\xE7\\x95\\x8C\"", Print(p));
|
||||
}
|
||||
|
||||
// char8_t*.
|
||||
TEST(PrintU8StringTest, NonConst) {
|
||||
char8_t p[] = u8"世";
|
||||
EXPECT_EQ(PrintPointer(p) + " pointing to u8\"\\xE4\\xB8\\x96\"",
|
||||
Print(static_cast<char8_t*>(p)));
|
||||
}
|
||||
|
||||
// NULL u8 string.
|
||||
TEST(PrintU8StringTest, Null) {
|
||||
const char8_t* p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
// Tests that u8 strings are escaped properly.
|
||||
TEST(PrintU8StringTest, EscapesProperly) {
|
||||
const char8_t* p = u8"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 世界";
|
||||
EXPECT_EQ(PrintPointer(p) +
|
||||
" pointing to u8\"'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\\x7F\\xFF "
|
||||
"hello \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"",
|
||||
Print(p));
|
||||
}
|
||||
#endif
|
||||
|
||||
// const char16_t*.
|
||||
TEST(PrintU16StringTest, Const) {
|
||||
const char16_t* p = u"界";
|
||||
EXPECT_EQ(PrintPointer(p) + " pointing to u\"\\x754C\"", Print(p));
|
||||
}
|
||||
|
||||
// char16_t*.
|
||||
TEST(PrintU16StringTest, NonConst) {
|
||||
char16_t p[] = u"世";
|
||||
EXPECT_EQ(PrintPointer(p) + " pointing to u\"\\x4E16\"",
|
||||
Print(static_cast<char16_t*>(p)));
|
||||
}
|
||||
|
||||
// NULL u16 string.
|
||||
TEST(PrintU16StringTest, Null) {
|
||||
const char16_t* p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
// Tests that u16 strings are escaped properly.
|
||||
TEST(PrintU16StringTest, EscapesProperly) {
|
||||
const char16_t* p = u"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 世界";
|
||||
EXPECT_EQ(PrintPointer(p) +
|
||||
" pointing to u\"'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\\x7F\\xFF "
|
||||
"hello \\x4E16\\x754C\"",
|
||||
Print(p));
|
||||
}
|
||||
|
||||
// const char32_t*.
|
||||
TEST(PrintU32StringTest, Const) {
|
||||
const char32_t* p = U"🗺️";
|
||||
EXPECT_EQ(PrintPointer(p) + " pointing to U\"\\x1F5FA\\xFE0F\"", Print(p));
|
||||
}
|
||||
|
||||
// char32_t*.
|
||||
TEST(PrintU32StringTest, NonConst) {
|
||||
char32_t p[] = U"🌌";
|
||||
EXPECT_EQ(PrintPointer(p) + " pointing to U\"\\x1F30C\"",
|
||||
Print(static_cast<char32_t*>(p)));
|
||||
}
|
||||
|
||||
// NULL u32 string.
|
||||
TEST(PrintU32StringTest, Null) {
|
||||
const char32_t* p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
// Tests that u32 strings are escaped properly.
|
||||
TEST(PrintU32StringTest, EscapesProperly) {
|
||||
const char32_t* p = U"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 🗺️";
|
||||
EXPECT_EQ(PrintPointer(p) +
|
||||
" pointing to U\"'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\\x7F\\xFF "
|
||||
"hello \\x1F5FA\\xFE0F\"",
|
||||
Print(p));
|
||||
}
|
||||
|
||||
// MSVC compiler can be configured to define whar_t as a typedef
|
||||
// of unsigned short. Defining an overload for const wchar_t* in that case
|
||||
// would cause pointers to unsigned shorts be printed as wide strings,
|
||||
@ -564,56 +650,6 @@ TEST(PrintCharPointerTest, ConstUnsignedChar) {
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
// char8_t*
|
||||
TEST(PrintCharPointerTest, Char8) {
|
||||
char8_t* p = reinterpret_cast<char8_t*>(0x1234);
|
||||
EXPECT_EQ(PrintPointer(p), Print(p));
|
||||
p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
// const char8_t*
|
||||
TEST(PrintCharPointerTest, ConstChar8) {
|
||||
const char8_t* p = reinterpret_cast<const char8_t*>(0x1234);
|
||||
EXPECT_EQ(PrintPointer(p), Print(p));
|
||||
p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
#endif
|
||||
|
||||
// char16_t*
|
||||
TEST(PrintCharPointerTest, Char16) {
|
||||
char16_t* p = reinterpret_cast<char16_t*>(0x1234);
|
||||
EXPECT_EQ(PrintPointer(p), Print(p));
|
||||
p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
// const char16_t*
|
||||
TEST(PrintCharPointerTest, ConstChar16) {
|
||||
const char16_t* p = reinterpret_cast<const char16_t*>(0x1234);
|
||||
EXPECT_EQ(PrintPointer(p), Print(p));
|
||||
p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
// char32_t*
|
||||
TEST(PrintCharPointerTest, Char32) {
|
||||
char32_t* p = reinterpret_cast<char32_t*>(0x1234);
|
||||
EXPECT_EQ(PrintPointer(p), Print(p));
|
||||
p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
// const char32_t*
|
||||
TEST(PrintCharPointerTest, ConstChar32) {
|
||||
const char32_t* p = reinterpret_cast<const char32_t*>(0x1234);
|
||||
EXPECT_EQ(PrintPointer(p), Print(p));
|
||||
p = nullptr;
|
||||
EXPECT_EQ("NULL", Print(p));
|
||||
}
|
||||
|
||||
// Tests printing pointers to simple, built-in types.
|
||||
|
||||
// bool*.
|
||||
@ -753,64 +789,70 @@ TEST(PrintArrayTest, CharArrayWithNoTerminatingNul) {
|
||||
EXPECT_EQ("\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// const char array with terminating NUL.
|
||||
TEST(PrintArrayTest, ConstCharArrayWithTerminatingNul) {
|
||||
// char array with terminating NUL.
|
||||
TEST(PrintArrayTest, CharArrayWithTerminatingNul) {
|
||||
const char a[] = "\0Hi";
|
||||
EXPECT_EQ("\"\\0Hi\"", PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// const wchar_t array without terminating NUL.
|
||||
#ifdef __cpp_char8_t
|
||||
// char_t array without terminating NUL.
|
||||
TEST(PrintArrayTest, Char8ArrayWithNoTerminatingNul) {
|
||||
// Array a contains '\0' in the middle and doesn't end with '\0'.
|
||||
const char8_t a[] = {u8'H', u8'\0', u8'i'};
|
||||
EXPECT_EQ("u8\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// char8_t array with terminating NUL.
|
||||
TEST(PrintArrayTest, Char8ArrayWithTerminatingNul) {
|
||||
const char8_t a[] = u8"\0世界";
|
||||
EXPECT_EQ(
|
||||
"u8\"\\0\\xE4\\xB8\\x96\\xE7\\x95\\x8C\"",
|
||||
PrintArrayHelper(a));
|
||||
}
|
||||
#endif
|
||||
|
||||
// const char16_t array without terminating NUL.
|
||||
TEST(PrintArrayTest, Char16ArrayWithNoTerminatingNul) {
|
||||
// Array a contains '\0' in the middle and doesn't end with '\0'.
|
||||
const char16_t a[] = {u'こ', u'\0', u'ん', u'に', u'ち', u'は'};
|
||||
EXPECT_EQ("u\"\\x3053\\0\\x3093\\x306B\\x3061\\x306F\" (no terminating NUL)",
|
||||
PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// char16_t array with terminating NUL.
|
||||
TEST(PrintArrayTest, Char16ArrayWithTerminatingNul) {
|
||||
const char16_t a[] = u"\0こんにちは";
|
||||
EXPECT_EQ("u\"\\0\\x3053\\x3093\\x306B\\x3061\\x306F\"", PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// char32_t array without terminating NUL.
|
||||
TEST(PrintArrayTest, Char32ArrayWithNoTerminatingNul) {
|
||||
// Array a contains '\0' in the middle and doesn't end with '\0'.
|
||||
const char32_t a[] = {U'👋', U'\0', U'🌌'};
|
||||
EXPECT_EQ("U\"\\x1F44B\\0\\x1F30C\" (no terminating NUL)",
|
||||
PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// char32_t array with terminating NUL.
|
||||
TEST(PrintArrayTest, Char32ArrayWithTerminatingNul) {
|
||||
const char32_t a[] = U"\0👋🌌";
|
||||
EXPECT_EQ("U\"\\0\\x1F44B\\x1F30C\"", PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// wchar_t array without terminating NUL.
|
||||
TEST(PrintArrayTest, WCharArrayWithNoTerminatingNul) {
|
||||
// Array a contains '\0' in the middle and doesn't end with '\0'.
|
||||
const wchar_t a[] = { L'H', L'\0', L'i' };
|
||||
const wchar_t a[] = {L'H', L'\0', L'i'};
|
||||
EXPECT_EQ("L\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// wchar_t array with terminating NUL.
|
||||
TEST(PrintArrayTest, WConstCharArrayWithTerminatingNul) {
|
||||
TEST(PrintArrayTest, WCharArrayWithTerminatingNul) {
|
||||
const wchar_t a[] = L"\0Hi";
|
||||
EXPECT_EQ("L\"\\0Hi\"", PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
// char8_t array.
|
||||
TEST(PrintArrayTest, Char8Array) {
|
||||
const char8_t a[] = u8"Hello, world!";
|
||||
EXPECT_EQ(
|
||||
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+0077, "
|
||||
"U+006F, U+0072, U+006C, U+0064, U+0021, U+0000 }",
|
||||
PrintArrayHelper(a));
|
||||
}
|
||||
#endif
|
||||
|
||||
// char16_t array.
|
||||
#ifdef _MSC_VER
|
||||
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
|
||||
TEST(PrintArrayTest, DISABLED_Char16Array) {
|
||||
#else
|
||||
TEST(PrintArrayTest, Char16Array) {
|
||||
#endif
|
||||
const char16_t a[] = u"Hello, 世界";
|
||||
EXPECT_EQ(
|
||||
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
|
||||
"U+754C, U+0000 }",
|
||||
PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// char32_t array.
|
||||
#ifdef _MSC_VER
|
||||
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
|
||||
TEST(PrintArrayTest, DISABLED_Char32Array) {
|
||||
#else
|
||||
TEST(PrintArrayTest, Char32Array) {
|
||||
#endif
|
||||
const char32_t a[] = U"Hello, 世界";
|
||||
EXPECT_EQ(
|
||||
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
|
||||
"U+754C, U+0000 }",
|
||||
PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// Array of objects.
|
||||
TEST(PrintArrayTest, ObjectArray) {
|
||||
std::string a[3] = {"Hi", "Hello", "Ni hao"};
|
||||
@ -872,41 +914,22 @@ TEST(PrintWideStringTest, StringAmbiguousHex) {
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
TEST(PrintStringTest, U8String) {
|
||||
std::u8string str = u8"Hello, world!";
|
||||
std::u8string str = u8"Hello, 世界";
|
||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||
EXPECT_EQ(
|
||||
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+0077, "
|
||||
"U+006F, U+0072, U+006C, U+0064, U+0021 }",
|
||||
Print(str));
|
||||
EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
|
||||
TEST(PrintStringTest, DISABLED_U16String) {
|
||||
#else
|
||||
TEST(PrintStringTest, U16String) {
|
||||
#endif
|
||||
std::u16string str = u"Hello, 世界";
|
||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||
EXPECT_EQ(
|
||||
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
|
||||
"U+754C }",
|
||||
Print(str));
|
||||
EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str));
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
|
||||
TEST(PrintStringTest, DISABLED_U32String) {
|
||||
#else
|
||||
TEST(PrintStringTest, U32String) {
|
||||
#endif
|
||||
std::u32string str = U"Hello, 世界";
|
||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||
EXPECT_EQ(
|
||||
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
|
||||
"U+754C }",
|
||||
Print(str));
|
||||
std::u32string 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
|
||||
|
Loading…
Reference in New Issue
Block a user