| 1 | //===----------------------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
| 10 | // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME |
| 11 | |
| 12 | // This version runs the test when the platform has Unicode support. |
| 13 | // UNSUPPORTED: libcpp-has-no-unicode |
| 14 | |
| 15 | // XFAIL: availability-fp_to_chars-missing |
| 16 | |
| 17 | // <format> |
| 18 | |
| 19 | // The paper |
| 20 | // P2572R1 std::format fill character allowances |
| 21 | // adds support for Unicode Scalar Values as fill character. |
| 22 | |
| 23 | #include <format> |
| 24 | |
| 25 | #include "assert_macros.h" |
| 26 | #include "concat_macros.h" |
| 27 | #include "format.functions.common.h" |
| 28 | #include "make_string.h" |
| 29 | #include "string_literal.h" |
| 30 | #include "test_format_string.h" |
| 31 | #include "test_macros.h" |
| 32 | |
| 33 | #define SV(S) MAKE_STRING_VIEW(CharT, S) |
| 34 | |
| 35 | auto check = []<class CharT, class... Args>( |
| 36 | std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) { |
| 37 | std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...); |
| 38 | TEST_REQUIRE(out == expected, |
| 39 | TEST_WRITE_CONCATENATED( |
| 40 | "\nFormat string " , fmt.get(), "\nExpected output " , expected, "\nActual output " , out, '\n')); |
| 41 | }; |
| 42 | |
| 43 | auto check_exception = |
| 44 | []<class CharT, class... Args>( |
| 45 | [[maybe_unused]] std::string_view what, |
| 46 | [[maybe_unused]] std::basic_string_view<CharT> fmt, |
| 47 | [[maybe_unused]] Args&&... args) { |
| 48 | TEST_VALIDATE_EXCEPTION( |
| 49 | std::format_error, |
| 50 | [&]([[maybe_unused]] const std::format_error& e) { |
| 51 | TEST_LIBCPP_REQUIRE( |
| 52 | e.what() == what, |
| 53 | TEST_WRITE_CONCATENATED( |
| 54 | "\nFormat string " , fmt, "\nExpected exception " , what, "\nActual exception " , e.what(), '\n')); |
| 55 | }, |
| 56 | TEST_IGNORE_NODISCARD std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...))); |
| 57 | }; |
| 58 | |
| 59 | template <class CharT> |
| 60 | void test() { |
| 61 | // 1, 2, 3, 4 code unit UTF-8 transitions |
| 62 | check(SV("\u000042\u0000" ), SV("{:\u0000^4}" ), 42); |
| 63 | check(SV("\u007f42\u007f" ), SV("{:\u007f^4}" ), 42); |
| 64 | check(SV("\u008042\u0080" ), SV("{:\u0080^4}" ), 42); |
| 65 | check(SV("\u07ff42\u07ff" ), SV("{:\u07ff^4}" ), 42); |
| 66 | check(SV("\u080042\u0800" ), SV("{:\u0800^4}" ), 42); |
| 67 | check(SV("\uffff42\uffff" ), SV("{:\uffff^4}" ), 42); |
| 68 | check(SV("\U0010000042\U00100000" ), SV("{:\U00100000^4}" ), 42); |
| 69 | check(SV("\U0010ffff42\U0010ffff" ), SV("{:\U0010ffff^4}" ), 42); |
| 70 | |
| 71 | // Examples of P2572R1 |
| 72 | check(SV("🤡🤡x🤡🤡🤡" ), SV("{:🤡^6}" ), SV("x" )); |
| 73 | check(SV("🤡🤡🤡" ), SV("{:*^6}" ), SV("🤡🤡🤡" )); |
| 74 | check(SV("12345678" ), SV("{:*>6}" ), SV("12345678" )); |
| 75 | |
| 76 | // Invalid Unicode Scalar Values |
| 77 | if constexpr (std::same_as<CharT, char>) { |
| 78 | check_exception("The format specifier contains malformed Unicode characters" , SV("{:\xed\xa0\x80^}" ), 42); // U+D800 |
| 79 | check_exception("The format specifier contains malformed Unicode characters" , SV("{:\xed\xa0\xbf^}" ), 42); // U+DBFF |
| 80 | check_exception("The format specifier contains malformed Unicode characters" , SV("{:\xed\xbf\x80^}" ), 42); // U+DC00 |
| 81 | check_exception("The format specifier contains malformed Unicode characters" , SV("{:\xed\xbf\xbf^}" ), 42); // U+DFFF |
| 82 | |
| 83 | check_exception( |
| 84 | "The format specifier contains malformed Unicode characters" , SV("{:\xf4\x90\x80\x80^}" ), 42); // U+110000 |
| 85 | check_exception( |
| 86 | "The format specifier contains malformed Unicode characters" , SV("{:\xf4\x90\xbf\xbf^}" ), 42); // U+11FFFF |
| 87 | |
| 88 | check_exception("The format specifier contains malformed Unicode characters" , |
| 89 | SV("{:\x80^}" ), |
| 90 | 42); // Trailing code unit with no leading one. |
| 91 | check_exception("The format specifier contains malformed Unicode characters" , |
| 92 | SV("{:\xc0^}" ), |
| 93 | 42); // Missing trailing code unit. |
| 94 | check_exception("The format specifier contains malformed Unicode characters" , |
| 95 | SV("{:\xe0\x80^}" ), |
| 96 | 42); // Missing trailing code unit. |
| 97 | check_exception("The format specifier contains malformed Unicode characters" , |
| 98 | SV("{:\xf0\x80^}" ), |
| 99 | 42); // Missing two trailing code units. |
| 100 | check_exception("The format specifier contains malformed Unicode characters" , |
| 101 | SV("{:\xf0\x80\x80^}" ), |
| 102 | 42); // Missing trailing code unit. |
| 103 | |
| 104 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
| 105 | } else { |
| 106 | # ifdef TEST_SHORT_WCHAR |
| 107 | check_exception("The format specifier contains malformed Unicode characters" , std::wstring_view{L"{:\xd800^}" }, 42); |
| 108 | check_exception("The format specifier contains malformed Unicode characters" , std::wstring_view{L"{:\xdbff^}" }, 42); |
| 109 | check_exception("The format specifier contains malformed Unicode characters" , std::wstring_view{L"{:\xdc00^}" }, 42); |
| 110 | check_exception("The format specifier contains malformed Unicode characters" , std::wstring_view{L"{:\xddff^}" }, 42); |
| 111 | |
| 112 | check_exception("The format specifier contains malformed Unicode characters" , |
| 113 | std::wstring_view{L"{:\xdc00\xd800^}" }, |
| 114 | 42); // Reverted surrogates. |
| 115 | |
| 116 | # else // TEST_SHORT_WCHAR |
| 117 | check_exception("The fill option contains an invalid value" , std::wstring_view{L"{:\xd800^}" }, 42); |
| 118 | check_exception("The fill option contains an invalid value" , std::wstring_view{L"{:\xdbff^}" }, 42); |
| 119 | check_exception("The fill option contains an invalid value" , std::wstring_view{L"{:\xdc00^}" }, 42); |
| 120 | check_exception("The fill option contains an invalid value" , std::wstring_view{L"{:\xddff^}" }, 42); |
| 121 | |
| 122 | check_exception( |
| 123 | "The format specifier should consume the input or end with a '}'" , std::wstring_view{L"{:\xdc00\xd800^}" }, 42); |
| 124 | |
| 125 | check_exception("The fill option contains an invalid value" , std::wstring_view{L"{:\x00110000^}" }, 42); |
| 126 | check_exception("The fill option contains an invalid value" , std::wstring_view{L"{:\x0011ffff^}" }, 42); |
| 127 | # endif // TEST_SHORT_WCHAR |
| 128 | #endif // TEST_HAS_NO_WIDE_CHARACTERS |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | int main(int, char**) { |
| 133 | test<char>(); |
| 134 | |
| 135 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
| 136 | test<wchar_t>(); |
| 137 | #endif |
| 138 | |
| 139 | return 0; |
| 140 | } |
| 141 | |