1 // Formatting library for C++ - formatting library tests
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
12 #include "fmt/chrono.h"
13 #include "fmt/color.h"
14 #include "fmt/ostream.h"
15 #include "fmt/ranges.h"
16 #include "gtest/gtest.h"
18 using fmt::detail::max_value
;
21 template <typename Char
> class test_string
{
23 std::basic_string
<Char
> s_
;
26 test_string(const Char
* s
) : s_(s
) {}
27 const Char
* data() const { return s_
.data(); }
28 size_t length() const { return s_
.size(); }
29 operator const Char
*() const { return s_
.c_str(); }
32 template <typename Char
>
33 fmt::basic_string_view
<Char
> to_string_view(const test_string
<Char
>& s
) {
34 return {s
.data(), s
.length()};
38 } // namespace test_ns
40 template <typename T
> class is_string_test
: public testing::Test
{};
42 using string_char_types
= testing::Types
<char, wchar_t, char16_t
, char32_t
>;
43 TYPED_TEST_SUITE(is_string_test
, string_char_types
);
45 template <typename Char
>
46 struct derived_from_string_view
: fmt::basic_string_view
<Char
> {};
48 TYPED_TEST(is_string_test
, is_string
) {
49 EXPECT_TRUE(fmt::detail::is_string
<TypeParam
*>::value
);
50 EXPECT_TRUE(fmt::detail::is_string
<const TypeParam
*>::value
);
51 EXPECT_TRUE(fmt::detail::is_string
<TypeParam
[2]>::value
);
52 EXPECT_TRUE(fmt::detail::is_string
<const TypeParam
[2]>::value
);
53 EXPECT_TRUE(fmt::detail::is_string
<std::basic_string
<TypeParam
>>::value
);
54 EXPECT_TRUE(fmt::detail::is_string
<fmt::basic_string_view
<TypeParam
>>::value
);
56 fmt::detail::is_string
<derived_from_string_view
<TypeParam
>>::value
);
57 using fmt_string_view
= fmt::detail::std_string_view
<TypeParam
>;
58 EXPECT_TRUE(std::is_empty
<fmt_string_view
>::value
!=
59 fmt::detail::is_string
<fmt_string_view
>::value
);
60 EXPECT_TRUE(fmt::detail::is_string
<test_ns::test_string
<TypeParam
>>::value
);
61 EXPECT_FALSE(fmt::detail::is_string
<test_ns::non_string
>::value
);
64 // std::is_constructible is broken in MSVC until version 2015.
65 #if !FMT_MSC_VER || FMT_MSC_VER >= 1900
66 struct explicitly_convertible_to_wstring_view
{
67 explicit operator fmt::wstring_view() const { return L
"foo"; }
70 TEST(xchar_test
, format_explicitly_convertible_to_wstring_view
) {
72 fmt::format(L
"{}", explicitly_convertible_to_wstring_view()));
76 TEST(xchar_test
, format
) {
77 EXPECT_EQ(L
"42", fmt::format(L
"{}", 42));
78 EXPECT_EQ(L
"4.2", fmt::format(L
"{}", 4.2));
79 EXPECT_EQ(L
"abc", fmt::format(L
"{}", L
"abc"));
80 EXPECT_EQ(L
"z", fmt::format(L
"{}", L
'z'));
81 EXPECT_THROW(fmt::format(L
"{:*\x343E}", 42), fmt::format_error
);
82 EXPECT_EQ(L
"true", fmt::format(L
"{}", true));
83 EXPECT_EQ(L
"a", fmt::format(L
"{0}", 'a'));
84 EXPECT_EQ(L
"a", fmt::format(L
"{0}", L
'a'));
85 EXPECT_EQ(L
"Cyrillic letter \x42e",
86 fmt::format(L
"Cyrillic letter {}", L
'\x42e'));
87 EXPECT_EQ(L
"abc1", fmt::format(L
"{}c{}", L
"ab", 1));
90 TEST(xchar_test
, compile_time_string
) {
91 #if defined(FMT_USE_STRING_VIEW) && __cplusplus >= 201703L
92 EXPECT_EQ(L
"42", fmt::format(FMT_STRING(std::wstring_view(L
"{}")), 42));
96 #if __cplusplus > 201103L
99 custom_char() = default;
101 template <typename T
>
102 constexpr custom_char(T val
) : value(static_cast<int>(val
)) {}
104 operator int() const { return value
; }
107 int to_ascii(custom_char c
) { return c
; }
110 template <> struct is_char
<custom_char
> : std::true_type
{};
113 TEST(xchar_test
, format_custom_char
) {
114 const custom_char format
[] = {'{', '}', 0};
115 auto result
= fmt::format(format
, custom_char('x'));
116 EXPECT_EQ(result
.size(), 1);
117 EXPECT_EQ(result
[0], custom_char('x'));
121 // Convert a char8_t string to std::string. Otherwise GTest will insist on
122 // inserting `char8_t` NTBS into a `char` stream which is disabled by P1423.
123 template <typename S
> std::string
from_u8str(const S
& str
) {
124 return std::string(str
.begin(), str
.end());
127 TEST(xchar_test
, format_utf8_precision
) {
128 using str_type
= std::basic_string
<fmt::detail::char8_type
>;
130 str_type(reinterpret_cast<const fmt::detail::char8_type
*>(u8
"{:.4}"));
131 auto str
= str_type(reinterpret_cast<const fmt::detail::char8_type
*>(
132 u8
"caf\u00e9s")); // cafés
133 auto result
= fmt::format(format
, str
);
134 EXPECT_EQ(fmt::detail::compute_width(result
), 4);
135 EXPECT_EQ(result
.size(), 5);
136 EXPECT_EQ(from_u8str(result
), from_u8str(str
.substr(0, 5)));
139 TEST(xchar_test
, format_to
) {
140 auto buf
= std::vector
<wchar_t>();
141 fmt::format_to(std::back_inserter(buf
), L
"{}{}", 42, L
'\0');
142 EXPECT_STREQ(buf
.data(), L
"42");
145 TEST(xchar_test
, vformat_to
) {
146 using wcontext
= fmt::wformat_context
;
147 fmt::basic_format_arg
<wcontext
> warg
= fmt::detail::make_arg
<wcontext
>(42);
148 auto wargs
= fmt::basic_format_args
<wcontext
>(&warg
, 1);
149 auto w
= std::wstring();
150 fmt::vformat_to(std::back_inserter(w
), L
"{}", wargs
);
153 fmt::vformat_to(std::back_inserter(w
), FMT_STRING(L
"{}"), wargs
);
157 TEST(format_test
, wide_format_to_n
) {
160 auto result
= fmt::format_to_n(buffer
, 3, L
"{}", 12345);
161 EXPECT_EQ(5u, result
.size
);
162 EXPECT_EQ(buffer
+ 3, result
.out
);
163 EXPECT_EQ(L
"123x", fmt::wstring_view(buffer
, 4));
167 result
= fmt::format_to_n(buffer
, 3, L
"{}", L
'A');
168 EXPECT_EQ(1u, result
.size
);
169 EXPECT_EQ(buffer
+ 1, result
.out
);
170 EXPECT_EQ(L
"Axxx", fmt::wstring_view(buffer
, 4));
171 result
= fmt::format_to_n(buffer
, 3, L
"{}{} ", L
'B', L
'C');
172 EXPECT_EQ(3u, result
.size
);
173 EXPECT_EQ(buffer
+ 3, result
.out
);
174 EXPECT_EQ(L
"BC x", fmt::wstring_view(buffer
, 4));
177 #if FMT_USE_USER_DEFINED_LITERALS
178 TEST(xchar_test
, format_udl
) {
179 using namespace fmt::literals
;
180 EXPECT_EQ(L
"{}c{}"_format(L
"ab", 1), fmt::format(L
"{}c{}", L
"ab", 1));
183 TEST(xchar_test
, named_arg_udl
) {
184 using namespace fmt::literals
;
186 fmt::format(L
"{first}{second}{first}{third}", L
"first"_a
= L
"abra",
187 L
"second"_a
= L
"cad", L
"third"_a
= 99);
189 fmt::format(L
"{first}{second}{first}{third}", fmt::arg(L
"first", L
"abra"),
190 fmt::arg(L
"second", L
"cad"), fmt::arg(L
"third", 99)),
193 #endif // FMT_USE_USER_DEFINED_LITERALS
195 TEST(xchar_test
, print
) {
196 // Check that the wide print overload compiles.
197 if (fmt::detail::const_check(false)) fmt::print(L
"test");
200 TEST(xchar_test
, join
) {
201 int v
[3] = {1, 2, 3};
202 EXPECT_EQ(fmt::format(L
"({})", fmt::join(v
, v
+ 3, L
", ")), L
"(1, 2, 3)");
203 auto t
= std::tuple
<wchar_t, int, float>('a', 1, 2.0f
);
204 EXPECT_EQ(fmt::format(L
"({})", fmt::join(t
, L
", ")), L
"(a, 1, 2)");
207 enum streamable_enum
{};
209 std::wostream
& operator<<(std::wostream
& os
, streamable_enum
) {
210 return os
<< L
"streamable_enum";
213 enum unstreamable_enum
{};
215 TEST(xchar_test
, enum) {
216 EXPECT_EQ(L
"streamable_enum", fmt::format(L
"{}", streamable_enum()));
217 EXPECT_EQ(L
"0", fmt::format(L
"{}", unstreamable_enum()));
220 TEST(xchar_test
, sign_not_truncated
) {
221 wchar_t format_str
[] = {
223 '+' | static_cast<wchar_t>(1 << fmt::detail::num_bits
<char>()), L
'}', 0};
224 EXPECT_THROW(fmt::format(format_str
, 42), fmt::format_error
);
230 QString(const wchar_t* s
) : s_(s
) {}
231 const wchar_t* utf16() const FMT_NOEXCEPT
{ return s_
.data(); }
232 int size() const FMT_NOEXCEPT
{ return static_cast<int>(s_
.size()); }
238 fmt::basic_string_view
<wchar_t> to_string_view(const QString
& s
) FMT_NOEXCEPT
{
239 return {s
.utf16(), static_cast<size_t>(s
.size())};
241 } // namespace fake_qt
243 TEST(format_test
, format_foreign_strings
) {
244 using fake_qt::QString
;
245 EXPECT_EQ(fmt::format(QString(L
"{}"), 42), L
"42");
246 EXPECT_EQ(fmt::format(QString(L
"{}"), QString(L
"42")), L
"42");
249 TEST(xchar_test
, chrono
) {
257 EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm
),
258 "The date is 2016-04-25 11:22:33.");
259 EXPECT_EQ(L
"42s", fmt::format(L
"{}", std::chrono::seconds(42)));
262 TEST(xchar_test
, color
) {
263 EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), L
"rgb(255,20,30) wide"),
264 L
"\x1b[38;2;255;020;030mrgb(255,20,30) wide\x1b[0m");
267 TEST(xchar_test
, ostream
) {
268 std::wostringstream wos
;
269 fmt::print(wos
, L
"Don't {}!", L
"panic");
270 EXPECT_EQ(L
"Don't panic!", wos
.str());
273 TEST(xchar_test
, to_wstring
) { EXPECT_EQ(L
"42", fmt::to_wstring(42)); }
275 #ifndef FMT_STATIC_THOUSANDS_SEPARATOR
276 template <typename Char
> struct numpunct
: std::numpunct
<Char
> {
278 Char
do_decimal_point() const override
{ return '?'; }
279 std::string
do_grouping() const override
{ return "\03"; }
280 Char
do_thousands_sep() const override
{ return '~'; }
283 template <typename Char
> struct no_grouping
: std::numpunct
<Char
> {
285 Char
do_decimal_point() const override
{ return '.'; }
286 std::string
do_grouping() const override
{ return ""; }
287 Char
do_thousands_sep() const override
{ return ','; }
290 template <typename Char
> struct special_grouping
: std::numpunct
<Char
> {
292 Char
do_decimal_point() const override
{ return '.'; }
293 std::string
do_grouping() const override
{ return "\03\02"; }
294 Char
do_thousands_sep() const override
{ return ','; }
297 template <typename Char
> struct small_grouping
: std::numpunct
<Char
> {
299 Char
do_decimal_point() const override
{ return '.'; }
300 std::string
do_grouping() const override
{ return "\01"; }
301 Char
do_thousands_sep() const override
{ return ','; }
304 TEST(locale_test
, double_decimal_point
) {
305 auto loc
= std::locale(std::locale(), new numpunct
<char>());
306 EXPECT_EQ("1?23", fmt::format(loc
, "{:L}", 1.23));
307 EXPECT_EQ("1?230000", fmt::format(loc
, "{:Lf}", 1.23));
310 TEST(locale_test
, format
) {
311 auto loc
= std::locale(std::locale(), new numpunct
<char>());
312 EXPECT_EQ("1234567", fmt::format(std::locale(), "{:L}", 1234567));
313 EXPECT_EQ("1~234~567", fmt::format(loc
, "{:L}", 1234567));
314 EXPECT_EQ("-1~234~567", fmt::format(loc
, "{:L}", -1234567));
315 EXPECT_EQ("-256", fmt::format(loc
, "{:L}", -256));
316 fmt::format_arg_store
<fmt::format_context
, int> as
{1234567};
317 EXPECT_EQ("1~234~567", fmt::vformat(loc
, "{:L}", fmt::format_args(as
)));
318 auto s
= std::string();
319 fmt::format_to(std::back_inserter(s
), loc
, "{:L}", 1234567);
320 EXPECT_EQ("1~234~567", s
);
322 auto no_grouping_loc
= std::locale(std::locale(), new no_grouping
<char>());
323 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));
330 auto small_grouping_loc
=
331 std::locale(std::locale(), new small_grouping
<char>());
332 EXPECT_EQ("4,2,9,4,9,6,7,2,9,5",
333 fmt::format(small_grouping_loc
, "{:L}", max_value
<uint32_t>()));
336 TEST(locale_test
, format_detault_align
) {
337 auto loc
= std::locale({}, new special_grouping
<char>());
338 EXPECT_EQ(" 12,345", fmt::format(loc
, "{:8L}", 12345));
341 TEST(locale_test
, format_plus
) {
342 auto loc
= std::locale({}, new special_grouping
<char>());
343 EXPECT_EQ("+100", fmt::format(loc
, "{:+L}", 100));
346 TEST(locale_test
, wformat
) {
347 auto loc
= std::locale(std::locale(), new numpunct
<wchar_t>());
348 EXPECT_EQ(L
"1234567", fmt::format(std::locale(), L
"{:L}", 1234567));
349 EXPECT_EQ(L
"1~234~567", fmt::format(loc
, L
"{:L}", 1234567));
350 using wcontext
= fmt::buffer_context
<wchar_t>;
351 fmt::format_arg_store
<wcontext
, int> as
{1234567};
352 EXPECT_EQ(L
"1~234~567",
353 fmt::vformat(loc
, L
"{:L}", fmt::basic_format_args
<wcontext
>(as
)));
354 EXPECT_EQ(L
"1234567", fmt::format(std::locale("C"), L
"{:L}", 1234567));
356 auto no_grouping_loc
= std::locale(std::locale(), new no_grouping
<wchar_t>());
357 EXPECT_EQ(L
"1234567", fmt::format(no_grouping_loc
, L
"{:L}", 1234567));
359 auto special_grouping_loc
=
360 std::locale(std::locale(), new special_grouping
<wchar_t>());
361 EXPECT_EQ(L
"1,23,45,678",
362 fmt::format(special_grouping_loc
, L
"{:L}", 12345678));
364 auto small_grouping_loc
=
365 std::locale(std::locale(), new small_grouping
<wchar_t>());
366 EXPECT_EQ(L
"4,2,9,4,9,6,7,2,9,5",
367 fmt::format(small_grouping_loc
, L
"{:L}", max_value
<uint32_t>()));
370 TEST(locale_test
, double_formatter
) {
371 auto loc
= std::locale(std::locale(), new special_grouping
<char>());
372 auto f
= fmt::formatter
<int>();
373 auto parse_ctx
= fmt::format_parse_context("L");
376 fmt::basic_format_context
<char*, char> format_ctx(
377 buf
, {}, fmt::detail::locale_ref(loc
));
378 *f
.format(12345, format_ctx
) = 0;
379 EXPECT_STREQ("12,345", buf
);
383 template <class charT
> struct formatter
<std::complex<double>, charT
> {
385 detail::dynamic_format_specs
<char> specs_
;
388 FMT_CONSTEXPR typename basic_format_parse_context
<charT
>::iterator
parse(
389 basic_format_parse_context
<charT
>& ctx
) {
391 detail::dynamic_specs_handler
<basic_format_parse_context
<charT
>>;
392 detail::specs_checker
<handler_type
> handler(handler_type(specs_
, ctx
),
393 detail::type::string_type
);
394 auto it
= parse_format_specs(ctx
.begin(), ctx
.end(), handler
);
395 detail::parse_float_type_spec(specs_
, ctx
.error_handler());
399 template <class FormatContext
>
400 typename
FormatContext::iterator
format(const std::complex<double>& c
,
401 FormatContext
& ctx
) {
402 detail::handle_dynamic_spec
<detail::precision_checker
>(
403 specs_
.precision
, specs_
.precision_ref
, ctx
);
404 auto specs
= std::string();
405 if (specs_
.precision
> 0) specs
= fmt::format(".{}", specs_
.precision
);
406 if (specs_
.type
) specs
+= specs_
.type
;
407 auto real
= fmt::format(ctx
.locale().template get
<std::locale
>(),
408 fmt::runtime("{:" + specs
+ "}"), c
.real());
409 auto imag
= fmt::format(ctx
.locale().template get
<std::locale
>(),
410 fmt::runtime("{:" + specs
+ "}"), c
.imag());
411 auto fill_align_width
= std::string();
412 if (specs_
.width
> 0) fill_align_width
= fmt::format(">{}", specs_
.width
);
413 return format_to(ctx
.out(), runtime("{:" + fill_align_width
+ "}"),
414 c
.real() != 0 ? fmt::format("({}+{}i)", real
, imag
)
415 : fmt::format("{}i", imag
));
420 TEST(locale_test
, complex) {
421 std::string s
= fmt::format("{}", std::complex<double>(1, 2));
422 EXPECT_EQ(s
, "(1+2i)");
423 EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)");
424 EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
427 #endif // FMT_STATIC_THOUSANDS_SEPARATOR