xchar-test.cc 17 KB

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