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