]> git.proxmox.com Git - ceph.git/blob - ceph/src/fmt/test/chrono-test.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / fmt / test / chrono-test.cc
1 // Formatting library for C++ - time formatting 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/chrono.h"
9
10 #include "gtest-extra.h" // EXPECT_THROW_MSG
11 #include "util.h" // get_locale
12
13 using fmt::runtime;
14
15 using testing::Contains;
16
17 auto make_tm() -> std::tm {
18 auto time = std::tm();
19 time.tm_mday = 1;
20 return time;
21 }
22
23 auto make_hour(int h) -> std::tm {
24 auto time = make_tm();
25 time.tm_hour = h;
26 return time;
27 }
28
29 auto make_minute(int m) -> std::tm {
30 auto time = make_tm();
31 time.tm_min = m;
32 return time;
33 }
34
35 auto make_second(int s) -> std::tm {
36 auto time = make_tm();
37 time.tm_sec = s;
38 return time;
39 }
40
41 TEST(chrono_test, format_tm) {
42 auto tm = std::tm();
43 tm.tm_year = 116;
44 tm.tm_mon = 3;
45 tm.tm_mday = 25;
46 tm.tm_hour = 11;
47 tm.tm_min = 22;
48 tm.tm_sec = 33;
49 EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
50 "The date is 2016-04-25 11:22:33.");
51 }
52
53 TEST(chrono_test, grow_buffer) {
54 auto s = std::string("{:");
55 for (int i = 0; i < 30; ++i) s += "%c";
56 s += "}\n";
57 auto t = std::time(nullptr);
58 fmt::format(fmt::runtime(s), *std::localtime(&t));
59 }
60
61 TEST(chrono_test, format_to_empty_container) {
62 auto time = std::tm();
63 time.tm_sec = 42;
64 auto s = std::string();
65 fmt::format_to(std::back_inserter(s), "{:%S}", time);
66 EXPECT_EQ(s, "42");
67 }
68
69 TEST(chrono_test, empty_result) { EXPECT_EQ(fmt::format("{}", std::tm()), ""); }
70
71 auto equal(const std::tm& lhs, const std::tm& rhs) -> bool {
72 return lhs.tm_sec == rhs.tm_sec && lhs.tm_min == rhs.tm_min &&
73 lhs.tm_hour == rhs.tm_hour && lhs.tm_mday == rhs.tm_mday &&
74 lhs.tm_mon == rhs.tm_mon && lhs.tm_year == rhs.tm_year &&
75 lhs.tm_wday == rhs.tm_wday && lhs.tm_yday == rhs.tm_yday &&
76 lhs.tm_isdst == rhs.tm_isdst;
77 }
78
79 TEST(chrono_test, localtime) {
80 auto t = std::time(nullptr);
81 auto tm = *std::localtime(&t);
82 EXPECT_TRUE(equal(tm, fmt::localtime(t)));
83 }
84
85 TEST(chrono_test, gmtime) {
86 auto t = std::time(nullptr);
87 auto tm = *std::gmtime(&t);
88 EXPECT_TRUE(equal(tm, fmt::gmtime(t)));
89 }
90
91 template <typename TimePoint> auto strftime(TimePoint tp) -> std::string {
92 auto t = std::chrono::system_clock::to_time_t(tp);
93 auto tm = *std::localtime(&t);
94 char output[256] = {};
95 std::strftime(output, sizeof(output), "%Y-%m-%d %H:%M:%S", &tm);
96 return output;
97 }
98
99 TEST(chrono_test, time_point) {
100 auto t1 = std::chrono::system_clock::now();
101 EXPECT_EQ(strftime(t1), fmt::format("{:%Y-%m-%d %H:%M:%S}", t1));
102 EXPECT_EQ(strftime(t1), fmt::format("{}", t1));
103 using time_point =
104 std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
105 auto t2 = time_point(std::chrono::seconds(42));
106 EXPECT_EQ(strftime(t2), fmt::format("{:%Y-%m-%d %H:%M:%S}", t2));
107 }
108
109 #ifndef FMT_STATIC_THOUSANDS_SEPARATOR
110
111 TEST(chrono_test, format_default) {
112 EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
113 EXPECT_EQ("42as",
114 fmt::format("{}", std::chrono::duration<int, std::atto>(42)));
115 EXPECT_EQ("42fs",
116 fmt::format("{}", std::chrono::duration<int, std::femto>(42)));
117 EXPECT_EQ("42ps",
118 fmt::format("{}", std::chrono::duration<int, std::pico>(42)));
119 EXPECT_EQ("42ns", fmt::format("{}", std::chrono::nanoseconds(42)));
120 EXPECT_EQ("42µs", fmt::format("{}", std::chrono::microseconds(42)));
121 EXPECT_EQ("42ms", fmt::format("{}", std::chrono::milliseconds(42)));
122 EXPECT_EQ("42cs",
123 fmt::format("{}", std::chrono::duration<int, std::centi>(42)));
124 EXPECT_EQ("42ds",
125 fmt::format("{}", std::chrono::duration<int, std::deci>(42)));
126 EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
127 EXPECT_EQ("42das",
128 fmt::format("{}", std::chrono::duration<int, std::deca>(42)));
129 EXPECT_EQ("42hs",
130 fmt::format("{}", std::chrono::duration<int, std::hecto>(42)));
131 EXPECT_EQ("42ks",
132 fmt::format("{}", std::chrono::duration<int, std::kilo>(42)));
133 EXPECT_EQ("42Ms",
134 fmt::format("{}", std::chrono::duration<int, std::mega>(42)));
135 EXPECT_EQ("42Gs",
136 fmt::format("{}", std::chrono::duration<int, std::giga>(42)));
137 EXPECT_EQ("42Ts",
138 fmt::format("{}", std::chrono::duration<int, std::tera>(42)));
139 EXPECT_EQ("42Ps",
140 fmt::format("{}", std::chrono::duration<int, std::peta>(42)));
141 EXPECT_EQ("42Es",
142 fmt::format("{}", std::chrono::duration<int, std::exa>(42)));
143 EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42)));
144 EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42)));
145 EXPECT_EQ(
146 "42[15]s",
147 fmt::format("{}", std::chrono::duration<int, std::ratio<15, 1>>(42)));
148 EXPECT_EQ(
149 "42[15/4]s",
150 fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
151 }
152
153 TEST(chrono_test, align) {
154 auto s = std::chrono::seconds(42);
155 EXPECT_EQ("42s ", fmt::format("{:5}", s));
156 EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5));
157 EXPECT_EQ(" 42s", fmt::format("{:>5}", s));
158 EXPECT_EQ("**42s**", fmt::format("{:*^7}", s));
159 EXPECT_EQ("03:25:45 ",
160 fmt::format("{:12%H:%M:%S}", std::chrono::seconds(12345)));
161 EXPECT_EQ(" 03:25:45",
162 fmt::format("{:>12%H:%M:%S}", std::chrono::seconds(12345)));
163 EXPECT_EQ("~~03:25:45~~",
164 fmt::format("{:~^12%H:%M:%S}", std::chrono::seconds(12345)));
165 EXPECT_EQ("03:25:45 ",
166 fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
167 }
168
169 TEST(chrono_test, format_specs) {
170 EXPECT_EQ("%", fmt::format("{:%%}", std::chrono::seconds(0)));
171 EXPECT_EQ("\n", fmt::format("{:%n}", std::chrono::seconds(0)));
172 EXPECT_EQ("\t", fmt::format("{:%t}", std::chrono::seconds(0)));
173 EXPECT_EQ("00", fmt::format("{:%S}", std::chrono::seconds(0)));
174 EXPECT_EQ("00", fmt::format("{:%S}", std::chrono::seconds(60)));
175 EXPECT_EQ("42", fmt::format("{:%S}", std::chrono::seconds(42)));
176 EXPECT_EQ("01.234", fmt::format("{:%S}", std::chrono::milliseconds(1234)));
177 EXPECT_EQ("00", fmt::format("{:%M}", std::chrono::minutes(0)));
178 EXPECT_EQ("00", fmt::format("{:%M}", std::chrono::minutes(60)));
179 EXPECT_EQ("42", fmt::format("{:%M}", std::chrono::minutes(42)));
180 EXPECT_EQ("01", fmt::format("{:%M}", std::chrono::seconds(61)));
181 EXPECT_EQ("00", fmt::format("{:%H}", std::chrono::hours(0)));
182 EXPECT_EQ("00", fmt::format("{:%H}", std::chrono::hours(24)));
183 EXPECT_EQ("14", fmt::format("{:%H}", std::chrono::hours(14)));
184 EXPECT_EQ("01", fmt::format("{:%H}", std::chrono::minutes(61)));
185 EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(0)));
186 EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(12)));
187 EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(24)));
188 EXPECT_EQ("04", fmt::format("{:%I}", std::chrono::hours(4)));
189 EXPECT_EQ("02", fmt::format("{:%I}", std::chrono::hours(14)));
190 EXPECT_EQ("03:25:45",
191 fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345)));
192 EXPECT_EQ("03:25", fmt::format("{:%R}", std::chrono::seconds(12345)));
193 EXPECT_EQ("03:25:45", fmt::format("{:%T}", std::chrono::seconds(12345)));
194 EXPECT_EQ("12345", fmt::format("{:%Q}", std::chrono::seconds(12345)));
195 EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(12345)));
196 }
197
198 TEST(chrono_test, invalid_specs) {
199 auto sec = std::chrono::seconds(0);
200 EXPECT_THROW_MSG(fmt::format(runtime("{:%a}"), sec), fmt::format_error,
201 "no date");
202 EXPECT_THROW_MSG(fmt::format(runtime("{:%A}"), sec), fmt::format_error,
203 "no date");
204 EXPECT_THROW_MSG(fmt::format(runtime("{:%c}"), sec), fmt::format_error,
205 "no date");
206 EXPECT_THROW_MSG(fmt::format(runtime("{:%x}"), sec), fmt::format_error,
207 "no date");
208 EXPECT_THROW_MSG(fmt::format(runtime("{:%Ex}"), sec), fmt::format_error,
209 "no date");
210 EXPECT_THROW_MSG(fmt::format(runtime("{:%X}"), sec), fmt::format_error,
211 "no date");
212 EXPECT_THROW_MSG(fmt::format(runtime("{:%EX}"), sec), fmt::format_error,
213 "no date");
214 EXPECT_THROW_MSG(fmt::format(runtime("{:%D}"), sec), fmt::format_error,
215 "no date");
216 EXPECT_THROW_MSG(fmt::format(runtime("{:%F}"), sec), fmt::format_error,
217 "no date");
218 EXPECT_THROW_MSG(fmt::format(runtime("{:%Ec}"), sec), fmt::format_error,
219 "no date");
220 EXPECT_THROW_MSG(fmt::format(runtime("{:%w}"), sec), fmt::format_error,
221 "no date");
222 EXPECT_THROW_MSG(fmt::format(runtime("{:%u}"), sec), fmt::format_error,
223 "no date");
224 EXPECT_THROW_MSG(fmt::format(runtime("{:%b}"), sec), fmt::format_error,
225 "no date");
226 EXPECT_THROW_MSG(fmt::format(runtime("{:%B}"), sec), fmt::format_error,
227 "no date");
228 EXPECT_THROW_MSG(fmt::format(runtime("{:%z}"), sec), fmt::format_error,
229 "no date");
230 EXPECT_THROW_MSG(fmt::format(runtime("{:%Z}"), sec), fmt::format_error,
231 "no date");
232 EXPECT_THROW_MSG(fmt::format(runtime("{:%Eq}"), sec), fmt::format_error,
233 "invalid format");
234 EXPECT_THROW_MSG(fmt::format(runtime("{:%Oq}"), sec), fmt::format_error,
235 "invalid format");
236 }
237
238 auto format_tm(const std::tm& time, fmt::string_view spec,
239 const std::locale& loc) -> std::string {
240 auto& facet = std::use_facet<std::time_put<char>>(loc);
241 std::ostringstream os;
242 os.imbue(loc);
243 facet.put(os, os, ' ', &time, spec.begin(), spec.end());
244 return os.str();
245 }
246
247 TEST(chrono_test, locale) {
248 auto loc = get_locale("ja_JP.utf8");
249 if (loc == std::locale::classic()) return;
250 # define EXPECT_TIME(spec, time, duration) \
251 { \
252 auto jp_loc = std::locale("ja_JP.utf8"); \
253 EXPECT_EQ(format_tm(time, spec, jp_loc), \
254 fmt::format(jp_loc, "{:L" spec "}", duration)); \
255 }
256 EXPECT_TIME("%OH", make_hour(14), std::chrono::hours(14));
257 EXPECT_TIME("%OI", make_hour(14), std::chrono::hours(14));
258 EXPECT_TIME("%OM", make_minute(42), std::chrono::minutes(42));
259 EXPECT_TIME("%OS", make_second(42), std::chrono::seconds(42));
260 auto time = make_tm();
261 time.tm_hour = 3;
262 time.tm_min = 25;
263 time.tm_sec = 45;
264 auto sec = std::chrono::seconds(12345);
265 EXPECT_TIME("%r", time, sec);
266 EXPECT_TIME("%p", time, sec);
267 }
268
269 using dms = std::chrono::duration<double, std::milli>;
270
271 TEST(chrono_test, format_default_fp) {
272 typedef std::chrono::duration<float> fs;
273 EXPECT_EQ("1.234s", fmt::format("{}", fs(1.234)));
274 typedef std::chrono::duration<float, std::milli> fms;
275 EXPECT_EQ("1.234ms", fmt::format("{}", fms(1.234)));
276 typedef std::chrono::duration<double> ds;
277 EXPECT_EQ("1.234s", fmt::format("{}", ds(1.234)));
278 EXPECT_EQ("1.234ms", fmt::format("{}", dms(1.234)));
279 }
280
281 TEST(chrono_test, format_precision) {
282 EXPECT_THROW_MSG(fmt::format(runtime("{:.2}"), std::chrono::seconds(42)),
283 fmt::format_error,
284 "precision not allowed for this argument type");
285 EXPECT_EQ("1.2ms", fmt::format("{:.1}", dms(1.234)));
286 EXPECT_EQ("1.23ms", fmt::format("{:.{}}", dms(1.234), 2));
287 }
288
289 TEST(chrono_test, format_full_specs) {
290 EXPECT_EQ("1.2ms ", fmt::format("{:6.1}", dms(1.234)));
291 EXPECT_EQ(" 1.23ms", fmt::format("{:>8.{}}", dms(1.234), 2));
292 EXPECT_EQ(" 1.2ms ", fmt::format("{:^{}.{}}", dms(1.234), 7, 1));
293 EXPECT_EQ(" 1.23ms ", fmt::format("{0:^{2}.{1}}", dms(1.234), 2, 8));
294 EXPECT_EQ("=1.234ms=", fmt::format("{:=^{}.{}}", dms(1.234), 9, 3));
295 EXPECT_EQ("*1.2340ms*", fmt::format("{:*^10.4}", dms(1.234)));
296 }
297
298 TEST(chrono_test, format_simple_q) {
299 typedef std::chrono::duration<float> fs;
300 EXPECT_EQ("1.234 s", fmt::format("{:%Q %q}", fs(1.234)));
301 typedef std::chrono::duration<float, std::milli> fms;
302 EXPECT_EQ("1.234 ms", fmt::format("{:%Q %q}", fms(1.234)));
303 typedef std::chrono::duration<double> ds;
304 EXPECT_EQ("1.234 s", fmt::format("{:%Q %q}", ds(1.234)));
305 EXPECT_EQ("1.234 ms", fmt::format("{:%Q %q}", dms(1.234)));
306 }
307
308 TEST(chrono_test, format_precision_q) {
309 EXPECT_THROW_MSG(fmt::format(runtime("{:.2%Q %q}"), std::chrono::seconds(42)),
310 fmt::format_error,
311 "precision not allowed for this argument type");
312 EXPECT_EQ("1.2 ms", fmt::format("{:.1%Q %q}", dms(1.234)));
313 EXPECT_EQ("1.23 ms", fmt::format("{:.{}%Q %q}", dms(1.234), 2));
314 }
315
316 TEST(chrono_test, format_full_specs_q) {
317 EXPECT_EQ("1.2 ms ", fmt::format("{:7.1%Q %q}", dms(1.234)));
318 EXPECT_EQ(" 1.23 ms", fmt::format("{:>8.{}%Q %q}", dms(1.234), 2));
319 EXPECT_EQ(" 1.2 ms ", fmt::format("{:^{}.{}%Q %q}", dms(1.234), 8, 1));
320 EXPECT_EQ(" 1.23 ms ", fmt::format("{0:^{2}.{1}%Q %q}", dms(1.234), 2, 9));
321 EXPECT_EQ("=1.234 ms=", fmt::format("{:=^{}.{}%Q %q}", dms(1.234), 10, 3));
322 EXPECT_EQ("*1.2340 ms*", fmt::format("{:*^11.4%Q %q}", dms(1.234)));
323 }
324
325 TEST(chrono_test, invalid_width_id) {
326 EXPECT_THROW(fmt::format(runtime("{:{o}"), std::chrono::seconds(0)),
327 fmt::format_error);
328 }
329
330 TEST(chrono_test, invalid_colons) {
331 EXPECT_THROW(fmt::format(runtime("{0}=:{0::"), std::chrono::seconds(0)),
332 fmt::format_error);
333 }
334
335 TEST(chrono_test, negative_durations) {
336 EXPECT_EQ("-12345", fmt::format("{:%Q}", std::chrono::seconds(-12345)));
337 EXPECT_EQ("-03:25:45",
338 fmt::format("{:%H:%M:%S}", std::chrono::seconds(-12345)));
339 EXPECT_EQ("-00:01",
340 fmt::format("{:%M:%S}", std::chrono::duration<double>(-1)));
341 EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(-12345)));
342 EXPECT_EQ("-00.127",
343 fmt::format("{:%S}",
344 std::chrono::duration<signed char, std::milli>{-127}));
345 auto min = std::numeric_limits<int>::min();
346 EXPECT_EQ(fmt::format("{}", min),
347 fmt::format("{:%Q}", std::chrono::duration<int>(min)));
348 }
349
350 TEST(chrono_test, special_durations) {
351 EXPECT_EQ(
352 "40.",
353 fmt::format("{:%S}", std::chrono::duration<double>(1e20)).substr(0, 3));
354 auto nan = std::numeric_limits<double>::quiet_NaN();
355 EXPECT_EQ(
356 "nan nan nan nan nan:nan nan",
357 fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan)));
358 fmt::format("{:%S}",
359 std::chrono::duration<float, std::atto>(1.79400457e+31f));
360 EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::exa>(1)),
361 "1Es");
362 EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)),
363 "1as");
364 EXPECT_EQ(fmt::format("{:%R}", std::chrono::duration<char, std::mega>{2}),
365 "03:33");
366 EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
367 "03:33:20");
368 }
369
370 TEST(chrono_test, unsigned_duration) {
371 EXPECT_EQ("42s", fmt::format("{}", std::chrono::duration<unsigned>(42)));
372 }
373
374 TEST(chrono_test, weekday) {
375 auto loc = get_locale("ru_RU.UTF-8");
376 std::locale::global(loc);
377 auto mon = fmt::weekday(1);
378 EXPECT_EQ(fmt::format("{}", mon), "Mon");
379 if (loc != std::locale::classic()) {
380 EXPECT_THAT((std::vector<std::string>{"пн", "Пн", "пнд", "Пнд"}),
381 Contains(fmt::format(loc, "{:L}", mon)));
382 }
383 }
384
385 #endif // FMT_STATIC_THOUSANDS_SEPARATOR