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 effects if not February
647 : //
648 1000 : if(t.tm_mon != 1)
649 : {
650 937 : struct tm year(t);
651 937 : year.tm_year += 100;
652 937 : CATCH_REQUIRE(snapdev::is_canonical_tm(year));
653 : }
654 :
655 : // tweak wday, no effect
656 : //
657 1000 : struct tm wday(t);
658 1000 : wday.tm_wday += 100;
659 1000 : CATCH_REQUIRE(snapdev::is_canonical_tm(wday));
660 :
661 : // tweak yday, no effect
662 : //
663 1000 : struct tm yday(t);
664 1000 : yday.tm_yday += 100;
665 1000 : CATCH_REQUIRE(snapdev::is_canonical_tm(yday));
666 : }
667 : }
668 2 : CATCH_END_SECTION()
669 :
670 2 : CATCH_START_SECTION("timespec_ex_tm: compare tm")
671 : {
672 1001 : for(int count(0); count < 1'000; ++count)
673 : {
674 1000 : time_t const a(snapdev::random(-1'000'000LL, 2'000'000'000LL));
675 1000 : time_t const b(snapdev::random(-1'000'000LL, 2'000'000'000LL));
676 :
677 : // canonical values
678 : //
679 1000 : struct tm ta = {};
680 1000 : struct tm tb = {};
681 :
682 1000 : gmtime_r(&a, &ta);
683 1000 : gmtime_r(&b, &tb);
684 :
685 : // tweak second
686 : //
687 1000 : struct tm ta_sec(ta);
688 1000 : ta_sec.tm_sec += 100;
689 1000 : struct tm tb_sec(tb);
690 1000 : tb_sec.tm_sec += 100;
691 :
692 : // tweak minute
693 : //
694 1000 : struct tm ta_min(ta);
695 1000 : ta_min.tm_min += 100;
696 1000 : struct tm tb_min(tb);
697 1000 : tb_min.tm_min += 100;
698 :
699 : // tweak hour
700 : //
701 1000 : struct tm ta_hour(ta);
702 1000 : ta_hour.tm_hour += 100;
703 1000 : struct tm tb_hour(tb);
704 1000 : tb_hour.tm_hour += 100;
705 :
706 : // tweak mday
707 : //
708 1000 : struct tm ta_mday(ta);
709 1000 : ta_mday.tm_mday += 100;
710 1000 : struct tm tb_mday(tb);
711 1000 : tb_mday.tm_mday += 100;
712 :
713 : // tweak month
714 : //
715 1000 : struct tm ta_mon(ta);
716 1000 : ta_mon.tm_mon += 100;
717 1000 : struct tm tb_mon(tb);
718 1000 : tb_mon.tm_mon += 100;
719 :
720 1000 : if(a < b)
721 : {
722 517 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb) == -1);
723 517 : CATCH_REQUIRE(snapdev::compare_tm(ta_sec, tb_sec) == -1);
724 517 : CATCH_REQUIRE(snapdev::compare_tm(ta_min, tb_min) == -1);
725 517 : CATCH_REQUIRE(snapdev::compare_tm(ta_hour, tb_hour) == -1);
726 517 : CATCH_REQUIRE(snapdev::compare_tm(ta_mday, tb_mday) == -1);
727 517 : CATCH_REQUIRE(snapdev::compare_tm(ta_mon, tb_mon) == -1);
728 :
729 517 : CATCH_REQUIRE(ta < tb);
730 517 : CATCH_REQUIRE(ta <= tb);
731 517 : CATCH_REQUIRE_FALSE(ta > tb);
732 517 : CATCH_REQUIRE_FALSE(ta >= tb);
733 517 : CATCH_REQUIRE_FALSE(ta == tb);
734 517 : CATCH_REQUIRE(ta != tb);
735 : }
736 483 : else if(a > b)
737 : {
738 483 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb) == 1);
739 483 : CATCH_REQUIRE(snapdev::compare_tm(ta_sec, tb_sec) == 1);
740 483 : CATCH_REQUIRE(snapdev::compare_tm(ta_min, tb_min) == 1);
741 483 : CATCH_REQUIRE(snapdev::compare_tm(ta_hour, tb_hour) == 1);
742 483 : CATCH_REQUIRE(snapdev::compare_tm(ta_mday, tb_mday) == 1);
743 483 : CATCH_REQUIRE(snapdev::compare_tm(ta_mon, tb_mon) == 1);
744 :
745 483 : CATCH_REQUIRE_FALSE(ta < tb);
746 483 : CATCH_REQUIRE_FALSE(ta <= tb);
747 483 : CATCH_REQUIRE(ta > tb);
748 483 : CATCH_REQUIRE(ta >= tb);
749 483 : CATCH_REQUIRE_FALSE(ta == tb);
750 483 : CATCH_REQUIRE(ta != tb);
751 : }
752 : // else -- we handle equality below anyway...
753 :
754 : // verify equality
755 : //
756 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta, ta) == 0);
757 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_sec, ta_sec) == 0);
758 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_min, ta_min) == 0);
759 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_hour, ta_hour) == 0);
760 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_mday, ta_mday) == 0);
761 1000 : CATCH_REQUIRE(snapdev::compare_tm(ta_mon, ta_mon) == 0);
762 :
763 1000 : CATCH_REQUIRE_FALSE(ta < ta);
764 1000 : CATCH_REQUIRE(ta <= ta);
765 1000 : CATCH_REQUIRE_FALSE(ta > ta);
766 1000 : CATCH_REQUIRE(ta >= ta);
767 1000 : CATCH_REQUIRE(ta == ta);
768 1000 : CATCH_REQUIRE_FALSE(ta != ta);
769 :
770 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb, tb) == 0);
771 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_sec, tb_sec) == 0);
772 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_min, tb_min) == 0);
773 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_hour, tb_hour) == 0);
774 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_mday, tb_mday) == 0);
775 1000 : CATCH_REQUIRE(snapdev::compare_tm(tb_mon, tb_mon) == 0);
776 :
777 1000 : CATCH_REQUIRE_FALSE(tb < tb);
778 1000 : CATCH_REQUIRE(tb <= tb);
779 1000 : CATCH_REQUIRE_FALSE(tb > tb);
780 1000 : CATCH_REQUIRE(tb >= tb);
781 1000 : CATCH_REQUIRE(tb == tb);
782 1000 : CATCH_REQUIRE_FALSE(tb != tb);
783 :
784 : // to get full coverage, we need to also make sure the
785 : // seconds, minutes, hours, etc. are equal on both sides
786 : //
787 : {
788 1000 : tm tb_same(tb);
789 :
790 1000 : auto compare = [a, ta, &tb_same]()
791 : {
792 6000 : tm cb(tb_same);
793 6000 : time_t const b_same(timegm(&cb));
794 6000 : if(a < b_same)
795 : {
796 2579 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb_same, false) == -1);
797 :
798 2579 : CATCH_REQUIRE(ta < tb_same);
799 2579 : CATCH_REQUIRE(a < tb_same);
800 2579 : CATCH_REQUIRE(ta < b_same);
801 2579 : CATCH_REQUIRE(snapdev::timespec_ex(ta) < tb_same);
802 2579 : CATCH_REQUIRE(ta < snapdev::timespec_ex(tb_same));
803 :
804 2579 : CATCH_REQUIRE(ta <= tb_same);
805 2579 : CATCH_REQUIRE(a <= tb_same);
806 2579 : CATCH_REQUIRE(ta <= b_same);
807 2579 : CATCH_REQUIRE(snapdev::timespec_ex(ta) <= tb_same);
808 2579 : CATCH_REQUIRE(ta <= snapdev::timespec_ex(tb_same));
809 :
810 2579 : CATCH_REQUIRE_FALSE(ta > tb_same);
811 2579 : CATCH_REQUIRE_FALSE(a > tb_same);
812 2579 : CATCH_REQUIRE_FALSE(ta > b_same);
813 2579 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) > tb_same);
814 2579 : CATCH_REQUIRE_FALSE(ta > snapdev::timespec_ex(tb_same));
815 :
816 2579 : CATCH_REQUIRE_FALSE(ta >= tb_same);
817 2579 : CATCH_REQUIRE_FALSE(a >= tb_same);
818 2579 : CATCH_REQUIRE_FALSE(ta >= b_same);
819 2579 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) >= tb_same);
820 2579 : CATCH_REQUIRE_FALSE(ta >= snapdev::timespec_ex(tb_same));
821 :
822 2579 : CATCH_REQUIRE_FALSE(ta == tb_same);
823 2579 : CATCH_REQUIRE_FALSE(a == tb_same);
824 2579 : CATCH_REQUIRE_FALSE(ta == b_same);
825 2579 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) == tb_same);
826 2579 : CATCH_REQUIRE_FALSE(ta == snapdev::timespec_ex(tb_same));
827 :
828 2579 : CATCH_REQUIRE(ta != tb_same);
829 2579 : CATCH_REQUIRE(a != tb_same);
830 2579 : CATCH_REQUIRE(ta != b_same);
831 2579 : CATCH_REQUIRE(snapdev::timespec_ex(ta) != tb_same);
832 2579 : CATCH_REQUIRE(ta != snapdev::timespec_ex(tb_same));
833 : }
834 3421 : else if(a > b_same)
835 : {
836 2413 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb_same, false) == 1);
837 :
838 2413 : CATCH_REQUIRE_FALSE(ta < tb_same);
839 2413 : CATCH_REQUIRE_FALSE(a < tb_same);
840 2413 : CATCH_REQUIRE_FALSE(ta < b_same);
841 2413 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) < tb_same);
842 2413 : CATCH_REQUIRE_FALSE(ta < snapdev::timespec_ex(tb_same));
843 :
844 2413 : CATCH_REQUIRE_FALSE(ta <= tb_same);
845 2413 : CATCH_REQUIRE_FALSE(a <= tb_same);
846 2413 : CATCH_REQUIRE_FALSE(ta <= b_same);
847 2413 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) <= tb_same);
848 2413 : CATCH_REQUIRE_FALSE(ta <= snapdev::timespec_ex(tb_same));
849 :
850 2413 : CATCH_REQUIRE(ta > tb_same);
851 2413 : CATCH_REQUIRE(a > tb_same);
852 2413 : CATCH_REQUIRE(ta > b_same);
853 2413 : CATCH_REQUIRE(snapdev::timespec_ex(ta) > tb_same);
854 2413 : CATCH_REQUIRE(ta > snapdev::timespec_ex(tb_same));
855 :
856 2413 : CATCH_REQUIRE(ta >= tb_same);
857 2413 : CATCH_REQUIRE(a >= tb_same);
858 2413 : CATCH_REQUIRE(ta >= b_same);
859 2413 : CATCH_REQUIRE(snapdev::timespec_ex(ta) >= tb_same);
860 2413 : CATCH_REQUIRE(ta >= snapdev::timespec_ex(tb_same));
861 :
862 2413 : CATCH_REQUIRE_FALSE(ta == tb_same);
863 2413 : CATCH_REQUIRE_FALSE(a == tb_same);
864 2413 : CATCH_REQUIRE_FALSE(ta == b_same);
865 2413 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) == tb_same);
866 2413 : CATCH_REQUIRE_FALSE(ta == snapdev::timespec_ex(tb_same));
867 :
868 2413 : CATCH_REQUIRE(ta != tb_same);
869 2413 : CATCH_REQUIRE(a != tb_same);
870 2413 : CATCH_REQUIRE(ta != b_same);
871 2413 : CATCH_REQUIRE(snapdev::timespec_ex(ta) != tb_same);
872 2413 : CATCH_REQUIRE(ta != snapdev::timespec_ex(tb_same));
873 : }
874 : else
875 : {
876 1008 : CATCH_REQUIRE(snapdev::compare_tm(ta, tb_same, false) == 0);
877 :
878 1008 : CATCH_REQUIRE_FALSE(ta < tb_same);
879 1008 : CATCH_REQUIRE_FALSE(a < tb_same);
880 1008 : CATCH_REQUIRE_FALSE(ta < b_same);
881 1008 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) < tb_same);
882 1008 : CATCH_REQUIRE_FALSE(ta < snapdev::timespec_ex(tb_same));
883 :
884 1008 : CATCH_REQUIRE(ta <= tb_same);
885 1008 : CATCH_REQUIRE(a <= tb_same);
886 1008 : CATCH_REQUIRE(ta <= b_same);
887 1008 : CATCH_REQUIRE(snapdev::timespec_ex(ta) <= tb_same);
888 1008 : CATCH_REQUIRE(ta <= snapdev::timespec_ex(tb_same));
889 :
890 1008 : CATCH_REQUIRE_FALSE(ta > tb_same);
891 1008 : CATCH_REQUIRE_FALSE(a > tb_same);
892 1008 : CATCH_REQUIRE_FALSE(ta > b_same);
893 1008 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) > tb_same);
894 1008 : CATCH_REQUIRE_FALSE(ta > snapdev::timespec_ex(tb_same));
895 :
896 1008 : CATCH_REQUIRE(ta >= tb_same);
897 1008 : CATCH_REQUIRE(a >= tb_same);
898 1008 : CATCH_REQUIRE(ta >= b_same);
899 1008 : CATCH_REQUIRE(snapdev::timespec_ex(ta) >= tb_same);
900 1008 : CATCH_REQUIRE(ta >= snapdev::timespec_ex(tb_same));
901 :
902 1008 : CATCH_REQUIRE(ta == tb_same);
903 1008 : CATCH_REQUIRE(a == tb_same);
904 1008 : CATCH_REQUIRE(ta == b_same);
905 1008 : CATCH_REQUIRE(snapdev::timespec_ex(ta) == tb_same);
906 1008 : CATCH_REQUIRE(ta == snapdev::timespec_ex(tb_same));
907 :
908 1008 : CATCH_REQUIRE_FALSE(ta != tb_same);
909 1008 : CATCH_REQUIRE_FALSE(a != tb_same);
910 1008 : CATCH_REQUIRE_FALSE(ta != b_same);
911 1008 : CATCH_REQUIRE_FALSE(snapdev::timespec_ex(ta) != tb_same);
912 1008 : CATCH_REQUIRE_FALSE(ta != snapdev::timespec_ex(tb_same));
913 : }
914 6000 : };
915 :
916 1000 : tb_same.tm_sec = ta.tm_sec;
917 1000 : compare();
918 1000 : tb_same.tm_min = ta.tm_min;
919 1000 : compare();
920 1000 : tb_same.tm_hour = ta.tm_hour;
921 1000 : compare();
922 1000 : tb_same.tm_mday = ta.tm_mday;
923 1000 : compare();
924 1000 : tb_same.tm_mon = ta.tm_mon;
925 1000 : compare();
926 1000 : tb_same.tm_year = ta.tm_year;
927 1000 : compare();
928 : }
929 :
930 : // same with the largest value equal first
931 : //
932 : // note that we have to make sure mday is not too large because
933 : // here we first change the month, then mday so it could go over
934 : // (as far as canonicalization is concerned and its important
935 : // to make sure the test is a full coverage test)
936 : {
937 1000 : tm ta_same(ta);
938 1000 : tm tb_same(tb);
939 :
940 1000 : if(ta_same.tm_mday > 28 || tb_same.tm_mday > 28)
941 : {
942 165 : ta_same.tm_mday = 15;
943 165 : tb_same.tm_mday = 15;
944 : }
945 :
946 1000 : time_t const a_same(timegm(&ta_same));
947 :
948 1000 : auto compare = [a_same, ta_same, &tb_same]()
949 : {
950 6000 : CATCH_REQUIRE(snapdev::is_canonical_tm(ta_same));
951 6000 : CATCH_REQUIRE(snapdev::is_canonical_tm(tb_same));
952 :
953 6000 : tm cb(tb_same);
954 6000 : time_t const b_same(timegm(&cb));
955 :
956 6000 : if(a_same < b_same)
957 : {
958 2523 : CATCH_REQUIRE(snapdev::compare_tm(ta_same, tb_same, false) == -1);
959 :
960 2523 : CATCH_REQUIRE(ta_same < tb_same);
961 2523 : CATCH_REQUIRE(ta_same <= tb_same);
962 2523 : CATCH_REQUIRE_FALSE(ta_same > tb_same);
963 2523 : CATCH_REQUIRE_FALSE(ta_same >= tb_same);
964 2523 : CATCH_REQUIRE_FALSE(ta_same == tb_same);
965 2523 : CATCH_REQUIRE(ta_same != tb_same);
966 : }
967 3477 : else if(a_same > b_same)
968 : {
969 2455 : CATCH_REQUIRE(snapdev::compare_tm(ta_same, tb_same, false) == 1);
970 :
971 2455 : CATCH_REQUIRE_FALSE(ta_same < tb_same);
972 2455 : CATCH_REQUIRE_FALSE(ta_same <= tb_same);
973 2455 : CATCH_REQUIRE(ta_same > tb_same);
974 2455 : CATCH_REQUIRE(ta_same >= tb_same);
975 2455 : CATCH_REQUIRE_FALSE(ta_same == tb_same);
976 2455 : CATCH_REQUIRE(ta_same != tb_same);
977 : }
978 : else
979 : {
980 1022 : CATCH_REQUIRE(snapdev::compare_tm(ta_same, tb_same, false) == 0);
981 :
982 1022 : CATCH_REQUIRE_FALSE(ta_same < tb_same);
983 1022 : CATCH_REQUIRE(ta_same <= tb_same);
984 1022 : CATCH_REQUIRE_FALSE(ta_same > tb_same);
985 1022 : CATCH_REQUIRE(ta_same >= tb_same);
986 1022 : CATCH_REQUIRE(ta_same == tb_same);
987 1022 : CATCH_REQUIRE_FALSE(ta_same != tb_same);
988 : }
989 6000 : };
990 :
991 1000 : tb_same.tm_year = ta_same.tm_year;
992 1000 : compare();
993 1000 : tb_same.tm_mon = ta_same.tm_mon;
994 1000 : compare();
995 1000 : tb_same.tm_mday = ta_same.tm_mday;
996 1000 : compare();
997 1000 : tb_same.tm_hour = ta_same.tm_hour;
998 1000 : compare();
999 1000 : tb_same.tm_min = ta_same.tm_min;
1000 1000 : compare();
1001 1000 : tb_same.tm_sec = ta_same.tm_sec;
1002 1000 : compare();
1003 : }
1004 :
1005 : }
1006 : }
1007 2 : CATCH_END_SECTION()
1008 2 : }
1009 :
1010 :
1011 7 : CATCH_TEST_CASE("timespec_ex_string", "[time][string]")
1012 : {
1013 7 : CATCH_START_SECTION("timespec_ex_string: ostream")
1014 : {
1015 : // 4511.913788345
1016 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1017 1 : snapdev::timespec_ex b;
1018 :
1019 1 : std::stringstream ss;
1020 1 : ss << a;
1021 :
1022 1 : CATCH_REQUIRE(ss.str() == "4511.913788345");
1023 1 : CATCH_REQUIRE(a.to_timestamp() == "4511.913788345");
1024 1 : CATCH_REQUIRE(a.to_timestamp(true) == "4511.913788345");
1025 :
1026 1 : b.set(ss.str());
1027 1 : CATCH_REQUIRE(a == b);
1028 :
1029 3 : b = "4511.913788345144763"; // ignore digits after 9 decimals
1030 1 : CATCH_REQUIRE(a == b);
1031 :
1032 3 : b = "4511.91378834598771"; // try again with an odd number of digits
1033 1 : CATCH_REQUIRE(a == b);
1034 :
1035 : // 83207.000000000
1036 1 : ss.str(std::string());
1037 1 : a.tv_sec = 83207L;
1038 1 : a.tv_nsec = 0;
1039 1 : ss << a;
1040 :
1041 1 : CATCH_REQUIRE(ss.str() == "83207");
1042 1 : CATCH_REQUIRE(a.to_timestamp() == "83207.000000000");
1043 1 : CATCH_REQUIRE(a.to_timestamp(true) == "83207");
1044 :
1045 1 : b.set(ss.str());
1046 1 : CATCH_REQUIRE(a == b);
1047 3 : b.set(" 83207.000000000 ");
1048 1 : CATCH_REQUIRE(a == b);
1049 3 : b.set(" 83207.0 ");
1050 1 : CATCH_REQUIRE(a == b);
1051 3 : b.set(" 83207. ");
1052 1 : CATCH_REQUIRE(a == b);
1053 3 : b.set(" 83207 ");
1054 1 : CATCH_REQUIRE(a == b);
1055 3 : b.set(" +83207s ");
1056 1 : CATCH_REQUIRE(a == b);
1057 3 : b.set(" 83207.s ");
1058 1 : CATCH_REQUIRE(a == b);
1059 3 : b.set(" 83207.0s ");
1060 1 : CATCH_REQUIRE(a == b);
1061 :
1062 3 : snapdev::timespec_ex c("+83207.0s");
1063 1 : CATCH_REQUIRE(a == c);
1064 :
1065 : // 0.000000101
1066 1 : ss.str(std::string());
1067 1 : a.tv_sec = 0L;
1068 1 : a.tv_nsec = 101;
1069 1 : ss << a;
1070 :
1071 1 : CATCH_REQUIRE(ss.str() == "0.000000101");
1072 1 : CATCH_REQUIRE(a.to_timestamp() == "0.000000101");
1073 1 : CATCH_REQUIRE(a.to_timestamp(true) == "0.000000101");
1074 :
1075 1 : b.set(ss.str());
1076 1 : CATCH_REQUIRE(a == b);
1077 :
1078 : // 1000000000.781200000
1079 1 : ss.str(std::string());
1080 1 : a.tv_sec = 1000000000L;
1081 1 : a.tv_nsec = 781200000;
1082 1 : ss << snapdev::setremovetrailingzeroes(false) << a;
1083 :
1084 1 : CATCH_REQUIRE(ss.str() == "1000000000.781200000");
1085 1 : CATCH_REQUIRE(a.to_timestamp() == "1000000000.781200000");
1086 1 : CATCH_REQUIRE(a.to_timestamp(true) == "1000000000.7812");
1087 :
1088 1 : b.set(ss.str());
1089 1 : CATCH_REQUIRE(a == b);
1090 :
1091 : // -259.900000000
1092 1 : ss.str(std::string());
1093 1 : a.tv_sec = -259L;
1094 1 : a.tv_nsec = 900000000;
1095 1 : ss << a;
1096 :
1097 1 : CATCH_REQUIRE(ss.str() == "-259.900000000");
1098 1 : CATCH_REQUIRE(a.to_timestamp() == "-259.900000000");
1099 1 : CATCH_REQUIRE(a.to_timestamp(true) == "-259.9");
1100 :
1101 1 : b.set(ss.str());
1102 1 : CATCH_REQUIRE(a == b);
1103 3 : b.set(" -259.900000000 ");
1104 1 : CATCH_REQUIRE(a == b);
1105 1 : }
1106 7 : CATCH_END_SECTION()
1107 :
1108 7 : CATCH_START_SECTION("timespec_ex_string: convert to string")
1109 : {
1110 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1111 :
1112 : // struct tm date_and_time = {};
1113 : // localtime_r(&a.tv_sec, &date_and_time);
1114 : //std::cerr << "a.tv_sec = " << a.tv_sec << " but localtime.tm_sec = " << date_and_time.tm_sec;
1115 : // gmtime_r(&a.tv_sec, &date_and_time);
1116 : //std::cerr << " and gmtime.tm_sec = " << date_and_time.tm_sec << "\n";
1117 :
1118 : // for these tests, we change the timezone to UTC so localtime_r()
1119 : // and gmtime_r() both return the same thing
1120 : //
1121 3 : std::string out(a.to_string("%s.%N", true));
1122 1 : CATCH_REQUIRE(out == "4511.913788345");
1123 :
1124 3 : out = a.to_string("%s.%N", false);
1125 1 : CATCH_REQUIRE(out == "4511.913788345");
1126 :
1127 1 : out = a.to_string();
1128 : //std::cerr << "seconds misplaced in: " << out << "?\n";
1129 1 : CATCH_REQUIRE(out.find("11.913788345") != std::string::npos);
1130 :
1131 1 : a.tv_nsec = 913'000'000;
1132 3 : out = a.to_string("%s.%N");
1133 1 : CATCH_REQUIRE(out == "4511.913000000");
1134 3 : out = a.to_string("%s.%EN");
1135 1 : CATCH_REQUIRE(out == "4511.913");
1136 :
1137 1 : a.tv_nsec = 0;
1138 3 : out = a.to_string("%s.%N");
1139 1 : CATCH_REQUIRE(out == "4511.000000000");
1140 3 : out = a.to_string("%s.%EN");
1141 1 : CATCH_REQUIRE(out == "4511.0");
1142 1 : }
1143 7 : CATCH_END_SECTION()
1144 :
1145 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"\".")
1146 : {
1147 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1148 :
1149 1 : time_t date(4511L);
1150 1 : struct tm t = *gmtime(&date);
1151 1 : char expected[256];
1152 1 : strftime(expected, sizeof(expected), "%a %b %e %H:%M:%S.913788345 %Y", &t);
1153 :
1154 1 : g_state = 0;
1155 1 : g_error = 0;
1156 1 : std::string out(a.to_string<wrap_nl_langinfo>());
1157 1 : CATCH_REQUIRE(g_error == 0);
1158 1 : CATCH_REQUIRE(out == expected);
1159 :
1160 1 : }
1161 7 : CATCH_END_SECTION()
1162 :
1163 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"%T\".")
1164 : {
1165 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1166 :
1167 1 : time_t date(4511L);
1168 1 : struct tm t = *gmtime(&date);
1169 1 : char expected[256];
1170 1 : strftime(expected, sizeof(expected), "%T.913788345", &t);
1171 :
1172 1 : g_state = 10;
1173 1 : g_error = 0;
1174 1 : std::string out(a.to_string<wrap_nl_langinfo>());
1175 1 : CATCH_REQUIRE(g_error == 0);
1176 1 : CATCH_REQUIRE(out == expected);
1177 :
1178 1 : }
1179 7 : CATCH_END_SECTION()
1180 :
1181 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"%r %X %EX\".")
1182 : {
1183 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
1184 :
1185 1 : time_t date(4511L);
1186 1 : struct tm t = *gmtime(&date);
1187 1 : char expected[256];
1188 1 : strftime(
1189 : expected
1190 : , sizeof(expected)
1191 : , "%I:%M:%S.913788345 %p" // %r
1192 : " %H:%M:%S.913788345" // %X
1193 : " %H.%M.%S.913788345" // %EX
1194 : , &t);
1195 :
1196 1 : g_state = 20;
1197 1 : g_error = 0;
1198 1 : std::string out(a.to_string<wrap_nl_langinfo>());
1199 1 : CATCH_REQUIRE(g_error == 0);
1200 1 : CATCH_REQUIRE(out == expected);
1201 1 : }
1202 7 : CATCH_END_SECTION()
1203 :
1204 7 : CATCH_START_SECTION("timespec_ex_string: to and from string.")
1205 : {
1206 1 : snapdev::timespec_ex a(timespec{ rand(), rand() % 1'000'000'000 });
1207 1 : snapdev::timespec_ex b;
1208 :
1209 3 : std::string const format("%D %T");
1210 1 : std::string const s(a.to_string(format));
1211 1 : b.from_string(s, format);
1212 :
1213 : // we do not have support for %N just yet in the "from_string()"
1214 : // so here we instead just test the seconds
1215 : //
1216 1 : int const diff(labs(a.tv_sec - b.tv_sec));
1217 1 : bool const result(diff == 0 || diff == 3600);
1218 1 : CATCH_REQUIRE(result); // this is not correct, many countries are "off" the timezone by 30 or 15 min.
1219 1 : }
1220 7 : CATCH_END_SECTION()
1221 :
1222 7 : CATCH_START_SECTION("timespec_ex_string: to and from string with %N.")
1223 : {
1224 1 : snapdev::timespec_ex a(timespec{ rand(), rand() % 1'000'000'000 });
1225 1 : snapdev::timespec_ex b;
1226 :
1227 3 : std::string format("%D %T.%N");
1228 1 : std::string s(a.to_string(format));
1229 : //b.from_string(s, format);
1230 3 : CATCH_REQUIRE_THROWS_MATCHES(
1231 : b.from_string(s, format)
1232 : , libexcept::fixme
1233 : , Catch::Matchers::ExceptionMessage(
1234 : "fixme: the from_string() %N extension is not yet implemented."));
1235 :
1236 : // once it works:
1237 : //
1238 : //CATCH_REQUIRE(a == b);
1239 1 : }
1240 7 : CATCH_END_SECTION()
1241 7 : }
1242 :
1243 :
1244 5 : CATCH_TEST_CASE("timespec_ex_from_string_error", "[time][string][error]")
1245 : {
1246 5 : CATCH_START_SECTION("timespec_ex_from_string_error: string does not start with a sign or digit")
1247 : {
1248 8 : CATCH_REQUIRE_THROWS_MATCHES(
1249 : snapdev::timespec_ex("@34.506")
1250 : , snapdev::syntax_error
1251 : , Catch::Matchers::ExceptionMessage(
1252 : "timespec_ex_exception: number of seconds must include at least one digit, even if '0'."));
1253 : }
1254 5 : CATCH_END_SECTION()
1255 :
1256 5 : CATCH_START_SECTION("timespec_ex_from_string_error: seconds overflow")
1257 : {
1258 8 : CATCH_REQUIRE_THROWS_MATCHES(
1259 : snapdev::timespec_ex("-9223372036854775808.506")
1260 : , snapdev::overflow
1261 : , Catch::Matchers::ExceptionMessage(
1262 : "timespec_ex_exception: number of seconds is too large."));
1263 : }
1264 5 : CATCH_END_SECTION()
1265 :
1266 5 : CATCH_START_SECTION("timespec_ex_from_string_error: bad unit")
1267 : {
1268 8 : CATCH_REQUIRE_THROWS_MATCHES(
1269 : snapdev::timespec_ex("-2036854775808.506sec")
1270 : , snapdev::syntax_error
1271 : , Catch::Matchers::ExceptionMessage(
1272 : "timespec_ex_exception: number include unexpected characters (ec)."));
1273 : }
1274 5 : CATCH_END_SECTION()
1275 :
1276 5 : CATCH_START_SECTION("timespec_ex_from_string_error: bad unit")
1277 : {
1278 1 : snapdev::timespec_ex t;
1279 1 : t.tv_sec = 34471;
1280 1 : t.tv_nsec = 1000000000;
1281 8 : CATCH_REQUIRE_THROWS_MATCHES(
1282 : t.to_string("%s.%N")
1283 : , snapdev::overflow
1284 : , Catch::Matchers::ExceptionMessage(
1285 : "timespec_ex_exception: tv_nsec is 1 billion or more, which is invalid."));
1286 : }
1287 5 : CATCH_END_SECTION()
1288 :
1289 5 : CATCH_START_SECTION("timespec_ex_from_string_error: output too long")
1290 : {
1291 1 : snapdev::timespec_ex t;
1292 1 : t.tv_sec = rand();
1293 1 : t.tv_nsec = rand() % 1000000000;
1294 1 : std::string const format(
1295 : "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."
1296 : " Our current limit is 256 characters so that limits our message. The truth is that you limit yourself"
1297 : " to just a date and time string rather than a whole message in this format string."
1298 : " It's probably easier to handle too... The date is: %D. The time is: %T."
1299 3 : " And we also have %F, %c, %r, %X, %EX for the alternative format, etc.");
1300 2 : CATCH_REQUIRE_THROWS_MATCHES(
1301 : t.to_string(format)
1302 : , snapdev::overflow
1303 : , Catch::Matchers::ExceptionMessage(
1304 : "timespec_ex_exception: the specified strftime() format \""
1305 : + format
1306 : + "\" failed."));
1307 1 : }
1308 5 : CATCH_END_SECTION()
1309 5 : }
1310 :
1311 :
1312 :
1313 : // vim: ts=4 sw=4 et
|