]> git.proxmox.com Git - ceph.git/blob - ceph/src/fmt/test/xchar-test.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / fmt / test / xchar-test.cc
1 // Formatting library for C++ - formatting library tests
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7
8 #include "fmt/xchar.h"
9
10 #include <complex>
11 #include <cwchar>
12 #include <vector>
13
14 #include "fmt/chrono.h"
15 #include "fmt/color.h"
16 #include "fmt/ostream.h"
17 #include "fmt/ranges.h"
18 #include "gtest-extra.h" // Contains
19 #include "util.h" // get_locale
20
21 using fmt::detail::max_value;
22 using testing::Contains;
23
24 namespace test_ns {
25 template <typename Char> class test_string {
26 private:
27 std::basic_string<Char> s_;
28
29 public:
30 test_string(const Char* s) : s_(s) {}
31 const Char* data() const { return s_.data(); }
32 size_t length() const { return s_.size(); }
33 operator const Char*() const { return s_.c_str(); }
34 };
35
36 template <typename Char>
37 fmt::basic_string_view<Char> to_string_view(const test_string<Char>& s) {
38 return {s.data(), s.length()};
39 }
40
41 struct non_string {};
42 } // namespace test_ns
43
44 template <typename T> class is_string_test : public testing::Test {};
45
46 using string_char_types = testing::Types<char, wchar_t, char16_t, char32_t>;
47 TYPED_TEST_SUITE(is_string_test, string_char_types);
48
49 template <typename Char>
50 struct derived_from_string_view : fmt::basic_string_view<Char> {};
51
52 TYPED_TEST(is_string_test, is_string) {
53 EXPECT_TRUE(fmt::detail::is_string<TypeParam*>::value);
54 EXPECT_TRUE(fmt::detail::is_string<const TypeParam*>::value);
55 EXPECT_TRUE(fmt::detail::is_string<TypeParam[2]>::value);
56 EXPECT_TRUE(fmt::detail::is_string<const TypeParam[2]>::value);
57 EXPECT_TRUE(fmt::detail::is_string<std::basic_string<TypeParam>>::value);
58 EXPECT_TRUE(fmt::detail::is_string<fmt::basic_string_view<TypeParam>>::value);
59 EXPECT_TRUE(
60 fmt::detail::is_string<derived_from_string_view<TypeParam>>::value);
61 using fmt_string_view = fmt::detail::std_string_view<TypeParam>;
62 EXPECT_TRUE(std::is_empty<fmt_string_view>::value !=
63 fmt::detail::is_string<fmt_string_view>::value);
64 EXPECT_TRUE(fmt::detail::is_string<test_ns::test_string<TypeParam>>::value);
65 EXPECT_FALSE(fmt::detail::is_string<test_ns::non_string>::value);
66 }
67
68 // std::is_constructible is broken in MSVC until version 2015.
69 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1900
70 struct explicitly_convertible_to_wstring_view {
71 explicit operator fmt::wstring_view() const { return L"foo"; }
72 };
73
74 TEST(xchar_test, format_explicitly_convertible_to_wstring_view) {
75 // Types explicitly convertible to wstring_view are not formattable by
76 // default because it may introduce ODR violations.
77 static_assert(
78 !fmt::is_formattable<explicitly_convertible_to_wstring_view>::value, "");
79 }
80 #endif
81
82 TEST(xchar_test, format) {
83 EXPECT_EQ(L"42", fmt::format(L"{}", 42));
84 EXPECT_EQ(L"4.2", fmt::format(L"{}", 4.2));
85 EXPECT_EQ(L"abc", fmt::format(L"{}", L"abc"));
86 EXPECT_EQ(L"z", fmt::format(L"{}", L'z'));
87 EXPECT_THROW(fmt::format(fmt::runtime(L"{:*\x343E}"), 42), fmt::format_error);
88 EXPECT_EQ(L"true", fmt::format(L"{}", true));
89 EXPECT_EQ(L"a", fmt::format(L"{0}", 'a'));
90 EXPECT_EQ(L"a", fmt::format(L"{0}", L'a'));
91 EXPECT_EQ(L"Cyrillic letter \x42e",
92 fmt::format(L"Cyrillic letter {}", L'\x42e'));
93 EXPECT_EQ(L"abc1", fmt::format(L"{}c{}", L"ab", 1));
94 }
95
96 TEST(xchar_test, is_formattable) {
97 static_assert(!fmt::is_formattable<const wchar_t*>::value, "");
98 }
99
100 TEST(xchar_test, compile_time_string) {
101 EXPECT_EQ(fmt::format(fmt::wformat_string<int>(L"{}"), 42), L"42");
102 #if defined(FMT_USE_STRING_VIEW) && FMT_CPLUSPLUS >= 201703L
103 EXPECT_EQ(fmt::format(FMT_STRING(std::wstring_view(L"{}")), 42), L"42");
104 #endif
105 }
106
107 #if FMT_CPLUSPLUS > 201103L
108 struct custom_char {
109 int value;
110 custom_char() = default;
111
112 template <typename T>
113 constexpr custom_char(T val) : value(static_cast<int>(val)) {}
114
115 operator int() const { return value; }
116 };
117
118 int to_ascii(custom_char c) { return c; }
119
120 FMT_BEGIN_NAMESPACE
121 template <> struct is_char<custom_char> : std::true_type {};
122 FMT_END_NAMESPACE
123
124 TEST(xchar_test, format_custom_char) {
125 const custom_char format[] = {'{', '}', 0};
126 auto result = fmt::format(format, custom_char('x'));
127 EXPECT_EQ(result.size(), 1);
128 EXPECT_EQ(result[0], custom_char('x'));
129 }
130 #endif
131
132 // Convert a char8_t string to std::string. Otherwise GTest will insist on
133 // inserting `char8_t` NTBS into a `char` stream which is disabled by P1423.
134 template <typename S> std::string from_u8str(const S& str) {
135 return std::string(str.begin(), str.end());
136 }
137
138 TEST(xchar_test, format_utf8_precision) {
139 using str_type = std::basic_string<fmt::detail::char8_type>;
140 auto format =
141 str_type(reinterpret_cast<const fmt::detail::char8_type*>(u8"{:.4}"));
142 auto str = str_type(reinterpret_cast<const fmt::detail::char8_type*>(
143 u8"caf\u00e9s")); // cafés
144 auto result = fmt::format(format, str);
145 EXPECT_EQ(fmt::detail::compute_width(result), 4);
146 EXPECT_EQ(result.size(), 5);
147 EXPECT_EQ(from_u8str(result), from_u8str(str.substr(0, 5)));
148 }
149
150 TEST(xchar_test, format_to) {
151 auto buf = std::vector<wchar_t>();
152 fmt::format_to(std::back_inserter(buf), L"{}{}", 42, L'\0');
153 EXPECT_STREQ(buf.data(), L"42");
154 }
155
156 TEST(xchar_test, vformat_to) {
157 using wcontext = fmt::wformat_context;
158 fmt::basic_format_arg<wcontext> warg = fmt::detail::make_arg<wcontext>(42);
159 auto wargs = fmt::basic_format_args<wcontext>(&warg, 1);
160 auto w = std::wstring();
161 fmt::vformat_to(std::back_inserter(w), L"{}", wargs);
162 EXPECT_EQ(L"42", w);
163 w.clear();
164 fmt::vformat_to(std::back_inserter(w), FMT_STRING(L"{}"), wargs);
165 EXPECT_EQ(L"42", w);
166 }
167
168 TEST(format_test, wide_format_to_n) {
169 wchar_t buffer[4];
170 buffer[3] = L'x';
171 auto result = fmt::format_to_n(buffer, 3, L"{}", 12345);
172 EXPECT_EQ(5u, result.size);
173 EXPECT_EQ(buffer + 3, result.out);
174 EXPECT_EQ(L"123x", fmt::wstring_view(buffer, 4));
175 buffer[0] = L'x';
176 buffer[1] = L'x';
177 buffer[2] = L'x';
178 result = fmt::format_to_n(buffer, 3, L"{}", L'A');
179 EXPECT_EQ(1u, result.size);
180 EXPECT_EQ(buffer + 1, result.out);
181 EXPECT_EQ(L"Axxx", fmt::wstring_view(buffer, 4));
182 result = fmt::format_to_n(buffer, 3, L"{}{} ", L'B', L'C');
183 EXPECT_EQ(3u, result.size);
184 EXPECT_EQ(buffer + 3, result.out);
185 EXPECT_EQ(L"BC x", fmt::wstring_view(buffer, 4));
186 }
187
188 #if FMT_USE_USER_DEFINED_LITERALS
189 TEST(xchar_test, named_arg_udl) {
190 using namespace fmt::literals;
191 auto udl_a =
192 fmt::format(L"{first}{second}{first}{third}", L"first"_a = L"abra",
193 L"second"_a = L"cad", L"third"_a = 99);
194 EXPECT_EQ(
195 fmt::format(L"{first}{second}{first}{third}", fmt::arg(L"first", L"abra"),
196 fmt::arg(L"second", L"cad"), fmt::arg(L"third", 99)),
197 udl_a);
198 }
199 #endif // FMT_USE_USER_DEFINED_LITERALS
200
201 TEST(xchar_test, print) {
202 // Check that the wide print overload compiles.
203 if (fmt::detail::const_check(false)) fmt::print(L"test");
204 }
205
206 TEST(xchar_test, join) {
207 int v[3] = {1, 2, 3};
208 EXPECT_EQ(fmt::format(L"({})", fmt::join(v, v + 3, L", ")), L"(1, 2, 3)");
209 auto t = std::tuple<wchar_t, int, float>('a', 1, 2.0f);
210 EXPECT_EQ(fmt::format(L"({})", fmt::join(t, L", ")), L"(a, 1, 2)");
211 }
212
213 enum streamable_enum {};
214
215 std::wostream& operator<<(std::wostream& os, streamable_enum) {
216 return os << L"streamable_enum";
217 }
218
219 namespace fmt {
220 template <>
221 struct formatter<streamable_enum, wchar_t> : basic_ostream_formatter<wchar_t> {
222 };
223 } // namespace fmt
224
225 enum unstreamable_enum {};
226 auto format_as(unstreamable_enum e) -> int { return e; }
227
228 TEST(xchar_test, enum) {
229 EXPECT_EQ(L"streamable_enum", fmt::format(L"{}", streamable_enum()));
230 EXPECT_EQ(L"0", fmt::format(L"{}", unstreamable_enum()));
231 }
232
233 struct streamable_and_unformattable {};
234
235 auto operator<<(std::wostream& os, streamable_and_unformattable)
236 -> std::wostream& {
237 return os << L"foo";
238 }
239
240 TEST(xchar_test, streamed) {
241 EXPECT_FALSE(fmt::is_formattable<streamable_and_unformattable>());
242 EXPECT_EQ(fmt::format(L"{}", fmt::streamed(streamable_and_unformattable())),
243 L"foo");
244 }
245
246 TEST(xchar_test, sign_not_truncated) {
247 wchar_t format_str[] = {
248 L'{', L':',
249 '+' | static_cast<wchar_t>(1 << fmt::detail::num_bits<char>()), L'}', 0};
250 EXPECT_THROW(fmt::format(fmt::runtime(format_str), 42), fmt::format_error);
251 }
252
253 TEST(xchar_test, chrono) {
254 auto tm = std::tm();
255 tm.tm_year = 116;
256 tm.tm_mon = 3;
257 tm.tm_mday = 25;
258 tm.tm_hour = 11;
259 tm.tm_min = 22;
260 tm.tm_sec = 33;
261 EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
262 "The date is 2016-04-25 11:22:33.");
263 EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42)));
264 EXPECT_EQ(fmt::format(L"{:%F}", tm), L"2016-04-25");
265 EXPECT_EQ(fmt::format(L"{:%T}", tm), L"11:22:33");
266 }
267
268 std::wstring system_wcsftime(const std::wstring& format, const std::tm* timeptr,
269 std::locale* locptr = nullptr) {
270 auto loc = locptr ? *locptr : std::locale::classic();
271 auto& facet = std::use_facet<std::time_put<wchar_t>>(loc);
272 std::wostringstream os;
273 os.imbue(loc);
274 facet.put(os, os, L' ', timeptr, format.c_str(),
275 format.c_str() + format.size());
276 #ifdef _WIN32
277 // Workaround a bug in older versions of Universal CRT.
278 auto str = os.str();
279 if (str == L"-0000") str = L"+0000";
280 return str;
281 #else
282 return os.str();
283 #endif
284 }
285
286 TEST(chrono_test_wchar, time_point) {
287 auto t1 = std::chrono::system_clock::now();
288
289 std::vector<std::wstring> spec_list = {
290 L"%%", L"%n", L"%t", L"%Y", L"%EY", L"%y", L"%Oy", L"%Ey", L"%C",
291 L"%EC", L"%G", L"%g", L"%b", L"%h", L"%B", L"%m", L"%Om", L"%U",
292 L"%OU", L"%W", L"%OW", L"%V", L"%OV", L"%j", L"%d", L"%Od", L"%e",
293 L"%Oe", L"%a", L"%A", L"%w", L"%Ow", L"%u", L"%Ou", L"%H", L"%OH",
294 L"%I", L"%OI", L"%M", L"%OM", L"%S", L"%OS", L"%x", L"%Ex", L"%X",
295 L"%EX", L"%D", L"%F", L"%R", L"%T", L"%p", L"%z", L"%Z"};
296 #ifndef _WIN32
297 // Disabled on Windows, because these formats is not consistent among
298 // platforms.
299 spec_list.insert(spec_list.end(), {L"%c", L"%Ec", L"%r"});
300 #elif defined(__MINGW32__) && !defined(_UCRT)
301 // Only C89 conversion specifiers when using MSVCRT instead of UCRT
302 spec_list = {L"%%", L"%Y", L"%y", L"%b", L"%B", L"%m", L"%U",
303 L"%W", L"%j", L"%d", L"%a", L"%A", L"%w", L"%H",
304 L"%I", L"%M", L"%S", L"%x", L"%X", L"%p", L"%Z"};
305 #endif
306 spec_list.push_back(L"%Y-%m-%d %H:%M:%S");
307
308 for (const auto& spec : spec_list) {
309 auto t = std::chrono::system_clock::to_time_t(t1);
310 auto tm = *std::localtime(&t);
311
312 auto sys_output = system_wcsftime(spec, &tm);
313
314 auto fmt_spec = fmt::format(L"{{:{}}}", spec);
315 EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), t1));
316 EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), tm));
317 }
318 }
319
320 TEST(xchar_test, color) {
321 EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), L"rgb(255,20,30) wide"),
322 L"\x1b[38;2;255;020;030mrgb(255,20,30) wide\x1b[0m");
323 }
324
325 TEST(xchar_test, ostream) {
326 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 409
327 std::wostringstream wos;
328 fmt::print(wos, L"Don't {}!", L"panic");
329 EXPECT_EQ(wos.str(), L"Don't panic!");
330 #endif
331 }
332
333 TEST(xchar_test, format_map) {
334 auto m = std::map<std::wstring, int>{{L"one", 1}, {L"t\"wo", 2}};
335 EXPECT_EQ(fmt::format(L"{}", m), L"{\"one\": 1, \"t\\\"wo\": 2}");
336 }
337
338 TEST(xchar_test, escape_string) {
339 using vec = std::vector<std::wstring>;
340 EXPECT_EQ(fmt::format(L"{}", vec{L"\n\r\t\"\\"}), L"[\"\\n\\r\\t\\\"\\\\\"]");
341 EXPECT_EQ(fmt::format(L"{}", vec{L"понедельник"}), L"[\"понедельник\"]");
342 }
343
344 TEST(xchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }
345
346 #ifndef FMT_STATIC_THOUSANDS_SEPARATOR
347 template <typename Char> struct numpunct : std::numpunct<Char> {
348 protected:
349 Char do_decimal_point() const override { return '?'; }
350 std::string do_grouping() const override { return "\03"; }
351 Char do_thousands_sep() const override { return '~'; }
352 };
353
354 template <typename Char> struct no_grouping : std::numpunct<Char> {
355 protected:
356 Char do_decimal_point() const override { return '.'; }
357 std::string do_grouping() const override { return ""; }
358 Char do_thousands_sep() const override { return ','; }
359 };
360
361 template <typename Char> struct special_grouping : std::numpunct<Char> {
362 protected:
363 Char do_decimal_point() const override { return '.'; }
364 std::string do_grouping() const override { return "\03\02"; }
365 Char do_thousands_sep() const override { return ','; }
366 };
367
368 template <typename Char> struct small_grouping : std::numpunct<Char> {
369 protected:
370 Char do_decimal_point() const override { return '.'; }
371 std::string do_grouping() const override { return "\01"; }
372 Char do_thousands_sep() const override { return ','; }
373 };
374
375 TEST(locale_test, localized_double) {
376 auto loc = std::locale(std::locale(), new numpunct<char>());
377 EXPECT_EQ(fmt::format(loc, "{:L}", 1.23), "1?23");
378 EXPECT_EQ(fmt::format(loc, "{:Lf}", 1.23), "1?230000");
379 EXPECT_EQ(fmt::format(loc, "{:L}", 1234.5), "1~234?5");
380 EXPECT_EQ(fmt::format(loc, "{:L}", 12000.0), "12~000");
381 EXPECT_EQ(fmt::format(loc, "{:8L}", 1230.0), " 1~230");
382 }
383
384 TEST(locale_test, format) {
385 auto loc = std::locale(std::locale(), new numpunct<char>());
386 EXPECT_EQ("1234567", fmt::format(std::locale(), "{:L}", 1234567));
387 EXPECT_EQ("1~234~567", fmt::format(loc, "{:L}", 1234567));
388 EXPECT_EQ("-1~234~567", fmt::format(loc, "{:L}", -1234567));
389 EXPECT_EQ("-256", fmt::format(loc, "{:L}", -256));
390 fmt::format_arg_store<fmt::format_context, int> as{1234567};
391 EXPECT_EQ("1~234~567", fmt::vformat(loc, "{:L}", fmt::format_args(as)));
392 auto s = std::string();
393 fmt::format_to(std::back_inserter(s), loc, "{:L}", 1234567);
394 EXPECT_EQ("1~234~567", s);
395
396 auto no_grouping_loc = std::locale(std::locale(), new no_grouping<char>());
397 EXPECT_EQ("1234567", fmt::format(no_grouping_loc, "{:L}", 1234567));
398
399 auto special_grouping_loc =
400 std::locale(std::locale(), new special_grouping<char>());
401 EXPECT_EQ("1,23,45,678", fmt::format(special_grouping_loc, "{:L}", 12345678));
402 EXPECT_EQ("12,345", fmt::format(special_grouping_loc, "{:L}", 12345));
403
404 auto small_grouping_loc =
405 std::locale(std::locale(), new small_grouping<char>());
406 EXPECT_EQ("4,2,9,4,9,6,7,2,9,5",
407 fmt::format(small_grouping_loc, "{:L}", max_value<uint32_t>()));
408 }
409
410 TEST(locale_test, format_detault_align) {
411 auto loc = std::locale({}, new special_grouping<char>());
412 EXPECT_EQ(" 12,345", fmt::format(loc, "{:8L}", 12345));
413 }
414
415 TEST(locale_test, format_plus) {
416 auto loc = std::locale({}, new special_grouping<char>());
417 EXPECT_EQ("+100", fmt::format(loc, "{:+L}", 100));
418 }
419
420 TEST(locale_test, wformat) {
421 auto loc = std::locale(std::locale(), new numpunct<wchar_t>());
422 EXPECT_EQ(L"1234567", fmt::format(std::locale(), L"{:L}", 1234567));
423 EXPECT_EQ(L"1~234~567", fmt::format(loc, L"{:L}", 1234567));
424 using wcontext = fmt::buffer_context<wchar_t>;
425 fmt::format_arg_store<wcontext, int> as{1234567};
426 EXPECT_EQ(L"1~234~567",
427 fmt::vformat(loc, L"{:L}", fmt::basic_format_args<wcontext>(as)));
428 EXPECT_EQ(L"1234567", fmt::format(std::locale("C"), L"{:L}", 1234567));
429
430 auto no_grouping_loc = std::locale(std::locale(), new no_grouping<wchar_t>());
431 EXPECT_EQ(L"1234567", fmt::format(no_grouping_loc, L"{:L}", 1234567));
432
433 auto special_grouping_loc =
434 std::locale(std::locale(), new special_grouping<wchar_t>());
435 EXPECT_EQ(L"1,23,45,678",
436 fmt::format(special_grouping_loc, L"{:L}", 12345678));
437
438 auto small_grouping_loc =
439 std::locale(std::locale(), new small_grouping<wchar_t>());
440 EXPECT_EQ(L"4,2,9,4,9,6,7,2,9,5",
441 fmt::format(small_grouping_loc, L"{:L}", max_value<uint32_t>()));
442 }
443
444 TEST(locale_test, double_formatter) {
445 auto loc = std::locale(std::locale(), new special_grouping<char>());
446 auto f = fmt::formatter<int>();
447 auto parse_ctx = fmt::format_parse_context("L");
448 f.parse(parse_ctx);
449 char buf[10] = {};
450 fmt::basic_format_context<char*, char> format_ctx(
451 buf, {}, fmt::detail::locale_ref(loc));
452 *f.format(12345, format_ctx) = 0;
453 EXPECT_STREQ("12,345", buf);
454 }
455
456 FMT_BEGIN_NAMESPACE
457 template <class charT> struct formatter<std::complex<double>, charT> {
458 private:
459 detail::dynamic_format_specs<char> specs_;
460
461 public:
462 FMT_CONSTEXPR typename basic_format_parse_context<charT>::iterator parse(
463 basic_format_parse_context<charT>& ctx) {
464 using handler_type =
465 detail::dynamic_specs_handler<basic_format_parse_context<charT>>;
466 detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
467 detail::type::string_type);
468 auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
469 detail::parse_float_type_spec(specs_, ctx.error_handler());
470 return it;
471 }
472
473 template <class FormatContext>
474 typename FormatContext::iterator format(const std::complex<double>& c,
475 FormatContext& ctx) {
476 detail::handle_dynamic_spec<detail::precision_checker>(
477 specs_.precision, specs_.precision_ref, ctx);
478 auto specs = std::string();
479 if (specs_.precision > 0) specs = fmt::format(".{}", specs_.precision);
480 if (specs_.type == presentation_type::fixed_lower) specs += 'f';
481 auto real = fmt::format(ctx.locale().template get<std::locale>(),
482 fmt::runtime("{:" + specs + "}"), c.real());
483 auto imag = fmt::format(ctx.locale().template get<std::locale>(),
484 fmt::runtime("{:" + specs + "}"), c.imag());
485 auto fill_align_width = std::string();
486 if (specs_.width > 0) fill_align_width = fmt::format(">{}", specs_.width);
487 return format_to(ctx.out(), runtime("{:" + fill_align_width + "}"),
488 c.real() != 0 ? fmt::format("({}+{}i)", real, imag)
489 : fmt::format("{}i", imag));
490 }
491 };
492 FMT_END_NAMESPACE
493
494 TEST(locale_test, complex) {
495 std::string s = fmt::format("{}", std::complex<double>(1, 2));
496 EXPECT_EQ(s, "(1+2i)");
497 EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)");
498 EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
499 }
500
501 TEST(locale_test, chrono_weekday) {
502 auto loc = get_locale("ru_RU.UTF-8", "Russian_Russia.1251");
503 auto loc_old = std::locale::global(loc);
504 auto mon = fmt::weekday(1);
505 EXPECT_EQ(fmt::format(L"{}", mon), L"Mon");
506 if (loc != std::locale::classic()) {
507 // {L"\x43F\x43D", L"\x41F\x43D", L"\x43F\x43D\x434", L"\x41F\x43D\x434"}
508 // {L"пн", L"Пн", L"пнд", L"Пнд"}
509 EXPECT_THAT(
510 (std::vector<std::wstring>{L"\x43F\x43D", L"\x41F\x43D",
511 L"\x43F\x43D\x434", L"\x41F\x43D\x434"}),
512 Contains(fmt::format(loc, L"{:L}", mon)));
513 }
514 std::locale::global(loc_old);
515 }
516
517 TEST(locale_test, sign) {
518 EXPECT_EQ(fmt::format(std::locale(), L"{:L}", -50), L"-50");
519 }
520
521 #endif // FMT_STATIC_THOUSANDS_SEPARATOR