Line data Source code
1 : // Copyright (c) 2018-2026 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : /** \file
20 : * \brief Verify that the timespec_ex operators function as expected.
21 : *
22 : * This file implements tests for the timespec_ex operator and other
23 : * functions.
24 : */
25 :
26 : // self
27 : //
28 : #include <snapdev/timespec_ex.h>
29 :
30 : #include "catch_main.h"
31 :
32 :
33 : // snapdev
34 : //
35 : #include <snapdev/not_reached.h>
36 :
37 :
38 : // C++
39 : //
40 : #include <iomanip>
41 :
42 :
43 : // last include
44 : //
45 : #include <snapdev/poison.h>
46 :
47 :
48 :
49 : namespace
50 : {
51 :
52 :
53 :
54 : int g_state(-1);
55 : int g_error(0);
56 :
57 6 : char * wrap_nl_langinfo(nl_item item)
58 : {
59 6 : switch(g_state++)
60 : {
61 1 : case 0:
62 1 : if(item != D_T_FMT)
63 : {
64 0 : g_error = 1;
65 : }
66 1 : return const_cast<char *>(""); // exercise the empty string
67 :
68 1 : case 10:
69 1 : if(item != D_T_FMT)
70 : {
71 0 : g_error = 1;
72 : }
73 1 : return const_cast<char *>("%T");
74 :
75 1 : case 20:
76 1 : if(item != D_T_FMT)
77 : {
78 0 : g_error = 1;
79 : }
80 1 : return const_cast<char *>("%r %X %EX");
81 :
82 1 : case 21:
83 1 : if(item != T_FMT_AMPM)
84 : {
85 0 : g_error = 1;
86 : }
87 1 : return const_cast<char *>("%I:%M:%S %p");
88 :
89 1 : case 22:
90 1 : if(item != T_FMT)
91 : {
92 0 : g_error = 1;
93 : }
94 1 : return const_cast<char *>("%H:%M:%S");
95 :
96 1 : case 23:
97 1 : if(item != ERA_T_FMT)
98 : {
99 0 : g_error = 1;
100 : }
101 1 : return const_cast<char *>("%H.%M.%S");
102 :
103 0 : default:
104 0 : throw std::logic_error("invalid state encountered.");
105 :
106 : }
107 :
108 : snapdev::NOT_REACHED();
109 : }
110 :
111 :
112 :
113 : }
114 : // no name namespace
115 :
116 :
117 :
118 3 : CATCH_TEST_CASE("timespec_ex_basics", "[time]")
119 : {
120 3 : CATCH_START_SECTION("timespec_ex_basics: minimum")
121 : {
122 1 : snapdev::timespec_ex a(snapdev::timespec_ex::min());
123 :
124 1 : CATCH_REQUIRE(a.tv_sec == std::numeric_limits<decltype(a.tv_sec)>::min());
125 1 : CATCH_REQUIRE(a.tv_nsec == 0);
126 : }
127 3 : CATCH_END_SECTION()
128 :
129 3 : CATCH_START_SECTION("timespec_ex_basics: maximum")
130 : {
131 1 : snapdev::timespec_ex a(snapdev::timespec_ex::max());
132 :
133 1 : CATCH_REQUIRE(a.tv_sec == std::numeric_limits<decltype(a.tv_sec)>::max());
134 1 : CATCH_REQUIRE(a.tv_nsec == 999'999'999);
135 : }
136 3 : CATCH_END_SECTION()
137 :
138 3 : CATCH_START_SECTION("timespec_ex_basics: time is in the future")
139 : {
140 1 : snapdev::timespec_ex a(snapdev::now());
141 :
142 1 : CATCH_REQUIRE_FALSE(a.is_in_the_future());
143 :
144 1 : a += static_cast<std::int64_t>(10'000'000'000); // +10s
145 1 : CATCH_REQUIRE(a.is_in_the_future());
146 : }
147 3 : CATCH_END_SECTION()
148 3 : }
149 :
150 :
151 11 : CATCH_TEST_CASE("timespec_ex_math", "[time][math]")
152 : {
153 11 : CATCH_START_SECTION("timespec_ex_math: simple add")
154 : {
155 1 : snapdev::timespec_ex a(timespec{ 5L, 345L });
156 :
157 1 : snapdev::timespec_ex b;
158 1 : timespec raw{ 13L, 701L };
159 1 : b = raw;
160 :
161 1 : CATCH_REQUIRE(a.valid());
162 1 : CATCH_REQUIRE(b.valid());
163 1 : CATCH_REQUIRE_FALSE(a.negative());
164 1 : CATCH_REQUIRE_FALSE(b.negative());
165 :
166 1 : snapdev::timespec_ex c(a + b);
167 :
168 1 : a += b;
169 :
170 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L);
171 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L);
172 :
173 1 : CATCH_REQUIRE(b.tv_sec == 13L);
174 1 : CATCH_REQUIRE(b.tv_nsec == 701L);
175 :
176 1 : CATCH_REQUIRE(c.tv_sec == 5L + 13L);
177 1 : CATCH_REQUIRE(c.tv_nsec == 345L + 701L);
178 1 : CATCH_REQUIRE(a == c);
179 1 : CATCH_REQUIRE(c == a);
180 :
181 1 : timespec d{ 3L, 55L };
182 :
183 1 : a += d;
184 :
185 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L + 3L);
186 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L + 55L);
187 :
188 1 : a += 301L;
189 :
190 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L + 3L);
191 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L + 55L + 301L);
192 :
193 1 : a -= 1'000'000'259L;
194 :
195 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L + 3L - 1L);
196 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L + 55L + 301L - 259L);
197 : }
198 11 : CATCH_END_SECTION()
199 :
200 11 : CATCH_START_SECTION("timespec_ex_math: simple subtract")
201 : {
202 1 : snapdev::timespec_ex a(timespec{ 25L, 1'345L });
203 1 : snapdev::timespec_ex b(timespec{ 13L, 701L });
204 :
205 1 : CATCH_REQUIRE(a.valid());
206 1 : CATCH_REQUIRE(b.valid());
207 :
208 1 : snapdev::timespec_ex c(a - b);
209 1 : snapdev::timespec_ex d(-b);
210 1 : snapdev::timespec_ex e(a + d);
211 1 : snapdev::timespec_ex f(a - 1'000L); // -1us
212 :
213 1 : a -= b;
214 :
215 1 : CATCH_REQUIRE(a.tv_sec == 25L - 13L);
216 1 : CATCH_REQUIRE(a.tv_nsec == 1'345L - 701L);
217 :
218 1 : CATCH_REQUIRE(b.tv_sec == 13L);
219 1 : CATCH_REQUIRE(b.tv_nsec == 701L);
220 :
221 1 : CATCH_REQUIRE(c.tv_sec == 25L - 13L);
222 1 : CATCH_REQUIRE(c.tv_nsec == 1'345L - 701L);
223 1 : CATCH_REQUIRE(a == c);
224 1 : CATCH_REQUIRE(c == a);
225 1 : CATCH_REQUIRE(a == e);
226 1 : CATCH_REQUIRE(e == c);
227 :
228 1 : CATCH_REQUIRE(f.tv_sec == 25L);
229 1 : CATCH_REQUIRE(f.tv_nsec == 1'345L - 1'000L);
230 : }
231 11 : CATCH_END_SECTION()
232 :
233 11 : CATCH_START_SECTION("timespec_ex_math: add \"minus one day\"")
234 : {
235 1 : snapdev::timespec_ex now(timespec{ 1629652541L, 345L });
236 1 : snapdev::timespec_ex backward(timespec{ -86400L, 0L }); // -1 day
237 :
238 1 : CATCH_REQUIRE(!!now);
239 1 : CATCH_REQUIRE_FALSE(!backward);
240 1 : CATCH_REQUIRE(backward.negative());
241 :
242 1 : now += backward;
243 :
244 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L - 86400L);
245 1 : CATCH_REQUIRE(now.tv_nsec == 345L);
246 :
247 1 : CATCH_REQUIRE(backward.tv_sec == -86400L);
248 1 : CATCH_REQUIRE(backward.tv_nsec == 0L);
249 : }
250 11 : CATCH_END_SECTION()
251 :
252 11 : CATCH_START_SECTION("timespec_ex_math: add with nano overflow")
253 : {
254 1 : snapdev::timespec_ex now(timespec{ 1629652541L, 913'788'345L });
255 1 : snapdev::timespec_ex backward(timespec{ 86400L, 500'000'000L }); // +1 day and 0.5 seconds
256 :
257 1 : CATCH_REQUIRE(!!now);
258 1 : CATCH_REQUIRE(!!backward);
259 :
260 1 : now += backward;
261 :
262 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 86400L + 1L); // +1 for the overflow
263 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L);
264 :
265 1 : CATCH_REQUIRE(backward.tv_sec == 86400L);
266 1 : CATCH_REQUIRE(backward.tv_nsec == 500'000'000L);
267 : }
268 11 : CATCH_END_SECTION()
269 :
270 11 : CATCH_START_SECTION("timespec_ex_math: subtract with nano underflow")
271 : {
272 1 : snapdev::timespec_ex a(13L, 701L);
273 1 : snapdev::timespec_ex b(25L, 1'345L);
274 :
275 1 : CATCH_REQUIRE(a.valid());
276 1 : CATCH_REQUIRE(b.valid());
277 :
278 1 : a -= b;
279 :
280 1 : CATCH_REQUIRE(a.tv_sec == 13L - 25L - 1L);
281 1 : CATCH_REQUIRE(a.tv_nsec == 701L - 1'345L + 1'000'000'000L);
282 :
283 1 : CATCH_REQUIRE(b.tv_sec == 25L);
284 1 : CATCH_REQUIRE(b.tv_nsec == 1'345L);
285 : }
286 11 : CATCH_END_SECTION()
287 :
288 11 : CATCH_START_SECTION("timespec_ex_math: -1, 0, +1")
289 : {
290 1 : snapdev::timespec_ex a = {};
291 :
292 1 : CATCH_REQUIRE(!a);
293 1 : CATCH_REQUIRE_FALSE(a.negative());
294 :
295 1 : --a;
296 :
297 1 : CATCH_REQUIRE_FALSE(!a);
298 1 : CATCH_REQUIRE(a.negative());
299 1 : CATCH_REQUIRE(a.tv_sec == -1L);
300 1 : CATCH_REQUIRE(a.tv_nsec == 999'999'999L);
301 :
302 1 : ++a;
303 :
304 1 : CATCH_REQUIRE(!a);
305 1 : CATCH_REQUIRE(a.tv_sec == 0L);
306 1 : CATCH_REQUIRE(a.tv_nsec == 0L);
307 :
308 1 : ++a;
309 :
310 1 : CATCH_REQUIRE(!!a);
311 1 : CATCH_REQUIRE_FALSE(a.negative());
312 1 : CATCH_REQUIRE(a.tv_sec == 0L);
313 1 : CATCH_REQUIRE(a.tv_nsec == 1L);
314 :
315 1 : --a;
316 :
317 1 : CATCH_REQUIRE(!a);
318 1 : CATCH_REQUIRE(a.tv_sec == 0L);
319 1 : CATCH_REQUIRE(a.tv_nsec == 0L);
320 : }
321 11 : CATCH_END_SECTION()
322 :
323 11 : CATCH_START_SECTION("timespec_ex_math: add nanos")
324 : {
325 1 : snapdev::timespec_ex now(1629652541L, 913'788'345L);
326 1 : std::int64_t nsec(500'000'000L);
327 :
328 1 : CATCH_REQUIRE(!!now);
329 :
330 1 : snapdev::timespec_ex sum(now + nsec);
331 :
332 1 : now += nsec;
333 :
334 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 1L); // +1 for the overflow
335 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L);
336 :
337 1 : CATCH_REQUIRE(now == sum);
338 1 : CATCH_REQUIRE_FALSE(now != sum);
339 1 : CATCH_REQUIRE_FALSE(now < sum);
340 1 : CATCH_REQUIRE(now <= sum);
341 1 : CATCH_REQUIRE_FALSE(now > sum);
342 1 : CATCH_REQUIRE(now >= sum);
343 :
344 1 : CATCH_REQUIRE(nsec == 500'000'000L);
345 :
346 1 : nsec += 86400L * 1'000'000'000L;
347 :
348 1 : snapdev::timespec_ex total(sum + nsec);
349 :
350 1 : now += nsec;
351 :
352 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 1L + 86400L); // +1 for the overflow above
353 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L + 500'000'000L);
354 :
355 1 : CATCH_REQUIRE(nsec == 500'000'000L + 86400L * 1'000'000'000L);
356 :
357 1 : CATCH_REQUIRE_FALSE(now == sum);
358 1 : CATCH_REQUIRE(now != sum);
359 1 : CATCH_REQUIRE_FALSE(now < sum);
360 1 : CATCH_REQUIRE_FALSE(now <= sum);
361 1 : CATCH_REQUIRE(now > sum);
362 1 : CATCH_REQUIRE(now >= sum);
363 :
364 1 : CATCH_REQUIRE(now == total);
365 1 : CATCH_REQUIRE_FALSE(now != total);
366 1 : CATCH_REQUIRE_FALSE(now < total);
367 1 : CATCH_REQUIRE(now <= total);
368 1 : CATCH_REQUIRE_FALSE(now > total);
369 1 : CATCH_REQUIRE(now >= total);
370 :
371 1 : snapdev::timespec_ex pre(++total);
372 :
373 1 : CATCH_REQUIRE(pre == total);
374 1 : CATCH_REQUIRE_FALSE(pre != total);
375 1 : CATCH_REQUIRE_FALSE(pre < total);
376 1 : CATCH_REQUIRE(pre <= total);
377 1 : CATCH_REQUIRE_FALSE(pre > total);
378 1 : CATCH_REQUIRE(pre >= total);
379 :
380 1 : CATCH_REQUIRE_FALSE(now == total);
381 1 : CATCH_REQUIRE(now != total);
382 1 : CATCH_REQUIRE(now < total);
383 1 : CATCH_REQUIRE(now <= total);
384 1 : CATCH_REQUIRE_FALSE(now > total);
385 1 : CATCH_REQUIRE_FALSE(now >= total);
386 :
387 1 : snapdev::timespec_ex post(now++);
388 :
389 1 : CATCH_REQUIRE_FALSE(post == total);
390 1 : CATCH_REQUIRE(post != total);
391 1 : CATCH_REQUIRE(post < total);
392 1 : CATCH_REQUIRE(post <= total);
393 1 : CATCH_REQUIRE_FALSE(post > total);
394 1 : CATCH_REQUIRE_FALSE(post >= total);
395 :
396 1 : CATCH_REQUIRE(now == total);
397 1 : CATCH_REQUIRE_FALSE(now != total);
398 1 : CATCH_REQUIRE_FALSE(now < total);
399 1 : CATCH_REQUIRE(now <= total);
400 1 : CATCH_REQUIRE_FALSE(now > total);
401 1 : CATCH_REQUIRE(now >= total);
402 :
403 1 : pre = --total;
404 :
405 1 : CATCH_REQUIRE(pre == total);
406 1 : CATCH_REQUIRE_FALSE(pre != total);
407 1 : CATCH_REQUIRE_FALSE(pre < total);
408 1 : CATCH_REQUIRE(pre <= total);
409 1 : CATCH_REQUIRE_FALSE(pre > total);
410 1 : CATCH_REQUIRE(pre >= total);
411 :
412 1 : CATCH_REQUIRE_FALSE(now == total);
413 1 : CATCH_REQUIRE(now != total);
414 1 : CATCH_REQUIRE_FALSE(now < total);
415 1 : CATCH_REQUIRE_FALSE(now <= total);
416 1 : CATCH_REQUIRE(now > total);
417 1 : CATCH_REQUIRE(now >= total);
418 :
419 1 : post = now--;
420 :
421 1 : CATCH_REQUIRE_FALSE(post == total);
422 1 : CATCH_REQUIRE(post != total);
423 1 : CATCH_REQUIRE_FALSE(post < total);
424 1 : CATCH_REQUIRE_FALSE(post <= total);
425 1 : CATCH_REQUIRE(post > total);
426 1 : CATCH_REQUIRE(post >= total);
427 :
428 1 : CATCH_REQUIRE(now == total);
429 1 : CATCH_REQUIRE_FALSE(now != total);
430 1 : CATCH_REQUIRE_FALSE(now < total);
431 1 : CATCH_REQUIRE(now <= total);
432 1 : CATCH_REQUIRE_FALSE(now > total);
433 1 : CATCH_REQUIRE(now >= total);
434 :
435 : }
436 11 : CATCH_END_SECTION()
437 :
438 11 : CATCH_START_SECTION("timespec_ex_math: load/save")
439 : {
440 1 : snapdev::timespec_ex now(1629652549L, 913'788'345L);
441 :
442 1 : std::int64_t nsec(now.to_nsec());
443 1 : CATCH_REQUIRE(nsec == 1629652549L * 1'000'000'000L + 913'788'345L);
444 :
445 1 : std::int64_t usec(now.to_usec());
446 1 : CATCH_REQUIRE(usec == 1629652549L * 1'000'000 + 913'788L);
447 :
448 1 : snapdev::timespec_ex save;
449 1 : CATCH_REQUIRE(!save);
450 1 : CATCH_REQUIRE(save.valid());
451 1 : save = nsec;
452 :
453 1 : CATCH_REQUIRE(nsec == 1629652549L * 1'000'000'000L + 913'788'345L);
454 1 : CATCH_REQUIRE(save.tv_sec == 1629652549L);
455 1 : CATCH_REQUIRE(save.tv_nsec == 913'788'345L);
456 :
457 1 : double seconds(33.0);
458 1 : save = seconds;
459 1 : CATCH_REQUIRE(save.tv_sec == 33L);
460 1 : CATCH_REQUIRE(save.tv_nsec == 0L);
461 :
462 1 : double precise_time(save.to_sec());
463 1 : bool precise_result(precise_time >= 33.0 && precise_time <= 33.0);
464 1 : CATCH_REQUIRE(precise_result);
465 :
466 1 : seconds = 81.325611932;
467 1 : save = seconds;
468 1 : CATCH_REQUIRE(save.tv_sec == 81L);
469 1 : CATCH_REQUIRE(save.tv_nsec == 325'611'932L);
470 :
471 1 : precise_time = save.to_sec();
472 1 : precise_result = precise_time >= 81.325611932 && precise_time <= 81.325611932;
473 1 : CATCH_REQUIRE(precise_result);
474 1 : CATCH_REQUIRE(save == 81.325611932);
475 1 : CATCH_REQUIRE_FALSE(save == 83.5);
476 1 : CATCH_REQUIRE(save != 83.5);
477 1 : CATCH_REQUIRE_FALSE(save != 81.325611932);
478 1 : CATCH_REQUIRE(save < 83.5);
479 1 : CATCH_REQUIRE(save <= 81.33);
480 1 : CATCH_REQUIRE(save <= 81.325611932);
481 1 : CATCH_REQUIRE(save > 71.5);
482 1 : CATCH_REQUIRE(save >= 81.324);
483 1 : CATCH_REQUIRE(save >= 81.325611932);
484 :
485 1 : snapdev::timespec_ex plus(save + 3.000101);
486 1 : precise_time = plus.to_sec();
487 1 : precise_result = precise_time >= 84.325712930 && precise_time <= 84.325712931; // we lose some precision here
488 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
489 : //<< " expected " << 81.325611932 + 3.000101 << "\n";
490 1 : CATCH_REQUIRE(precise_result);
491 :
492 1 : save += 3.000101;
493 1 : precise_time = save.to_sec();
494 1 : precise_result = precise_time >= 84.325712930 && precise_time <= 84.325712931; // we lose some precision here
495 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
496 : //<< " expected " << 81.325611932 + 3.000101 << "\n";
497 1 : CATCH_REQUIRE(precise_result);
498 1 : CATCH_REQUIRE(save == plus);
499 :
500 1 : snapdev::timespec_ex minus(save - 1.20050001);
501 1 : precise_time = minus.to_sec();
502 1 : precise_result = precise_time >= 83.125212920 && precise_time <= 83.125212921;
503 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
504 : //<< " expected " << 81.325611932 + 3.000101 - 1.20050001 << "\n";
505 1 : CATCH_REQUIRE(precise_result);
506 :
507 1 : save -= 1.20050001;
508 1 : precise_time = save.to_sec();
509 1 : precise_result = precise_time >= 83.125212920 && precise_time <= 83.125212921;
510 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
511 : //<< " expected " << 81.325611932 + 3.000101 - 1.20050001 << "\n";
512 1 : CATCH_REQUIRE(precise_result);
513 1 : CATCH_REQUIRE(save == minus);
514 :
515 1 : double neg(-701.445123421);
516 1 : save = neg;
517 1 : CATCH_REQUIRE(save.tv_sec == -702L);
518 2 : precise_result = save.tv_nsec >= -445'123'420L + 1'000'000'000L
519 1 : || save.tv_nsec <= -445'123'422L + 1'000'000'000L;
520 1 : CATCH_REQUIRE(precise_result);
521 : }
522 11 : CATCH_END_SECTION()
523 :
524 11 : CATCH_START_SECTION("timespec_ex_math: negative + negative")
525 : {
526 1 : snapdev::timespec_ex pa(4511L, 913'788'345L);
527 1 : snapdev::timespec_ex pb( 311L, 301'225'198L);
528 :
529 1 : snapdev::timespec_ex na(-pa);
530 1 : snapdev::timespec_ex nb(-pb);
531 :
532 1 : snapdev::timespec_ex sum_ab(na + nb);
533 1 : snapdev::timespec_ex sum_ba(nb + na);
534 1 : snapdev::timespec_ex diff_ab(na - nb);
535 1 : snapdev::timespec_ex diff_ba(nb - na);
536 :
537 1 : CATCH_REQUIRE(sum_ab.tv_sec != -4511L + -311L);
538 1 : CATCH_REQUIRE(sum_ab.tv_sec == -4511L + -1L + -311L + -1L);
539 1 : CATCH_REQUIRE(sum_ab.tv_nsec != -913'788'345L + -301'225'198L);
540 1 : CATCH_REQUIRE(sum_ab.tv_nsec == (1'000'000'000 - 913'788'345L) + (1'000'000'000L - 301'225'198L));
541 :
542 1 : CATCH_REQUIRE(sum_ab == (-4511L + -1L + -311L + -1L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + (1'000'000'000L - 301'225'198L));
543 1 : CATCH_REQUIRE_FALSE(sum_ab != (-4511L + -1L + -311L + -1L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + (1'000'000'000L - 301'225'198L));
544 1 : CATCH_REQUIRE_FALSE(sum_ab == (-4511L + 0L + -311L + -1L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + (1'000'000'000L - 301'225'198L));
545 1 : CATCH_REQUIRE(sum_ab != (-4511L + -1L + -311L + -1L) * 1'000'000'000 + (1'000'000'000 - 913'788'344L) + (1'000'000'000L - 301'225'198L));
546 :
547 1 : CATCH_REQUIRE(sum_ba.tv_sec != -311L + -4511L);
548 1 : CATCH_REQUIRE(sum_ba.tv_sec == -311L + -1L + -4511L + -1L);
549 1 : CATCH_REQUIRE(sum_ba.tv_nsec != -301'225'198L + -913'788'345L);
550 1 : CATCH_REQUIRE(sum_ba.tv_nsec == (1'000'000'000L - 301'225'198L) + (1'000'000'000 - 913'788'345L));
551 :
552 1 : CATCH_REQUIRE(diff_ab.tv_sec == -4511L + -1L + 311L);
553 1 : CATCH_REQUIRE(diff_ab.tv_nsec == (1'000'000'000 - 913'788'345L) + 301'225'198L);
554 :
555 1 : CATCH_REQUIRE(diff_ab >= (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
556 1 : CATCH_REQUIRE_FALSE(diff_ab > (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
557 1 : CATCH_REQUIRE(diff_ab <= (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
558 1 : CATCH_REQUIRE_FALSE(diff_ab < (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
559 :
560 1 : CATCH_REQUIRE(diff_ba.tv_sec == -311L + -1L + 4511L + 1L);
561 1 : CATCH_REQUIRE(diff_ba.tv_nsec == (((1'000'000'000 - 301'225'198L) + 913'788'345L) - 1'000'000'000));
562 :
563 1 : CATCH_REQUIRE(diff_ba >= (-311L + -1L + 4511L + 1L) * 1'000'000'000 + (((1'000'000'000 - 301'225'198L) + 913'788'345L) - 1'000'000'000));
564 1 : CATCH_REQUIRE_FALSE(diff_ba > (-311L + -1L + 4511L + 1L) * 1'000'000'000 + (((1'000'000'000 - 301'225'198L) + 913'788'345L) - 1'000'000'000));
565 1 : CATCH_REQUIRE(diff_ba <= (-311L + -1L + 4511L + 1L) * 1'000'000'000 + (((1'000'000'000 - 301'225'198L) + 913'788'345L) - 1'000'000'000));
566 1 : CATCH_REQUIRE_FALSE(diff_ba < (-311L + -1L + 4511L + 1L) * 1'000'000'000 + (((1'000'000'000 - 301'225'198L) + 913'788'345L) - 1'000'000'000));
567 : }
568 11 : CATCH_END_SECTION()
569 :
570 11 : CATCH_START_SECTION("timespec_ex_math: system time (gettime() function)")
571 : {
572 1 : snapdev::timespec_ex now;
573 1 : timespec verify = {};
574 :
575 1 : now = snapdev::timespec_ex::gettime();
576 1 : clock_gettime(CLOCK_REALTIME, &verify);
577 :
578 1 : snapdev::timespec_ex const diff(now - verify);
579 1 : snapdev::timespec_ex const max_diff(100L);
580 :
581 1 : CATCH_REQUIRE(diff < max_diff);
582 : }
583 11 : CATCH_END_SECTION()
584 :
585 11 : CATCH_START_SECTION("timespec_ex_math: system time (snapdev::now() function)")
586 : {
587 1 : timespec verify = {};
588 :
589 1 : snapdev::timespec_ex const now(snapdev::now());
590 1 : clock_gettime(CLOCK_REALTIME, &verify);
591 :
592 1 : snapdev::timespec_ex const diff(now - verify);
593 1 : snapdev::timespec_ex const max_diff(0, 100L);
594 :
595 1 : CATCH_REQUIRE(diff < max_diff);
596 : }
597 11 : CATCH_END_SECTION()
598 11 : }
599 :
600 :
601 2 : CATCH_TEST_CASE("timespec_ex_tm", "[time]")
602 : {
603 2 : CATCH_START_SECTION("timespec_ex_tm: tm is canonical")
604 : {
605 1001 : for(int count(0); count < 1'000; ++count)
606 : {
607 1000 : time_t const org(snapdev::random(-1'000'000LL, 2'000'000'000LL));
608 :
609 1000 : struct tm t;
610 1000 : gmtime_r(&org, &t);
611 :
612 : // a brand new tm is always canonical
613 : //
614 1000 : CATCH_REQUIRE(snapdev::is_canonical_tm(t));
615 :
616 : // tweak second
617 : //
618 1000 : struct tm sec(t);
619 1000 : sec.tm_sec += 100;
620 1000 : CATCH_REQUIRE_FALSE(snapdev::is_canonical_tm(sec));
621 :
622 : // tweak minute
623 : //
624 1000 : struct tm min(t);
625 1000 : min.tm_min += 100;
626 1000 : CATCH_REQUIRE_FALSE(snapdev::is_canonical_tm(min));
627 :
628 : // tweak hour
629 : //
630 1000 : struct tm hour(t);
631 1000 : hour.tm_hour += 100;
632 1000 : CATCH_REQUIRE_FALSE(snapdev::is_canonical_tm(hour));
633 :
634 : // tweak mday
635 : //
636 1000 : struct tm mday(t);
637 1000 : mday.tm_mday += 100;
638 1000 : CATCH_REQUIRE_FALSE(snapdev::is_canonical_tm(mday));
639 :
640 : // tweak month
641 : //
642 1000 : struct tm mon(t);
643 1000 : mon.tm_mon += 100;
644 1000 : CATCH_REQUIRE_FALSE(snapdev::is_canonical_tm(mon));
645 :
646 : // tweak years, no effect
647 : //
648 1000 : struct tm year(t);
649 1000 : year.tm_year += 100;
650 1000 : CATCH_REQUIRE(snapdev::is_canonical_tm(year));
651 :
652 : // tweak wday, no effect
653 : //
654 1000 : struct tm wday(t);
655 1000 : wday.tm_wday += 100;
656 1000 : CATCH_REQUIRE(snapdev::is_canonical_tm(wday));
657 :
658 : // tweak yday, no effect
659 : //
660 1000 : struct tm yday(t);
661 1000 : yday.tm_yday += 100;
662 1000 : CATCH_REQUIRE(snapdev::is_canonical_tm(yday));
663 : }
664 : }
665 2 : CATCH_END_SECTION()
666 :
667 2 : CATCH_START_SECTION("timespec_ex_tm: compare tm")
668 : {
669 1001 : for(int count(0); count < 1'000; ++count)
670 : {
671 1000 : time_t const a(snapdev::random(-1'000'000LL, 2'000'000'000LL));
672 1000 : time_t const b(snapdev::random(-1'000'000LL, 2'000'000'000LL));
673 :
674 : // canonical values
675 : //
676 1000 : struct tm ta = {};
677 1000 : struct tm tb = {};
678 :
679 1000 : gmtime_r(&a, &ta);
680 1000 : gmtime_r(&b, &tb);
681 :
682 : // tweak second
683 : //
684 1000 : struct tm ta_sec(ta);
685 1000 : ta_sec.tm_sec += 100;
686 1000 : struct tm tb_sec(tb);
687 1000 : tb_sec.tm_sec += 100;
688 :
689 : // tweak minute
690 : //
691 1000 : struct tm ta_min(ta);
692 1000 : ta_min.tm_min += 100;
693 1000 : struct tm tb_min(tb);
694 1000 : tb_min.tm_min += 100;
695 :
696 : // tweak hour
697 : //
698 1000 : struct tm ta_hour(ta);
699 1000 : ta_hour.tm_hour += 100;
700 1000 : struct tm tb_hour(tb);
701 1000 : tb_hour.tm_hour += 100;
702 :
703 : // tweak mday
704 : //
705 1000 : struct tm ta_mday(ta);
706 1000 : ta_mday.tm_mday += 100;
707 1000 : struct tm tb_mday(tb);
708 1000 : tb_mday.tm_mday += 100;
709 :
710 : // tweak month
711 : //
712 1000 : struct tm ta_mon(ta);
713 1000 : ta_mon.tm_mon += 100;
714 1000 : struct tm tb_mon(tb);
715 1000 : tb_mon.tm_mon += 100;
716 :
717 1000 : if(a < b)
718 : {
719 496 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb) == -1);
720 496 : CATCH_REQUIRE(snapdev::compare_tm(ta_sec, tb_sec) == -1);
721 496 : CATCH_REQUIRE(snapdev::compare_tm(ta_min, tb_min) == -1);
722 496 : CATCH_REQUIRE(snapdev::compare_tm(ta_hour, tb_hour) == -1);
723 496 : CATCH_REQUIRE(snapdev::compare_tm(ta_mday, tb_mday) == -1);
724 496 : CATCH_REQUIRE(snapdev::compare_tm(ta_mon, tb_mon) == -1);
725 :
726 496 : CATCH_REQUIRE(ta < tb);
727 496 : CATCH_REQUIRE(ta <= tb);
728 496 : CATCH_REQUIRE_FALSE(ta > tb);
729 496 : CATCH_REQUIRE_FALSE(ta >= tb);
730 496 : CATCH_REQUIRE_FALSE(ta == tb);
731 496 : CATCH_REQUIRE(ta != tb);
732 : }
733 504 : else if(a > b)
734 : {
735 504 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb) == 1);
736 504 : CATCH_REQUIRE(snapdev::compare_tm(ta_sec, tb_sec) == 1);
737 504 : CATCH_REQUIRE(snapdev::compare_tm(ta_min, tb_min) == 1);
738 504 : CATCH_REQUIRE(snapdev::compare_tm(ta_hour, tb_hour) == 1);
739 504 : CATCH_REQUIRE(snapdev::compare_tm(ta_mday, tb_mday) == 1);
740 504 : CATCH_REQUIRE(snapdev::compare_tm(ta_mon, tb_mon) == 1);
741 :
742 504 : CATCH_REQUIRE_FALSE(ta < tb);
743 504 : CATCH_REQUIRE_FALSE(ta <= tb);
744 504 : CATCH_REQUIRE(ta > tb);
745 504 : CATCH_REQUIRE(ta >= tb);
746 504 : CATCH_REQUIRE_FALSE(ta == tb);
747 504 : CATCH_REQUIRE(ta != tb);
748 : }
749 : // else -- we handle equality below anyway...
750 :
751 : // verify equality
752 : //
753 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta, ta) == 0);
754 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_sec, ta_sec) == 0);
755 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_min, ta_min) == 0);
756 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_hour, ta_hour) == 0);
757 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_mday, ta_mday) == 0);
758 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_mon, ta_mon) == 0);
759 :
760 1000 : CATCH_REQUIRE_FALSE(ta < ta);
761 1000 : CATCH_REQUIRE(ta <= ta);
762 1000 : CATCH_REQUIRE_FALSE(ta > ta);
763 1000 : CATCH_REQUIRE(ta >= ta);
764 1000 : CATCH_REQUIRE(ta == ta);
765 1000 : CATCH_REQUIRE_FALSE(ta != ta);
766 :
767 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb, tb) == 0);
768 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_sec, tb_sec) == 0);
769 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_min, tb_min) == 0);
770 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_hour, tb_hour) == 0);
771 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_mday, tb_mday) == 0);
772 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_mon, tb_mon) == 0);
773 :
774 1000 : CATCH_REQUIRE_FALSE(tb < tb);
775 1000 : CATCH_REQUIRE(tb <= tb);
776 1000 : CATCH_REQUIRE_FALSE(tb > tb);
777 1000 : CATCH_REQUIRE(tb >= tb);
778 1000 : CATCH_REQUIRE(tb == tb);
779 1000 : CATCH_REQUIRE_FALSE(tb != tb);
780 :
781 : // to get full coverage, we need to also make sure the
782 : // seconds, minutes, hours, etc. are equal on both sides
783 : //
784 : {
785 1000 : tm tb_same(tb);
786 :
787 1000 : auto compare = [a, ta, &tb_same]()
788 : {
789 6000 : tm cb(tb_same);
790 6000 : time_t const b_same(timegm(&cb));
791 6000 : if(a < b_same)
792 : {
793 2471 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb_same, false) == -1);
794 :
795 2471 : CATCH_REQUIRE(ta < tb_same);
796 2471 : CATCH_REQUIRE(a < tb_same);
797 2471 : CATCH_REQUIRE(ta < b_same);
798 2471 : CATCH_REQUIRE(snapdev::timespec_ex(ta) < tb_same);
799 2471 : CATCH_REQUIRE(ta < snapdev::timespec_ex(tb_same));
800 :
801 2471 : CATCH_REQUIRE(ta <= tb_same);
802 2471 : CATCH_REQUIRE(a <= tb_same);
803 2471 : CATCH_REQUIRE(ta <= b_same);
804 2471 : CATCH_REQUIRE(snapdev::timespec_ex(ta) <= tb_same);
805 2471 : CATCH_REQUIRE(ta <= snapdev::timespec_ex(tb_same));
806 :
807 2471 : CATCH_REQUIRE_FALSE(ta > tb_same);
808 2471 : CATCH_REQUIRE_FALSE(a > tb_same);
809 2471 : CATCH_REQUIRE_FALSE(ta > b_same);
810 2471 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) > tb_same);
811 2471 : CATCH_REQUIRE_FALSE(ta > snapdev::timespec_ex(tb_same));
812 :
813 2471 : CATCH_REQUIRE_FALSE(ta >= tb_same);
814 2471 : CATCH_REQUIRE_FALSE(a >= tb_same);
815 2471 : CATCH_REQUIRE_FALSE(ta >= b_same);
816 2471 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) >= tb_same);
817 2471 : CATCH_REQUIRE_FALSE(ta >= snapdev::timespec_ex(tb_same));
818 :
819 2471 : CATCH_REQUIRE_FALSE(ta == tb_same);
820 2471 : CATCH_REQUIRE_FALSE(a == tb_same);
821 2471 : CATCH_REQUIRE_FALSE(ta == b_same);
822 2471 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) == tb_same);
823 2471 : CATCH_REQUIRE_FALSE(ta == snapdev::timespec_ex(tb_same));
824 :
825 2471 : CATCH_REQUIRE(ta != tb_same);
826 2471 : CATCH_REQUIRE(a != tb_same);
827 2471 : CATCH_REQUIRE(ta != b_same);
828 2471 : CATCH_REQUIRE(snapdev::timespec_ex(ta) != tb_same);
829 2471 : CATCH_REQUIRE(ta != snapdev::timespec_ex(tb_same));
830 : }
831 3529 : else if(a > b_same)
832 : {
833 2515 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb_same, false) == 1);
834 :
835 2515 : CATCH_REQUIRE_FALSE(ta < tb_same);
836 2515 : CATCH_REQUIRE_FALSE(a < tb_same);
837 2515 : CATCH_REQUIRE_FALSE(ta < b_same);
838 2515 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) < tb_same);
839 2515 : CATCH_REQUIRE_FALSE(ta < snapdev::timespec_ex(tb_same));
840 :
841 2515 : CATCH_REQUIRE_FALSE(ta <= tb_same);
842 2515 : CATCH_REQUIRE_FALSE(a <= tb_same);
843 2515 : CATCH_REQUIRE_FALSE(ta <= b_same);
844 2515 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) <= tb_same);
845 2515 : CATCH_REQUIRE_FALSE(ta <= snapdev::timespec_ex(tb_same));
846 :
847 2515 : CATCH_REQUIRE(ta > tb_same);
848 2515 : CATCH_REQUIRE(a > tb_same);
849 2515 : CATCH_REQUIRE(ta > b_same);
850 2515 : CATCH_REQUIRE(snapdev::timespec_ex(ta) > tb_same);
851 2515 : CATCH_REQUIRE(ta > snapdev::timespec_ex(tb_same));
852 :
853 2515 : CATCH_REQUIRE(ta >= tb_same);
854 2515 : CATCH_REQUIRE(a >= tb_same);
855 2515 : CATCH_REQUIRE(ta >= b_same);
856 2515 : CATCH_REQUIRE(snapdev::timespec_ex(ta) >= tb_same);
857 2515 : CATCH_REQUIRE(ta >= snapdev::timespec_ex(tb_same));
858 :
859 2515 : CATCH_REQUIRE_FALSE(ta == tb_same);
860 2515 : CATCH_REQUIRE_FALSE(a == tb_same);
861 2515 : CATCH_REQUIRE_FALSE(ta == b_same);
862 2515 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) == tb_same);
863 2515 : CATCH_REQUIRE_FALSE(ta == snapdev::timespec_ex(tb_same));
864 :
865 2515 : CATCH_REQUIRE(ta != tb_same);
866 2515 : CATCH_REQUIRE(a != tb_same);
867 2515 : CATCH_REQUIRE(ta != b_same);
868 2515 : CATCH_REQUIRE(snapdev::timespec_ex(ta) != tb_same);
869 2515 : CATCH_REQUIRE(ta != snapdev::timespec_ex(tb_same));
870 : }
871 : else
872 : {
873 1014 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb_same, false) == 0);
874 :
875 1014 : CATCH_REQUIRE_FALSE(ta < tb_same);
876 1014 : CATCH_REQUIRE_FALSE(a < tb_same);
877 1014 : CATCH_REQUIRE_FALSE(ta < b_same);
878 1014 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) < tb_same);
879 1014 : CATCH_REQUIRE_FALSE(ta < snapdev::timespec_ex(tb_same));
880 :
881 1014 : CATCH_REQUIRE(ta <= tb_same);
882 1014 : CATCH_REQUIRE(a <= tb_same);
883 1014 : CATCH_REQUIRE(ta <= b_same);
884 1014 : CATCH_REQUIRE(snapdev::timespec_ex(ta) <= tb_same);
885 1014 : CATCH_REQUIRE(ta <= snapdev::timespec_ex(tb_same));
886 :
887 1014 : CATCH_REQUIRE_FALSE(ta > tb_same);
888 1014 : CATCH_REQUIRE_FALSE(a > tb_same);
889 1014 : CATCH_REQUIRE_FALSE(ta > b_same);
890 1014 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) > tb_same);
891 1014 : CATCH_REQUIRE_FALSE(ta > snapdev::timespec_ex(tb_same));
892 :
893 1014 : CATCH_REQUIRE(ta >= tb_same);
894 1014 : CATCH_REQUIRE(a >= tb_same);
895 1014 : CATCH_REQUIRE(ta >= b_same);
896 1014 : CATCH_REQUIRE(snapdev::timespec_ex(ta) >= tb_same);
897 1014 : CATCH_REQUIRE(ta >= snapdev::timespec_ex(tb_same));
898 :
899 1014 : CATCH_REQUIRE(ta == tb_same);
900 1014 : CATCH_REQUIRE(a == tb_same);
901 1014 : CATCH_REQUIRE(ta == b_same);
902 1014 : CATCH_REQUIRE(snapdev::timespec_ex(ta) == tb_same);
903 1014 : CATCH_REQUIRE(ta == snapdev::timespec_ex(tb_same));
904 :
905 1014 : CATCH_REQUIRE_FALSE(ta != tb_same);
906 1014 : CATCH_REQUIRE_FALSE(a != tb_same);
907 1014 : CATCH_REQUIRE_FALSE(ta != b_same);
908 1014 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) != tb_same);
909 1014 : CATCH_REQUIRE_FALSE(ta != snapdev::timespec_ex(tb_same));
910 : }
911 6000 : };
912 :
913 1000 : tb_same.tm_sec = ta.tm_sec;
914 1000 : compare();
915 1000 : tb_same.tm_min = ta.tm_min;
916 1000 : compare();
917 1000 : tb_same.tm_hour = ta.tm_hour;
918 1000 : compare();
919 1000 : tb_same.tm_mday = ta.tm_mday;
920 1000 : compare();
921 1000 : tb_same.tm_mon = ta.tm_mon;
922 1000 : compare();
923 1000 : tb_same.tm_year = ta.tm_year;
924 1000 : compare();
925 : }
926 :
927 : // same with the largest value equal first
928 : //
929 : // note that we have to make sure mday is not too large because
930 : // here we first change the month, then mday so it could go over
931 : // (as far as canonicalization is concerned and its important
932 : // to make sure the test is a full coverage test)
933 : {
934 1000 : tm ta_same(ta);
935 1000 : tm tb_same(tb);
936 :
937 1000 : if(ta_same.tm_mday > 28 || tb_same.tm_mday > 28)
938 : {
939 171 : ta_same.tm_mday = 15;
940 171 : tb_same.tm_mday = 15;
941 : }
942 :
943 1000 : time_t const a_same(timegm(&ta_same));
944 :
945 1000 : auto compare = [a_same, ta_same, &tb_same]()
946 : {
947 6000 : CATCH_REQUIRE(snapdev::is_canonical_tm(ta_same));
948 6000 : CATCH_REQUIRE(snapdev::is_canonical_tm(tb_same));
949 :
950 6000 : tm cb(tb_same);
951 6000 : time_t const b_same(timegm(&cb));
952 :
953 6000 : if(a_same < b_same)
954 : {
955 2544 : CATCH_REQUIRE(snapdev::compare_tm(ta_same, tb_same, false) == -1);
956 :
957 2544 : CATCH_REQUIRE(ta_same < tb_same);
958 2544 : CATCH_REQUIRE(ta_same <= tb_same);
959 2544 : CATCH_REQUIRE_FALSE(ta_same > tb_same);
960 2544 : CATCH_REQUIRE_FALSE(ta_same >= tb_same);
961 2544 : CATCH_REQUIRE_FALSE(ta_same == tb_same);
962 2544 : CATCH_REQUIRE(ta_same != tb_same);
963 : }
964 3456 : else if(a_same > b_same)
965 : {
966 2433 : CATCH_REQUIRE(snapdev::compare_tm(ta_same, tb_same, false) == 1);
967 :
968 2433 : CATCH_REQUIRE_FALSE(ta_same < tb_same);
969 2433 : CATCH_REQUIRE_FALSE(ta_same <= tb_same);
970 2433 : CATCH_REQUIRE(ta_same > tb_same);
971 2433 : CATCH_REQUIRE(ta_same >= tb_same);
972 2433 : CATCH_REQUIRE_FALSE(ta_same == tb_same);
973 2433 : CATCH_REQUIRE(ta_same != tb_same);
974 : }
975 : else
976 : {
977 1023 : CATCH_REQUIRE(snapdev::compare_tm(ta_same, tb_same, false) == 0);
978 :
979 1023 : CATCH_REQUIRE_FALSE(ta_same < tb_same);
980 1023 : CATCH_REQUIRE(ta_same <= tb_same);
981 1023 : CATCH_REQUIRE_FALSE(ta_same > tb_same);
982 1023 : CATCH_REQUIRE(ta_same >= tb_same);
983 1023 : CATCH_REQUIRE(ta_same == tb_same);
984 1023 : CATCH_REQUIRE_FALSE(ta_same != tb_same);
985 : }
986 6000 : };
987 :
988 1000 : tb_same.tm_year = ta_same.tm_year;
989 1000 : compare();
990 1000 : tb_same.tm_mon = ta_same.tm_mon;
991 1000 : compare();
992 1000 : tb_same.tm_mday = ta_same.tm_mday;
993 1000 : compare();
994 1000 : tb_same.tm_hour = ta_same.tm_hour;
995 1000 : compare();
996 1000 : tb_same.tm_min = ta_same.tm_min;
997 1000 : compare();
998 1000 : tb_same.tm_sec = ta_same.tm_sec;
999 1000 : compare();
1000 : }
1001 :
1002 : }
1003 : }
1004 2 : CATCH_END_SECTION()
1005 2 : }
1006 :
1007 :
1008 7 : CATCH_TEST_CASE("timespec_ex_string", "[time][string]")
1009 : {
1010 7 : CATCH_START_SECTION("timespec_ex_string: ostream")
1011 : {
1012 : // 4511.913788345
1013 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1014 1 : snapdev::timespec_ex b;
1015 :
1016 1 : std::stringstream ss;
1017 1 : ss << a;
1018 :
1019 1 : CATCH_REQUIRE(ss.str() == "4511.913788345");
1020 1 : CATCH_REQUIRE(a.to_timestamp() == "4511.913788345");
1021 1 : CATCH_REQUIRE(a.to_timestamp(true) == "4511.913788345");
1022 :
1023 1 : b.set(ss.str());
1024 1 : CATCH_REQUIRE(a == b);
1025 :
1026 3 : b = "4511.913788345144763"; // ignore digits after 9 decimals
1027 1 : CATCH_REQUIRE(a == b);
1028 :
1029 3 : b = "4511.91378834598771"; // try again with an odd number of digits
1030 1 : CATCH_REQUIRE(a == b);
1031 :
1032 : // 83207.000000000
1033 1 : ss.str(std::string());
1034 1 : a.tv_sec = 83207L;
1035 1 : a.tv_nsec = 0;
1036 1 : ss << a;
1037 :
1038 1 : CATCH_REQUIRE(ss.str() == "83207");
1039 1 : CATCH_REQUIRE(a.to_timestamp() == "83207.000000000");
1040 1 : CATCH_REQUIRE(a.to_timestamp(true) == "83207");
1041 :
1042 1 : b.set(ss.str());
1043 1 : CATCH_REQUIRE(a == b);
1044 3 : b.set(" 83207.000000000 ");
1045 1 : CATCH_REQUIRE(a == b);
1046 3 : b.set(" 83207.0 ");
1047 1 : CATCH_REQUIRE(a == b);
1048 3 : b.set(" 83207. ");
1049 1 : CATCH_REQUIRE(a == b);
1050 3 : b.set(" 83207 ");
1051 1 : CATCH_REQUIRE(a == b);
1052 3 : b.set(" +83207s ");
1053 1 : CATCH_REQUIRE(a == b);
1054 3 : b.set(" 83207.s ");
1055 1 : CATCH_REQUIRE(a == b);
1056 3 : b.set(" 83207.0s ");
1057 1 : CATCH_REQUIRE(a == b);
1058 :
1059 3 : snapdev::timespec_ex c("+83207.0s");
1060 1 : CATCH_REQUIRE(a == c);
1061 :
1062 : // 0.000000101
1063 1 : ss.str(std::string());
1064 1 : a.tv_sec = 0L;
1065 1 : a.tv_nsec = 101;
1066 1 : ss << a;
1067 :
1068 1 : CATCH_REQUIRE(ss.str() == "0.000000101");
1069 1 : CATCH_REQUIRE(a.to_timestamp() == "0.000000101");
1070 1 : CATCH_REQUIRE(a.to_timestamp(true) == "0.000000101");
1071 :
1072 1 : b.set(ss.str());
1073 1 : CATCH_REQUIRE(a == b);
1074 :
1075 : // 1000000000.781200000
1076 1 : ss.str(std::string());
1077 1 : a.tv_sec = 1000000000L;
1078 1 : a.tv_nsec = 781200000;
1079 1 : ss << snapdev::setremovetrailingzeroes(false) << a;
1080 :
1081 1 : CATCH_REQUIRE(ss.str() == "1000000000.781200000");
1082 1 : CATCH_REQUIRE(a.to_timestamp() == "1000000000.781200000");
1083 1 : CATCH_REQUIRE(a.to_timestamp(true) == "1000000000.7812");
1084 :
1085 1 : b.set(ss.str());
1086 1 : CATCH_REQUIRE(a == b);
1087 :
1088 : // -259.900000000
1089 1 : ss.str(std::string());
1090 1 : a.tv_sec = -259L;
1091 1 : a.tv_nsec = 900000000;
1092 1 : ss << a;
1093 :
1094 1 : CATCH_REQUIRE(ss.str() == "-259.900000000");
1095 1 : CATCH_REQUIRE(a.to_timestamp() == "-259.900000000");
1096 1 : CATCH_REQUIRE(a.to_timestamp(true) == "-259.9");
1097 :
1098 1 : b.set(ss.str());
1099 1 : CATCH_REQUIRE(a == b);
1100 3 : b.set(" -259.900000000 ");
1101 1 : CATCH_REQUIRE(a == b);
1102 1 : }
1103 7 : CATCH_END_SECTION()
1104 :
1105 7 : CATCH_START_SECTION("timespec_ex_string: convert to string")
1106 : {
1107 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1108 :
1109 : // struct tm date_and_time = {};
1110 : // localtime_r(&a.tv_sec, &date_and_time);
1111 : //std::cerr << "a.tv_sec = " << a.tv_sec << " but localtime.tm_sec = " << date_and_time.tm_sec;
1112 : // gmtime_r(&a.tv_sec, &date_and_time);
1113 : //std::cerr << " and gmtime.tm_sec = " << date_and_time.tm_sec << "\n";
1114 :
1115 : // for these tests, we change the timezone to UTC so localtime_r()
1116 : // and gmtime_r() both return the same thing
1117 : //
1118 3 : std::string out(a.to_string("%s.%N", true));
1119 1 : CATCH_REQUIRE(out == "4511.913788345");
1120 :
1121 3 : out = a.to_string("%s.%N", false);
1122 1 : CATCH_REQUIRE(out == "4511.913788345");
1123 :
1124 1 : out = a.to_string();
1125 : //std::cerr << "seconds misplaced in: " << out << "?\n";
1126 1 : CATCH_REQUIRE(out.find("11.913788345") != std::string::npos);
1127 :
1128 1 : a.tv_nsec = 913'000'000;
1129 3 : out = a.to_string("%s.%N");
1130 1 : CATCH_REQUIRE(out == "4511.913000000");
1131 3 : out = a.to_string("%s.%EN");
1132 1 : CATCH_REQUIRE(out == "4511.913");
1133 :
1134 1 : a.tv_nsec = 0;
1135 3 : out = a.to_string("%s.%N");
1136 1 : CATCH_REQUIRE(out == "4511.000000000");
1137 3 : out = a.to_string("%s.%EN");
1138 1 : CATCH_REQUIRE(out == "4511.0");
1139 1 : }
1140 7 : CATCH_END_SECTION()
1141 :
1142 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"\".")
1143 : {
1144 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1145 :
1146 1 : time_t date(4511L);
1147 1 : struct tm t = *gmtime(&date);
1148 1 : char expected[256];
1149 1 : strftime(expected, sizeof(expected), "%a %b %e %H:%M:%S.913788345 %Y", &t);
1150 :
1151 1 : g_state = 0;
1152 1 : g_error = 0;
1153 1 : std::string out(a.to_string<wrap_nl_langinfo>());
1154 1 : CATCH_REQUIRE(g_error == 0);
1155 1 : CATCH_REQUIRE(out == expected);
1156 :
1157 1 : }
1158 7 : CATCH_END_SECTION()
1159 :
1160 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"%T\".")
1161 : {
1162 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1163 :
1164 1 : time_t date(4511L);
1165 1 : struct tm t = *gmtime(&date);
1166 1 : char expected[256];
1167 1 : strftime(expected, sizeof(expected), "%T.913788345", &t);
1168 :
1169 1 : g_state = 10;
1170 1 : g_error = 0;
1171 1 : std::string out(a.to_string<wrap_nl_langinfo>());
1172 1 : CATCH_REQUIRE(g_error == 0);
1173 1 : CATCH_REQUIRE(out == expected);
1174 :
1175 1 : }
1176 7 : CATCH_END_SECTION()
1177 :
1178 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"%r %X %EX\".")
1179 : {
1180 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1181 :
1182 1 : time_t date(4511L);
1183 1 : struct tm t = *gmtime(&date);
1184 1 : char expected[256];
1185 1 : strftime(
1186 : expected
1187 : , sizeof(expected)
1188 : , "%I:%M:%S.913788345 %p" // %r
1189 : " %H:%M:%S.913788345" // %X
1190 : " %H.%M.%S.913788345" // %EX
1191 : , &t);
1192 :
1193 1 : g_state = 20;
1194 1 : g_error = 0;
1195 1 : std::string out(a.to_string<wrap_nl_langinfo>());
1196 1 : CATCH_REQUIRE(g_error == 0);
1197 1 : CATCH_REQUIRE(out == expected);
1198 1 : }
1199 7 : CATCH_END_SECTION()
1200 :
1201 7 : CATCH_START_SECTION("timespec_ex_string: to and from string.")
1202 : {
1203 1 : snapdev::timespec_ex a(timespec{ rand(), rand() % 1'000'000'000 });
1204 1 : snapdev::timespec_ex b;
1205 :
1206 3 : std::string const format("%D %T");
1207 1 : std::string const s(a.to_string(format));
1208 1 : b.from_string(s, format);
1209 :
1210 : // we do not have support for %N just yet in the "from_string()"
1211 : // so here we instead just test the seconds
1212 : //
1213 1 : int const diff(labs(a.tv_sec - b.tv_sec));
1214 1 : bool const result(diff == 0 || diff == 3600);
1215 1 : CATCH_REQUIRE(result); // this is not correct, many countries are "off" the timezone by 30 or 15 min.
1216 1 : }
1217 7 : CATCH_END_SECTION()
1218 :
1219 7 : CATCH_START_SECTION("timespec_ex_string: to and from string with %N.")
1220 : {
1221 1 : snapdev::timespec_ex a(timespec{ rand(), rand() % 1'000'000'000 });
1222 1 : snapdev::timespec_ex b;
1223 :
1224 3 : std::string format("%D %T.%N");
1225 1 : std::string s(a.to_string(format));
1226 : //b.from_string(s, format);
1227 3 : CATCH_REQUIRE_THROWS_MATCHES(
1228 : b.from_string(s, format)
1229 : , libexcept::fixme
1230 : , Catch::Matchers::ExceptionMessage(
1231 : "fixme: the from_string() %N extension is not yet implemented."));
1232 :
1233 : // once it works:
1234 : //
1235 : //CATCH_REQUIRE(a == b);
1236 1 : }
1237 7 : CATCH_END_SECTION()
1238 7 : }
1239 :
1240 :
1241 5 : CATCH_TEST_CASE("timespec_ex_from_string_error", "[time][string][error]")
1242 : {
1243 5 : CATCH_START_SECTION("timespec_ex_from_string_error: string does not start with a sign or digit")
1244 : {
1245 8 : CATCH_REQUIRE_THROWS_MATCHES(
1246 : snapdev::timespec_ex("@34.506")
1247 : , snapdev::syntax_error
1248 : , Catch::Matchers::ExceptionMessage(
1249 : "timespec_ex_exception: number of seconds must include at least one digit, even if '0'."));
1250 : }
1251 5 : CATCH_END_SECTION()
1252 :
1253 5 : CATCH_START_SECTION("timespec_ex_from_string_error: seconds overflow")
1254 : {
1255 8 : CATCH_REQUIRE_THROWS_MATCHES(
1256 : snapdev::timespec_ex("-9223372036854775808.506")
1257 : , snapdev::overflow
1258 : , Catch::Matchers::ExceptionMessage(
1259 : "timespec_ex_exception: number of seconds is too large."));
1260 : }
1261 5 : CATCH_END_SECTION()
1262 :
1263 5 : CATCH_START_SECTION("timespec_ex_from_string_error: bad unit")
1264 : {
1265 8 : CATCH_REQUIRE_THROWS_MATCHES(
1266 : snapdev::timespec_ex("-2036854775808.506sec")
1267 : , snapdev::syntax_error
1268 : , Catch::Matchers::ExceptionMessage(
1269 : "timespec_ex_exception: number include unexpected characters (ec)."));
1270 : }
1271 5 : CATCH_END_SECTION()
1272 :
1273 5 : CATCH_START_SECTION("timespec_ex_from_string_error: bad unit")
1274 : {
1275 1 : snapdev::timespec_ex t;
1276 1 : t.tv_sec = 34471;
1277 1 : t.tv_nsec = 1000000000;
1278 8 : CATCH_REQUIRE_THROWS_MATCHES(
1279 : t.to_string("%s.%N")
1280 : , snapdev::overflow
1281 : , Catch::Matchers::ExceptionMessage(
1282 : "timespec_ex_exception: tv_nsec is 1 billion or more, which is invalid."));
1283 : }
1284 5 : CATCH_END_SECTION()
1285 :
1286 5 : CATCH_START_SECTION("timespec_ex_from_string_error: output too long")
1287 : {
1288 1 : snapdev::timespec_ex t;
1289 1 : t.tv_sec = rand();
1290 1 : t.tv_nsec = rand() % 1000000000;
1291 1 : std::string const format(
1292 : "If we use the format string as a string too, then we can end up with a string that's just way way way too long."
1293 : " Our current limit is 256 characters so that limits our message. The truth is that you limit yourself"
1294 : " to just a date and time string rather than a whole message in this format string."
1295 : " It's probably easier to handle too... The date is: %D. The time is: %T."
1296 3 : " And we also have %F, %c, %r, %X, %EX for the alternative format, etc.");
1297 2 : CATCH_REQUIRE_THROWS_MATCHES(
1298 : t.to_string(format)
1299 : , snapdev::overflow
1300 : , Catch::Matchers::ExceptionMessage(
1301 : "timespec_ex_exception: the specified strftime() format \""
1302 : + format
1303 : + "\" failed."));
1304 1 : }
1305 5 : CATCH_END_SECTION()
1306 5 : }
1307 :
1308 :
1309 :
1310 : // vim: ts=4 sw=4 et
|