xchar-test.cc 20 KB

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