| // { 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-require-effective-target 4byte_wchar_t } |
| // { dg-add-options no_pch } |
| // { dg-timeout-factor 2 } |
| |
| #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"('ÿ')") ); |
| } |
| } |
| |
| template<typename CharT> |
| void |
| test_unicode_escapes() |
| { |
| #if UNICODE_ENC |
| 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'") ); |
| } |
| #endif // UNICODE_ENC |
| } |
| |
| template<typename CharT> |
| void |
| test_grapheme_extend() |
| { |
| #if UNICODE_ENC |
| 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}')") ); |
| } |
| #endif // UNICODE_ENC |
| } |
| |
| template<typename CharT> |
| void |
| test_replacement_char() |
| { |
| #if UNICODE_ENC |
| 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\"") ); |
| #endif // UNICODE_ENC |
| } |
| |
| void |
| test_ill_formed_utf8_seq() |
| { |
| #if UNICODE_ENC |
| 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}")" ); |
| #endif // UNICODE_ENC |
| } |
| |
| void |
| test_ill_formed_utf32() |
| { |
| #if UNICODE_ENC |
| 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 |
| } |
| |
| bool strip_quote(std::string_view& v) |
| { |
| if (!v.starts_with('"')) |
| return false; |
| v.remove_prefix(1); |
| return true; |
| } |
| |
| bool strip_quotes(std::string_view& v) |
| { |
| if (!v.starts_with('"') || !v.ends_with('"')) |
| return false; |
| v.remove_prefix(1); |
| v.remove_suffix(1); |
| return true; |
| } |
| |
| bool strip_prefix(std::string_view& v, size_t n, char c) |
| { |
| size_t pos = v.find_first_not_of(c); |
| if (pos == std::string_view::npos) |
| pos = v.size(); |
| if (pos != n) |
| return false; |
| v.remove_prefix(n); |
| return true; |
| } |
| |
| void test_padding() |
| { |
| std::string res; |
| std::string_view resv; |
| |
| // width and size are 26 |
| std::string in = "abcdefghijklmnopqrstuvwxyz"; |
| in += in; // width and size are 52 |
| in += in; // width and size are 104 |
| in += in; // width and size are 208 |
| in += in; // width and size are 416 |
| std::string_view inv = in; |
| |
| resv = res = std::format("{}", in); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:.500}", in); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:.400}", in); |
| VERIFY( resv == inv.substr(0, 400) ); |
| |
| resv = res = std::format("{:.200}", in); |
| VERIFY( resv == inv.substr(0, 200) ); |
| |
| resv = res = std::format("{:.10}", in); |
| VERIFY( resv == inv.substr(0, 10) ); |
| |
| resv = res = std::format("{:.0}", in); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>20}", in); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>20.500}", in); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>20.400}", in); |
| VERIFY( resv == inv.substr(0, 400) ); |
| |
| resv = res = std::format("{:*>20.200}", in); |
| VERIFY( resv == inv.substr(0, 200) ); |
| |
| resv = res = std::format("{:*>20.10}", in); |
| VERIFY( strip_prefix(resv, 10, '*') ); |
| VERIFY( resv == inv.substr(0, 10) ); |
| |
| resv = res = std::format("{:*>20.0}", in); |
| VERIFY( strip_prefix(resv, 20, '*') ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>450}", in); |
| VERIFY( strip_prefix(resv, 34, '*') ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>450.500}", in); |
| VERIFY( strip_prefix(resv, 34, '*') ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>450.420}", in); |
| VERIFY( strip_prefix(resv, 34, '*') ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>450.400}", in); |
| VERIFY( strip_prefix(resv, 50, '*') ); |
| VERIFY( resv == inv.substr(0, 400) ); |
| |
| resv = res = std::format("{:*>450.200}", in); |
| VERIFY( strip_prefix(resv, 250, '*') ); |
| VERIFY( resv == inv.substr(0, 200) ); |
| |
| resv = res = std::format("{:*>450.10}", in); |
| VERIFY( strip_prefix(resv, 440, '*') ); |
| VERIFY( resv == inv.substr(0, 10) ); |
| |
| resv = res = std::format("{:*>450.0}", in); |
| VERIFY( strip_prefix(resv, 450, '*') ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:?}", in); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:.500?}", in); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:.400?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 399) ); |
| |
| resv = res = std::format("{:.200?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 199) ); |
| |
| resv = res = std::format("{:.10?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 9) ); |
| |
| resv = res = std::format("{:.1?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:.0?}", in); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>20?}", in); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>20.500?}", in); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>20.400?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 399) ); |
| |
| resv = res = std::format("{:*>20.200?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 199) ); |
| |
| resv = res = std::format("{:*>20.10?}", in); |
| VERIFY( strip_prefix(resv, 10, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 9) ); |
| |
| resv = res = std::format("{:*>20.1?}", in); |
| VERIFY( strip_prefix(resv, 19, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>20.0?}", in); |
| VERIFY( strip_prefix(resv, 20, '*') ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>450?}", in); |
| VERIFY( strip_prefix(resv, 32, '*') ); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>450.500?}", in); |
| VERIFY( strip_prefix(resv, 32, '*') ); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>450.420?}", in); |
| VERIFY( strip_prefix(resv, 32, '*') ); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>450.400?}", in); |
| VERIFY( strip_prefix(resv, 50, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 399) ); |
| |
| resv = res = std::format("{:*>450.200?}", in); |
| VERIFY( strip_prefix(resv, 250, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 199) ); |
| |
| resv = res = std::format("{:*>450.10?}", in); |
| VERIFY( strip_prefix(resv, 440, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 9) ); |
| |
| resv = res = std::format("{:*>450.1?}", in); |
| VERIFY( strip_prefix(resv, 449, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>450.0?}", in); |
| VERIFY( strip_prefix(resv, 450, '*') ); |
| VERIFY( resv == "" ); |
| |
| #if UNICODE_ENC |
| // width is 3, size is 15 |
| in = "o\u0302\u0323i\u0302\u0323u\u0302\u0323"; |
| in += in; // width is 6, size is 30 |
| in += in; // width is 12, size is 60 |
| in += in; // width is 24, size is 120 |
| in += in; // width is 48, size is 240 |
| in += in; // width is 96, size is 480 |
| in += in; // width is 192, size is 960 |
| inv = in; |
| |
| resv = res = std::format("{:}", in); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:.200}", in); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:.96}", in); |
| VERIFY( resv == inv.substr(0, 480) ); |
| |
| resv = res = std::format("{:.12}", in); |
| VERIFY( resv == inv.substr(0, 60) ); |
| |
| resv = res = std::format("{:.3}", in); |
| VERIFY( resv == inv.substr(0, 15) ); |
| |
| resv = res = std::format("{:.0}", in); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>10}", in); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>10.200}", in); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>10.96}", in); |
| VERIFY( resv == inv.substr(0, 480) ); |
| |
| resv = res = std::format("{:*>10.12}", in); |
| VERIFY( resv == inv.substr(0, 60) ); |
| |
| resv = res = std::format("{:*>10.3}", in); |
| VERIFY( strip_prefix(resv, 7, '*') ); |
| VERIFY( resv == inv.substr(0, 15) ); |
| |
| resv = res = std::format("{:*>10.0}", in); |
| VERIFY( strip_prefix(resv, 10, '*') ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>240s}", in); |
| VERIFY( strip_prefix(resv, 48, '*') ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>300.200s}", in); |
| VERIFY( strip_prefix(resv, 108, '*') ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>240.200s}", in); |
| VERIFY( strip_prefix(resv, 48, '*') ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>240.96s}", in); |
| VERIFY( strip_prefix(resv, 144, '*') ); |
| VERIFY( resv == inv.substr(0, 480) ); |
| |
| resv = res = std::format("{:*>240.12}", in); |
| VERIFY( strip_prefix(resv, 228, '*') ); |
| VERIFY( resv == inv.substr(0, 60) ); |
| |
| resv = res = std::format("{:*>240.3s}", in); |
| VERIFY( strip_prefix(resv, 237, '*') ); |
| VERIFY( resv == inv.substr(0, 15) ); |
| |
| resv = res = std::format("{:*>240.0s}", in); |
| VERIFY( strip_prefix(resv, 240, '*') ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:?}", in); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:.200?}", in); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:.97?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 480) ); |
| |
| resv = res = std::format("{:.13?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 60) ); |
| |
| resv = res = std::format("{:.4?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 15) ); |
| |
| resv = res = std::format("{:.1?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:.0?}", in); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>10?}", in); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>10.200?}", in); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>10.97?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 480) ); |
| |
| resv = res = std::format("{:*>10.13?}", in); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 60) ); |
| |
| resv = res = std::format("{:*>10.4?}", in); |
| VERIFY( strip_prefix(resv, 6, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 15) ); |
| |
| resv = res = std::format("{:*>10.1?}", in); |
| VERIFY( strip_prefix(resv, 9, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>10.0?}", in); |
| VERIFY( strip_prefix(resv, 10, '*') ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>240?}", in); |
| VERIFY( strip_prefix(resv, 46, '*') ); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>300.200?}", in); |
| VERIFY( strip_prefix(resv, 106, '*') ); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>240.200?}", in); |
| VERIFY( strip_prefix(resv, 46, '*') ); |
| VERIFY( strip_quotes(resv) ); |
| VERIFY( resv == inv ); |
| |
| resv = res = std::format("{:*>240.97?}", in); |
| VERIFY( strip_prefix(resv, 143, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 480) ); |
| |
| resv = res = std::format("{:*>240.13?}", in); |
| VERIFY( strip_prefix(resv, 227, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 60) ); |
| |
| resv = res = std::format("{:*>240.4?}", in); |
| VERIFY( strip_prefix(resv, 236, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == inv.substr(0, 15) ); |
| |
| resv = res = std::format("{:*>240.1?}", in); |
| VERIFY( strip_prefix(resv, 239, '*') ); |
| VERIFY( strip_quote(resv) ); |
| VERIFY( resv == "" ); |
| |
| resv = res = std::format("{:*>240.0?}", in); |
| VERIFY( strip_prefix(resv, 240, '*') ); |
| VERIFY( resv == "" ); |
| #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>(); |
| |
| 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(); |
| |
| test_fill<char>(); |
| test_fill<wchar_t>(); |
| test_prec<char>(); |
| test_prec<wchar_t>(); |
| |
| test_padding(); |
| |
| test_formatters_c(); |
| } |