]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | #include <format> |
2 | ||
20effc67 | 3 | #include "gtest/gtest.h" |
f67539c2 | 4 | |
20effc67 | 5 | TEST(std_format_test, escaping) { |
f67539c2 TL |
6 | using namespace std; |
7 | string s = format("{0}-{{", 8); // s == "8-{" | |
8 | EXPECT_EQ(s, "8-{"); | |
9 | } | |
10 | ||
20effc67 | 11 | TEST(std_format_test, indexing) { |
f67539c2 TL |
12 | using namespace std; |
13 | string s0 = format("{} to {}", "a", "b"); // OK: automatic indexing | |
14 | string s1 = format("{1} to {0}", "a", "b"); // OK: manual indexing | |
15 | EXPECT_EQ(s0, "a to b"); | |
16 | EXPECT_EQ(s1, "b to a"); | |
17 | // Error: mixing automatic and manual indexing | |
18 | EXPECT_THROW(string s2 = format("{0} to {}", "a", "b"), std::format_error); | |
19 | // Error: mixing automatic and manual indexing | |
20 | EXPECT_THROW(string s3 = format("{} to {1}", "a", "b"), std::format_error); | |
21 | } | |
22 | ||
20effc67 | 23 | TEST(std_format_test, alignment) { |
f67539c2 TL |
24 | using namespace std; |
25 | char c = 120; | |
26 | string s0 = format("{:6}", 42); // s0 == " 42" | |
27 | string s1 = format("{:6}", 'x'); // s1 == "x " | |
28 | string s2 = format("{:*<6}", 'x'); // s2 == "x*****" | |
29 | string s3 = format("{:*>6}", 'x'); // s3 == "*****x" | |
30 | string s4 = format("{:*^6}", 'x'); // s4 == "**x***" | |
31 | // Error: '=' with charT and no integer presentation type | |
32 | EXPECT_THROW(string s5 = format("{:=6}", 'x'), std::format_error); | |
33 | string s6 = format("{:6d}", c); // s6 == " 120" | |
34 | string s7 = format("{:6}", true); // s9 == "true " | |
35 | EXPECT_EQ(s0, " 42"); | |
36 | EXPECT_EQ(s1, "x "); | |
37 | EXPECT_EQ(s2, "x*****"); | |
38 | EXPECT_EQ(s3, "*****x"); | |
39 | EXPECT_EQ(s4, "**x***"); | |
40 | EXPECT_EQ(s6, " 120"); | |
41 | EXPECT_EQ(s7, "true "); | |
42 | } | |
43 | ||
20effc67 | 44 | TEST(std_format_test, float) { |
f67539c2 TL |
45 | using namespace std; |
46 | double inf = numeric_limits<double>::infinity(); | |
47 | double nan = numeric_limits<double>::quiet_NaN(); | |
48 | string s0 = format("{0:} {0:+} {0:-} {0: }", 1); // s0 == "1 +1 1 1" | |
49 | string s1 = format("{0:} {0:+} {0:-} {0: }", -1); // s1 == "-1 -1 -1 -1" | |
50 | string s2 = | |
51 | format("{0:} {0:+} {0:-} {0: }", inf); // s2 == "inf +inf inf inf" | |
52 | string s3 = | |
53 | format("{0:} {0:+} {0:-} {0: }", nan); // s3 == "nan +nan nan nan" | |
54 | EXPECT_EQ(s0, "1 +1 1 1"); | |
55 | EXPECT_EQ(s1, "-1 -1 -1 -1"); | |
56 | EXPECT_EQ(s2, "inf +inf inf inf"); | |
57 | EXPECT_EQ(s3, "nan +nan nan nan"); | |
58 | } | |
59 | ||
20effc67 | 60 | TEST(std_format_test, int) { |
f67539c2 TL |
61 | using namespace std; |
62 | string s0 = format("{}", 42); // s0 == "42" | |
63 | string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // s1 == "101010 42 52 2a" | |
64 | string s2 = format("{0:#x} {0:#X}", 42); // s2 == "0x2a 0X2A" | |
20effc67 | 65 | string s3 = format("{:L}", 1234); // s3 == "1234" (depends on the locale) |
f67539c2 TL |
66 | EXPECT_EQ(s0, "42"); |
67 | EXPECT_EQ(s1, "101010 42 52 2a"); | |
68 | EXPECT_EQ(s2, "0x2a 0X2A"); | |
69 | EXPECT_EQ(s3, "1234"); | |
70 | } | |
71 | ||
72 | #include <format> | |
73 | ||
74 | enum color { red, green, blue }; | |
75 | ||
76 | const char* color_names[] = {"red", "green", "blue"}; | |
77 | ||
78 | template <> struct std::formatter<color> : std::formatter<const char*> { | |
79 | auto format(color c, format_context& ctx) { | |
80 | return formatter<const char*>::format(color_names[c], ctx); | |
81 | } | |
82 | }; | |
83 | ||
84 | struct err {}; | |
85 | ||
20effc67 | 86 | TEST(std_format_test, formatter) { |
f67539c2 TL |
87 | std::string s0 = std::format("{}", 42); // OK: library-provided formatter |
88 | // std::string s1 = std::format("{}", L"foo"); // Ill-formed: disabled | |
89 | // formatter | |
90 | std::string s2 = std::format("{}", red); // OK: user-provided formatter | |
91 | // std::string s3 = std::format("{}", err{}); // Ill-formed: disabled | |
92 | // formatter | |
93 | EXPECT_EQ(s0, "42"); | |
94 | EXPECT_EQ(s2, "red"); | |
95 | } | |
96 | ||
97 | struct S { | |
98 | int value; | |
99 | }; | |
100 | ||
101 | template <> struct std::formatter<S> { | |
102 | size_t width_arg_id = 0; | |
103 | ||
104 | // Parses a width argument id in the format { <digit> }. | |
105 | constexpr auto parse(format_parse_context& ctx) { | |
20effc67 TL |
106 | constexpr auto is_ascii_digit = [](const char c) { |
107 | return c >= '0' && c <= '9'; | |
108 | }; | |
109 | ||
f67539c2 TL |
110 | auto iter = ctx.begin(); |
111 | // auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; }; | |
112 | auto get_char = [&]() { return iter != ctx.end() ? *iter : '\0'; }; | |
113 | if (get_char() != '{') return iter; | |
114 | ++iter; | |
115 | char c = get_char(); | |
20effc67 | 116 | if (!is_ascii_digit(c) || (++iter, get_char()) != '}') |
f67539c2 | 117 | throw format_error("invalid format"); |
20effc67 | 118 | width_arg_id = fmt::detail::to_unsigned(c - '0'); |
f67539c2 TL |
119 | ctx.check_arg_id(width_arg_id); |
120 | return ++iter; | |
121 | } | |
122 | ||
123 | // Formats S with width given by the argument width_arg_id. | |
124 | auto format(S s, format_context& ctx) { | |
125 | int width = visit_format_arg( | |
126 | [](auto value) -> int { | |
127 | using type = decltype(value); | |
128 | if constexpr (!is_integral_v<type> || is_same_v<type, bool>) | |
129 | throw format_error("width is not integral"); | |
130 | // else if (value < 0 || value > numeric_limits<int>::max()) | |
131 | else if (fmt::detail::is_negative(value) || | |
132 | value > numeric_limits<int>::max()) | |
133 | throw format_error("invalid width"); | |
134 | else | |
135 | return static_cast<int>(value); | |
136 | }, | |
137 | ctx.arg(width_arg_id)); | |
138 | return format_to(ctx.out(), "{0:{1}}", s.value, width); | |
139 | } | |
140 | }; | |
141 | ||
20effc67 | 142 | TEST(std_format_test, parsing) { |
f67539c2 TL |
143 | std::string s = std::format("{0:{1}}", S{42}, 10); // s == " 42" |
144 | EXPECT_EQ(s, " 42"); | |
145 | } | |
146 | ||
147 | #if FMT_USE_INT128 | |
148 | template <> struct std::formatter<__int128_t> : std::formatter<long long> { | |
149 | auto format(__int128_t n, format_context& ctx) { | |
150 | // Format as a long long since we only want to check if it is possible to | |
151 | // specialize formatter for __int128_t. | |
152 | return formatter<long long>::format(static_cast<long long>(n), ctx); | |
153 | } | |
154 | }; | |
155 | ||
20effc67 | 156 | TEST(std_format_test, int128) { |
f67539c2 TL |
157 | __int128_t n = 42; |
158 | auto s = std::format("{}", n); | |
159 | EXPECT_EQ(s, "42"); | |
160 | } | |
161 | #endif // FMT_USE_INT128 |