| // { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE -DUNICODE_ENC" { target le } } |
| // { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE -DUNICODE_ENC" { target be } } |
| // { dg-do run { target c++23 } } |
| // { dg-add-options no_pch } |
| |
| #include <format> |
| #include <testsuite_hooks.h> |
| |
| std::string |
| fdebug(char t) |
| { return std::format("{:?}", t); } |
| |
| std::wstring |
| fdebug(wchar_t t) |
| { return std::format(L"{:?}", t); } |
| |
| std::string |
| fdebug(std::string_view t) |
| { return std::format("{:?}", t); } |
| |
| std::wstring |
| fdebug(std::wstring_view t) |
| { return std::format(L"{:?}", t); } |
| |
| |
| #define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) |
| #define WIDEN(S) WIDEN_(_CharT, S) |
| |
| template<typename _CharT> |
| void |
| test_basic_escapes() |
| { |
| std::basic_string<_CharT> res; |
| |
| const auto tab = WIDEN("\t"); |
| res = fdebug(tab); |
| VERIFY( res == WIDEN(R"("\t")") ); |
| res = fdebug(tab[0]); |
| VERIFY( res == WIDEN(R"('\t')") ); |
| |
| const auto nline = WIDEN("\n"); |
| res = fdebug(nline); |
| VERIFY( res == WIDEN(R"("\n")") ); |
| res = fdebug(nline[0]); |
| VERIFY( res == WIDEN(R"('\n')") ); |
| |
| const auto carret = WIDEN("\r"); |
| res = fdebug(carret); |
| VERIFY( res == WIDEN(R"("\r")") ); |
| res = fdebug(carret[0]); |
| VERIFY( res == WIDEN(R"('\r')") ); |
| |
| const auto bslash = WIDEN("\\"); |
| res = fdebug(bslash); |
| VERIFY( res == WIDEN(R"("\\")") ); |
| res = fdebug(bslash[0]); |
| VERIFY( res == WIDEN(R"('\\')") ); |
| |
| const auto quote = WIDEN("\""); |
| res = fdebug(quote); |
| VERIFY( res == WIDEN(R"("\"")") ); |
| res = fdebug(quote[0]); |
| VERIFY( res == WIDEN(R"('"')") ); |
| |
| const auto apos = WIDEN("\'"); |
| res = fdebug(apos); |
| VERIFY( res == WIDEN(R"("'")") ); |
| res = fdebug(apos[0]); |
| VERIFY( res == WIDEN(R"('\'')") ); |
| } |
| |
| template<typename _CharT> |
| void |
| test_ascii_escapes() |
| { |
| std::basic_string<_CharT> res; |
| |
| const auto in = WIDEN("\x10 abcde\x7f\t0123"); |
| res = fdebug(in); |
| VERIFY( res == WIDEN(R"("\u{10} abcde\u{7f}\t0123")") ); |
| res = fdebug(in[0]); |
| VERIFY( res == WIDEN(R"('\u{10}')") ); |
| res = fdebug(in[1]); |
| VERIFY( res == WIDEN(R"(' ')") ); |
| res = fdebug(in[2]); |
| VERIFY( res == WIDEN(R"('a')") ); |
| } |
| |
| template<typename _CharT> |
| void |
| test_extended_ascii() |
| { |
| std::basic_string<_CharT> res; |
| |
| const auto in = WIDEN("Åëÿ"); |
| res = fdebug(in); |
| VERIFY( res == WIDEN(R"("Åëÿ")") ); |
| |
| static constexpr bool __test_characters |
| #if UNICODE_ENC |
| = sizeof(_CharT) >= 2; |
| #else // ISO8859-1 |
| = true; |
| #endif // UNICODE_ENC |
| |
| if constexpr (__test_characters) |
| { |
| res = fdebug(in[0]); |
| VERIFY( res == WIDEN(R"('Å')") ); |
| res = fdebug(in[1]); |
| VERIFY( res == WIDEN(R"('ë')") ); |
| res = fdebug(in[2]); |
| VERIFY( res == WIDEN(R"('ÿ')") ); |
| } |
| } |
| |
| #if UNICODE_ENC |
| template<typename _CharT> |
| void |
| test_unicode_escapes() |
| { |
| std::basic_string<_CharT> res; |
| |
| const auto in = WIDEN( |
| "\u008a" // Cc, Control, Line Tabulation Set, |
| "\u00ad" // Cf, Format, Soft Hyphen |
| "\u1d3d" // Lm, Modifier letter, Modifier Letter Capital Ou |
| "\u00a0" // Zs, Space Separator, No-Break Space (NBSP) |
| "\u2029" // Zp, Paragraph Separator, Paragraph Separator |
| "\U0001f984" // So, Other Symbol, Unicorn Face |
| ); |
| const auto out = WIDEN("\"" |
| R"(\u{8a})" |
| R"(\u{ad})" |
| "\u1d3d" |
| R"(\u{a0})" |
| R"(\u{2029})" |
| "\U0001f984" |
| "\""); |
| |
| res = fdebug(in); |
| VERIFY( res == out ); |
| |
| if constexpr (sizeof(_CharT) >= 2) |
| { |
| res = fdebug(in[0]); |
| VERIFY( res == WIDEN(R"('\u{8a}')") ); |
| res = fdebug(in[1]); |
| VERIFY( res == WIDEN(R"('\u{ad}')") ); |
| res = fdebug(in[2]); |
| VERIFY( res == WIDEN("'\u1d3d'") ); |
| res = fdebug(in[3]); |
| VERIFY( res == WIDEN(R"('\u{a0}')") ); |
| res = fdebug(in[4]); |
| VERIFY( res == WIDEN(R"('\u{2029}')") ); |
| } |
| |
| if constexpr (sizeof(_CharT) >= 4) |
| { |
| res = fdebug(in[5]); |
| VERIFY( res == WIDEN("'\U0001f984'") ); |
| } |
| } |
| |
| template<typename _CharT> |
| void |
| test_grapheme_extend() |
| { |
| std::basic_string<_CharT> res; |
| |
| const auto vin = WIDEN("o\u0302\u0323"); |
| res = fdebug(vin); |
| VERIFY( res == WIDEN("\"o\u0302\u0323\"") ); |
| |
| std::basic_string_view<_CharT> in = WIDEN("\t\u0302\u0323"); |
| res = fdebug(in); |
| VERIFY( res == WIDEN(R"("\t\u{302}\u{323}")") ); |
| |
| res = fdebug(in.substr(1)); |
| VERIFY( res == WIDEN(R"("\u{302}\u{323}")") ); |
| |
| if constexpr (sizeof(_CharT) >= 2) |
| { |
| res = fdebug(in[1]); |
| VERIFY( res == WIDEN(R"('\u{302}')") ); |
| } |
| } |
| |
| template<typename _CharT> |
| void |
| test_replacement_char() |
| { |
| std::basic_string<_CharT> repl = WIDEN("\uFFFD"); |
| std::basic_string<_CharT> res = fdebug(repl); |
| VERIFY( res == WIDEN("\"\uFFFD\"") ); |
| |
| repl = WIDEN("\uFFFD\uFFFD"); |
| res = fdebug(repl); |
| VERIFY( res == WIDEN("\"\uFFFD\uFFFD\"") ); |
| } |
| |
| void |
| test_ill_formed_utf8_seq() |
| { |
| std::string_view seq = "\xf0\x9f\xa6\x84"; // \U0001F984 |
| std::string res; |
| |
| res = fdebug(seq); |
| VERIFY( res == "\"\U0001F984\"" ); |
| |
| res = fdebug(seq.substr(1)); |
| VERIFY( res == R"("\x{9f}\x{a6}\x{84}")" ); |
| |
| res = fdebug(seq.substr(2)); |
| VERIFY( res == R"("\x{a6}\x{84}")" ); |
| |
| res = fdebug(seq[0]); |
| VERIFY( res == R"('\x{f0}')" ); |
| res = fdebug(seq.substr(0, 1)); |
| VERIFY( res == R"("\x{f0}")" ); |
| |
| res = fdebug(seq[1]); |
| VERIFY( res == R"('\x{9f}')" ); |
| res = fdebug(seq.substr(1, 1)); |
| VERIFY( res == R"("\x{9f}")" ); |
| |
| res = fdebug(seq[2]); |
| VERIFY( res == R"('\x{a6}')" ); |
| res = fdebug(seq.substr(2, 1)); |
| VERIFY( res == R"("\x{a6}")" ); |
| |
| res = fdebug(seq[3]); |
| VERIFY( res == R"('\x{84}')" ); |
| res = fdebug(seq.substr(3, 1)); |
| VERIFY( res == R"("\x{84}")" ); |
| } |
| |
| void |
| test_ill_formed_utf32() |
| { |
| std::wstring res; |
| |
| wchar_t ic1 = static_cast<wchar_t>(0xff'ffff); |
| res = fdebug(ic1); |
| VERIFY( res == LR"('\x{ffffff}')" ); |
| |
| std::wstring is1(1, ic1); |
| res = fdebug(is1); |
| VERIFY( res == LR"("\x{ffffff}")" ); |
| |
| wchar_t ic2 = static_cast<wchar_t>(0xffff'ffff); |
| res = fdebug(ic2); |
| VERIFY( res == LR"('\x{ffffffff}')" ); |
| |
| std::wstring is2(1, ic2); |
| res = fdebug(is2); |
| VERIFY( res == LR"("\x{ffffffff}")" ); |
| } |
| #endif // UNICODE_ENC |
| |
| template<typename _CharT> |
| void |
| test_fill() |
| { |
| std::basic_string<_CharT> res; |
| |
| std::basic_string_view<_CharT> in = WIDEN("a\t\x10\u00ad"); |
| res = std::format(WIDEN("{:10?}"), in.substr(0, 1)); |
| VERIFY( res == WIDEN(R"("a" )") ); |
| |
| res = std::format(WIDEN("{:->10?}"), in.substr(1, 1)); |
| VERIFY( res == WIDEN(R"(------"\t")") ); |
| |
| res = std::format(WIDEN("{:+<10?}"), in.substr(2, 1)); |
| VERIFY( res == WIDEN(R"("\u{10}"++)") ); |
| |
| |
| res = std::format(WIDEN("{:10?}"), in[0]); |
| VERIFY( res == WIDEN(R"('a' )") ); |
| |
| res = std::format(WIDEN("{:->10?}"), in[1]); |
| VERIFY( res == WIDEN(R"(------'\t')") ); |
| |
| res = std::format(WIDEN("{:+<10?}"), in[2]); |
| VERIFY( res == WIDEN(R"('\u{10}'++)") ); |
| |
| #if UNICODE_ENC |
| res = std::format(WIDEN("{:=^10?}"), in.substr(3)); |
| VERIFY( res == WIDEN(R"(="\u{ad}"=)") ); |
| |
| // width is 2 |
| std::basic_string_view<_CharT> in2 = WIDEN("\u1100"); |
| res = std::format(WIDEN("{:*^10?}"), in2); |
| VERIFY( res == WIDEN("***\"\u1100\"***") ); |
| |
| if constexpr (sizeof(_CharT) >= 2) |
| { |
| res = std::format(WIDEN("{:=^10?}"), in[3]); |
| VERIFY( res == WIDEN(R"(='\u{ad}'=)") ); |
| |
| res = std::format(WIDEN("{:*^10?}"), in2[0]); |
| VERIFY( res == WIDEN("***'\u1100'***") ); |
| } |
| #endif // UNICODE_ENC |
| } |
| |
| template<typename _CharT> |
| void |
| test_prec() |
| { |
| std::basic_string<_CharT> res; |
| // with ? escpaed presentation is copied to ouput, same as source |
| |
| std::basic_string_view<_CharT> in = WIDEN("a\t\x10\u00ad"); |
| res = std::format(WIDEN("{:.2?}"), in.substr(0, 1)); |
| VERIFY( res == WIDEN(R"("a)") ); |
| |
| res = std::format(WIDEN("{:.4?}"), in.substr(1, 1)); |
| VERIFY( res == WIDEN(R"("\t")") ); |
| |
| res = std::format(WIDEN("{:.5?}"), in.substr(2, 1)); |
| VERIFY( res == WIDEN(R"("\u{1)") ); |
| |
| #if UNICODE_ENC |
| res = std::format(WIDEN("{:.10?}"), in.substr(3)); |
| VERIFY( res == WIDEN(R"("\u{ad}")") ); |
| |
| std::basic_string_view<_CharT> in2 = WIDEN("\u1100"); |
| res = std::format(WIDEN("{:.3?}"), in2); |
| VERIFY( res == WIDEN("\"\u1100") ); |
| #endif // UNICODE_ENC |
| } |
| |
| void test_char_as_wchar() |
| { |
| std::wstring res; |
| |
| res = std::format(L"{:?}", 'a'); |
| VERIFY( res == LR"('a')" ); |
| |
| res = std::format(L"{:?}", '\t'); |
| VERIFY( res == LR"('\t')" ); |
| |
| res = std::format(L"{:+<10?}", '\x10'); |
| VERIFY( res == LR"('\u{10}'++)" ); |
| } |
| |
| template<typename T> |
| struct DebugWrapper |
| { |
| T val; |
| }; |
| |
| template<typename T, typename CharT> |
| struct std::formatter<DebugWrapper<T>, CharT> |
| { |
| constexpr std::basic_format_parse_context<CharT>::iterator |
| parse(std::basic_format_parse_context<CharT>& pc) |
| { |
| auto out = under.parse(pc); |
| under.set_debug_format(); |
| return out; |
| } |
| |
| template<typename Out> |
| Out format(DebugWrapper<T> const& t, |
| std::basic_format_context<Out, CharT>& fc) const |
| { return under.format(t.val, fc); } |
| |
| private: |
| std::formatter<T, CharT> under; |
| }; |
| |
| template<typename _CharT, typename StrT> |
| void |
| test_formatter_str() |
| { |
| _CharT buf[]{ 'a', 'b', 'c', 0 }; |
| DebugWrapper<StrT> in{ buf }; |
| std::basic_string<_CharT> res = std::format(WIDEN("{:?}"), in ); |
| VERIFY( res == WIDEN(R"("abc")") ); |
| } |
| |
| template<typename _CharT> |
| void |
| test_formatter_arr() |
| { |
| std::basic_string<_CharT> res; |
| |
| DebugWrapper<_CharT[3]> in3{ 'a', 'b', 'c' }; |
| res = std::format(WIDEN("{:?}"), in3 ); |
| VERIFY( res == WIDEN(R"("abc")") ); |
| |
| // We print all characters, including null-terminator |
| DebugWrapper<_CharT[4]> in4{ 'a', 'b', 'c', 0 }; |
| res = std::format(WIDEN("{:?}"), in4 ); |
| VERIFY( res == WIDEN(R"("abc\u{0}")") ); |
| } |
| |
| template<typename _CharT, typename SrcT> |
| void |
| test_formatter_char() |
| { |
| DebugWrapper<SrcT> in{ 'a' }; |
| std::basic_string<_CharT> res = std::format(WIDEN("{:?}"), in); |
| VERIFY( res == WIDEN(R"('a')") ); |
| } |
| |
| template<typename CharT> |
| void |
| test_formatters() |
| { |
| test_formatter_char<CharT, CharT>(); |
| test_formatter_str<CharT, CharT*>(); |
| test_formatter_str<CharT, const CharT*>(); |
| test_formatter_str<CharT, std::basic_string<CharT>>(); |
| test_formatter_str<CharT, std::basic_string_view<CharT>>(); |
| test_formatter_arr<CharT>(); |
| } |
| |
| void |
| test_formatters_c() |
| { |
| test_formatters<char>(); |
| test_formatters<wchar_t>(); |
| test_formatter_char<wchar_t, char>(); |
| } |
| |
| int main() |
| { |
| test_basic_escapes<char>(); |
| test_basic_escapes<wchar_t>(); |
| test_ascii_escapes<char>(); |
| test_ascii_escapes<wchar_t>(); |
| test_extended_ascii<char>(); |
| test_extended_ascii<wchar_t>(); |
| |
| #if UNICODE_ENC |
| test_unicode_escapes<char>(); |
| test_unicode_escapes<wchar_t>(); |
| test_grapheme_extend<char>(); |
| test_grapheme_extend<wchar_t>(); |
| test_replacement_char<char>(); |
| test_replacement_char<wchar_t>(); |
| test_ill_formed_utf8_seq(); |
| test_ill_formed_utf32(); |
| #endif // UNICODE_ENC |
| |
| test_fill<char>(); |
| test_fill<wchar_t>(); |
| test_prec<char>(); |
| test_prec<wchar_t>(); |
| |
| test_formatters_c(); |
| } |