Line data Source code
1 : // Copyright (c) 2018-2023 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 11 : CATCH_TEST_CASE("timespec_ex_math", "[math]")
119 : {
120 11 : CATCH_START_SECTION("timespec_ex_math: simple add")
121 : {
122 1 : snapdev::timespec_ex a(timespec{ 5L, 345L });
123 :
124 1 : snapdev::timespec_ex b;
125 1 : timespec raw{ 13L, 701L };
126 1 : b = raw;
127 :
128 1 : CATCH_REQUIRE(a.valid());
129 1 : CATCH_REQUIRE(b.valid());
130 1 : CATCH_REQUIRE_FALSE(a.negative());
131 1 : CATCH_REQUIRE_FALSE(b.negative());
132 :
133 1 : snapdev::timespec_ex c(a + b);
134 :
135 1 : a += b;
136 :
137 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L);
138 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L);
139 :
140 1 : CATCH_REQUIRE(b.tv_sec == 13L);
141 1 : CATCH_REQUIRE(b.tv_nsec == 701L);
142 :
143 1 : CATCH_REQUIRE(c.tv_sec == 5L + 13L);
144 1 : CATCH_REQUIRE(c.tv_nsec == 345L + 701L);
145 1 : CATCH_REQUIRE(a == c);
146 1 : CATCH_REQUIRE(c == a);
147 :
148 1 : timespec d{ 3L, 55L };
149 :
150 1 : a += d;
151 :
152 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L + 3L);
153 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L + 55L);
154 :
155 1 : a += 301L;
156 :
157 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L + 3L);
158 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L + 55L + 301L);
159 :
160 1 : a -= 1'000'000'259L;
161 :
162 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L + 3L - 1L);
163 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L + 55L + 301L - 259L);
164 : }
165 11 : CATCH_END_SECTION()
166 :
167 11 : CATCH_START_SECTION("timespec_ex_math: simple subtract")
168 : {
169 1 : snapdev::timespec_ex a(timespec{ 25L, 1'345L });
170 1 : snapdev::timespec_ex b(timespec{ 13L, 701L });
171 :
172 1 : CATCH_REQUIRE(a.valid());
173 1 : CATCH_REQUIRE(b.valid());
174 :
175 1 : snapdev::timespec_ex c(a - b);
176 1 : snapdev::timespec_ex d(-b);
177 1 : snapdev::timespec_ex e(a + d);
178 1 : snapdev::timespec_ex f(a - 1'000L); // -1us
179 :
180 1 : a -= b;
181 :
182 1 : CATCH_REQUIRE(a.tv_sec == 25L - 13L);
183 1 : CATCH_REQUIRE(a.tv_nsec == 1'345L - 701L);
184 :
185 1 : CATCH_REQUIRE(b.tv_sec == 13L);
186 1 : CATCH_REQUIRE(b.tv_nsec == 701L);
187 :
188 1 : CATCH_REQUIRE(c.tv_sec == 25L - 13L);
189 1 : CATCH_REQUIRE(c.tv_nsec == 1'345L - 701L);
190 1 : CATCH_REQUIRE(a == c);
191 1 : CATCH_REQUIRE(c == a);
192 1 : CATCH_REQUIRE(a == e);
193 1 : CATCH_REQUIRE(e == c);
194 :
195 1 : CATCH_REQUIRE(f.tv_sec == 25L);
196 1 : CATCH_REQUIRE(f.tv_nsec == 1'345L - 1'000L);
197 : }
198 11 : CATCH_END_SECTION()
199 :
200 11 : CATCH_START_SECTION("timespec_ex_math: add \"minus one day\"")
201 : {
202 1 : snapdev::timespec_ex now(timespec{ 1629652541L, 345L });
203 1 : snapdev::timespec_ex backward(timespec{ -86400L, 0L }); // -1 day
204 :
205 1 : CATCH_REQUIRE(!!now);
206 1 : CATCH_REQUIRE_FALSE(!backward);
207 1 : CATCH_REQUIRE(backward.negative());
208 :
209 1 : now += backward;
210 :
211 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L - 86400L);
212 1 : CATCH_REQUIRE(now.tv_nsec == 345L);
213 :
214 1 : CATCH_REQUIRE(backward.tv_sec == -86400L);
215 1 : CATCH_REQUIRE(backward.tv_nsec == 0L);
216 : }
217 11 : CATCH_END_SECTION()
218 :
219 11 : CATCH_START_SECTION("timespec_ex_math: add with nano overflow")
220 : {
221 1 : snapdev::timespec_ex now(timespec{ 1629652541L, 913'788'345L });
222 1 : snapdev::timespec_ex backward(timespec{ 86400L, 500'000'000L }); // +1 day and 0.5 seconds
223 :
224 1 : CATCH_REQUIRE(!!now);
225 1 : CATCH_REQUIRE(!!backward);
226 :
227 1 : now += backward;
228 :
229 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 86400L + 1L); // +1 for the overflow
230 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L);
231 :
232 1 : CATCH_REQUIRE(backward.tv_sec == 86400L);
233 1 : CATCH_REQUIRE(backward.tv_nsec == 500'000'000L);
234 : }
235 11 : CATCH_END_SECTION()
236 :
237 11 : CATCH_START_SECTION("timespec_ex_math: subtract with nano underflow")
238 : {
239 1 : snapdev::timespec_ex a(13L, 701L);
240 1 : snapdev::timespec_ex b(25L, 1'345L);
241 :
242 1 : CATCH_REQUIRE(a.valid());
243 1 : CATCH_REQUIRE(b.valid());
244 :
245 1 : a -= b;
246 :
247 1 : CATCH_REQUIRE(a.tv_sec == 13L - 25L - 1L);
248 1 : CATCH_REQUIRE(a.tv_nsec == 701L - 1'345L + 1'000'000'000L);
249 :
250 1 : CATCH_REQUIRE(b.tv_sec == 25L);
251 1 : CATCH_REQUIRE(b.tv_nsec == 1'345L);
252 : }
253 11 : CATCH_END_SECTION()
254 :
255 11 : CATCH_START_SECTION("timespec_ex_math: -1, 0, +1")
256 : {
257 1 : snapdev::timespec_ex a = {};
258 :
259 1 : CATCH_REQUIRE(!a);
260 1 : CATCH_REQUIRE_FALSE(a.negative());
261 :
262 1 : --a;
263 :
264 1 : CATCH_REQUIRE_FALSE(!a);
265 1 : CATCH_REQUIRE(a.negative());
266 1 : CATCH_REQUIRE(a.tv_sec == -1L);
267 1 : CATCH_REQUIRE(a.tv_nsec == 999'999'999L);
268 :
269 1 : ++a;
270 :
271 1 : CATCH_REQUIRE(!a);
272 1 : CATCH_REQUIRE(a.tv_sec == 0L);
273 1 : CATCH_REQUIRE(a.tv_nsec == 0L);
274 :
275 1 : ++a;
276 :
277 1 : CATCH_REQUIRE(!!a);
278 1 : CATCH_REQUIRE_FALSE(a.negative());
279 1 : CATCH_REQUIRE(a.tv_sec == 0L);
280 1 : CATCH_REQUIRE(a.tv_nsec == 1L);
281 :
282 1 : --a;
283 :
284 1 : CATCH_REQUIRE(!a);
285 1 : CATCH_REQUIRE(a.tv_sec == 0L);
286 1 : CATCH_REQUIRE(a.tv_nsec == 0L);
287 : }
288 11 : CATCH_END_SECTION()
289 :
290 11 : CATCH_START_SECTION("timespec_ex_math: add nanos")
291 : {
292 1 : snapdev::timespec_ex now(1629652541L, 913'788'345L);
293 1 : std::int64_t nsec(500'000'000L);
294 :
295 1 : CATCH_REQUIRE(!!now);
296 :
297 1 : snapdev::timespec_ex sum(now + nsec);
298 :
299 1 : now += nsec;
300 :
301 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 1L); // +1 for the overflow
302 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L);
303 :
304 1 : CATCH_REQUIRE(now == sum);
305 1 : CATCH_REQUIRE_FALSE(now != sum);
306 1 : CATCH_REQUIRE_FALSE(now < sum);
307 1 : CATCH_REQUIRE(now <= sum);
308 1 : CATCH_REQUIRE_FALSE(now > sum);
309 1 : CATCH_REQUIRE(now >= sum);
310 :
311 1 : CATCH_REQUIRE(nsec == 500'000'000L);
312 :
313 1 : nsec += 86400L * 1'000'000'000L;
314 :
315 1 : snapdev::timespec_ex total(sum + nsec);
316 :
317 1 : now += nsec;
318 :
319 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 1L + 86400L); // +1 for the overflow above
320 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L + 500'000'000L);
321 :
322 1 : CATCH_REQUIRE(nsec == 500'000'000L + 86400L * 1'000'000'000L);
323 :
324 1 : CATCH_REQUIRE_FALSE(now == sum);
325 1 : CATCH_REQUIRE(now != sum);
326 1 : CATCH_REQUIRE_FALSE(now < sum);
327 1 : CATCH_REQUIRE_FALSE(now <= sum);
328 1 : CATCH_REQUIRE(now > sum);
329 1 : CATCH_REQUIRE(now >= sum);
330 :
331 1 : CATCH_REQUIRE(now == total);
332 1 : CATCH_REQUIRE_FALSE(now != total);
333 1 : CATCH_REQUIRE_FALSE(now < total);
334 1 : CATCH_REQUIRE(now <= total);
335 1 : CATCH_REQUIRE_FALSE(now > total);
336 1 : CATCH_REQUIRE(now >= total);
337 :
338 1 : snapdev::timespec_ex pre(++total);
339 :
340 1 : CATCH_REQUIRE(pre == total);
341 1 : CATCH_REQUIRE_FALSE(pre != total);
342 1 : CATCH_REQUIRE_FALSE(pre < total);
343 1 : CATCH_REQUIRE(pre <= total);
344 1 : CATCH_REQUIRE_FALSE(pre > total);
345 1 : CATCH_REQUIRE(pre >= total);
346 :
347 1 : CATCH_REQUIRE_FALSE(now == total);
348 1 : CATCH_REQUIRE(now != total);
349 1 : CATCH_REQUIRE(now < total);
350 1 : CATCH_REQUIRE(now <= total);
351 1 : CATCH_REQUIRE_FALSE(now > total);
352 1 : CATCH_REQUIRE_FALSE(now >= total);
353 :
354 1 : snapdev::timespec_ex post(now++);
355 :
356 1 : CATCH_REQUIRE_FALSE(post == total);
357 1 : CATCH_REQUIRE(post != total);
358 1 : CATCH_REQUIRE(post < total);
359 1 : CATCH_REQUIRE(post <= total);
360 1 : CATCH_REQUIRE_FALSE(post > total);
361 1 : CATCH_REQUIRE_FALSE(post >= total);
362 :
363 1 : CATCH_REQUIRE(now == total);
364 1 : CATCH_REQUIRE_FALSE(now != total);
365 1 : CATCH_REQUIRE_FALSE(now < total);
366 1 : CATCH_REQUIRE(now <= total);
367 1 : CATCH_REQUIRE_FALSE(now > total);
368 1 : CATCH_REQUIRE(now >= total);
369 :
370 1 : pre = --total;
371 :
372 1 : CATCH_REQUIRE(pre == total);
373 1 : CATCH_REQUIRE_FALSE(pre != total);
374 1 : CATCH_REQUIRE_FALSE(pre < total);
375 1 : CATCH_REQUIRE(pre <= total);
376 1 : CATCH_REQUIRE_FALSE(pre > total);
377 1 : CATCH_REQUIRE(pre >= total);
378 :
379 1 : CATCH_REQUIRE_FALSE(now == total);
380 1 : CATCH_REQUIRE(now != total);
381 1 : CATCH_REQUIRE_FALSE(now < total);
382 1 : CATCH_REQUIRE_FALSE(now <= total);
383 1 : CATCH_REQUIRE(now > total);
384 1 : CATCH_REQUIRE(now >= total);
385 :
386 1 : post = now--;
387 :
388 1 : CATCH_REQUIRE_FALSE(post == total);
389 1 : CATCH_REQUIRE(post != total);
390 1 : CATCH_REQUIRE_FALSE(post < total);
391 1 : CATCH_REQUIRE_FALSE(post <= total);
392 1 : CATCH_REQUIRE(post > total);
393 1 : CATCH_REQUIRE(post >= total);
394 :
395 1 : CATCH_REQUIRE(now == total);
396 1 : CATCH_REQUIRE_FALSE(now != total);
397 1 : CATCH_REQUIRE_FALSE(now < total);
398 1 : CATCH_REQUIRE(now <= total);
399 1 : CATCH_REQUIRE_FALSE(now > total);
400 1 : CATCH_REQUIRE(now >= total);
401 :
402 : }
403 11 : CATCH_END_SECTION()
404 :
405 11 : CATCH_START_SECTION("timespec_ex_math: load/save")
406 : {
407 1 : snapdev::timespec_ex now(1629652549L, 913'788'345L);
408 :
409 1 : std::int64_t nsec(now.to_nsec());
410 1 : CATCH_REQUIRE(nsec == 1629652549L * 1'000'000'000L + 913'788'345L);
411 :
412 1 : std::int64_t usec(now.to_usec());
413 1 : CATCH_REQUIRE(usec == 1629652549L * 1'000'000 + 913'788L);
414 :
415 1 : snapdev::timespec_ex save;
416 1 : CATCH_REQUIRE(!save);
417 1 : CATCH_REQUIRE(save.valid());
418 1 : save = nsec;
419 :
420 1 : CATCH_REQUIRE(nsec == 1629652549L * 1'000'000'000L + 913'788'345L);
421 1 : CATCH_REQUIRE(save.tv_sec == 1629652549L);
422 1 : CATCH_REQUIRE(save.tv_nsec == 913'788'345L);
423 :
424 1 : double seconds(33.0);
425 1 : save = seconds;
426 1 : CATCH_REQUIRE(save.tv_sec == 33L);
427 1 : CATCH_REQUIRE(save.tv_nsec == 0L);
428 :
429 1 : double precise_time(save.to_sec());
430 1 : bool precise_result(precise_time >= 33.0 && precise_time <= 33.0);
431 1 : CATCH_REQUIRE(precise_result);
432 :
433 1 : seconds = 81.325611932;
434 1 : save = seconds;
435 1 : CATCH_REQUIRE(save.tv_sec == 81L);
436 1 : CATCH_REQUIRE(save.tv_nsec == 325'611'932L);
437 :
438 1 : precise_time = save.to_sec();
439 1 : precise_result = precise_time >= 81.325611932 && precise_time <= 81.325611932;
440 1 : CATCH_REQUIRE(precise_result);
441 1 : CATCH_REQUIRE(save == 81.325611932);
442 1 : CATCH_REQUIRE_FALSE(save == 83.5);
443 1 : CATCH_REQUIRE(save != 83.5);
444 1 : CATCH_REQUIRE_FALSE(save != 81.325611932);
445 1 : CATCH_REQUIRE(save < 83.5);
446 1 : CATCH_REQUIRE(save <= 81.33);
447 1 : CATCH_REQUIRE(save <= 81.325611932);
448 1 : CATCH_REQUIRE(save > 71.5);
449 1 : CATCH_REQUIRE(save >= 81.324);
450 1 : CATCH_REQUIRE(save >= 81.325611932);
451 :
452 1 : snapdev::timespec_ex plus(save + 3.000101);
453 1 : precise_time = plus.to_sec();
454 1 : precise_result = precise_time >= 84.325712930 && precise_time <= 84.325712931; // we lose some precision here
455 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
456 : //<< " expected " << 81.325611932 + 3.000101 << "\n";
457 1 : CATCH_REQUIRE(precise_result);
458 :
459 1 : save += 3.000101;
460 1 : precise_time = save.to_sec();
461 1 : precise_result = precise_time >= 84.325712930 && precise_time <= 84.325712931; // we lose some precision here
462 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
463 : //<< " expected " << 81.325611932 + 3.000101 << "\n";
464 1 : CATCH_REQUIRE(precise_result);
465 1 : CATCH_REQUIRE(save == plus);
466 :
467 1 : snapdev::timespec_ex minus(save - 1.20050001);
468 1 : precise_time = minus.to_sec();
469 1 : precise_result = precise_time >= 83.125212920 && precise_time <= 83.125212921;
470 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
471 : //<< " expected " << 81.325611932 + 3.000101 - 1.20050001 << "\n";
472 1 : CATCH_REQUIRE(precise_result);
473 :
474 1 : save -= 1.20050001;
475 1 : precise_time = save.to_sec();
476 1 : precise_result = precise_time >= 83.125212920 && precise_time <= 83.125212921;
477 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
478 : //<< " expected " << 81.325611932 + 3.000101 - 1.20050001 << "\n";
479 1 : CATCH_REQUIRE(precise_result);
480 1 : CATCH_REQUIRE(save == minus);
481 :
482 1 : double neg(-701.445123421);
483 1 : save = neg;
484 1 : CATCH_REQUIRE(save.tv_sec == -702L);
485 2 : precise_result = save.tv_nsec >= -445'123'420L + 1'000'000'000L
486 1 : || save.tv_nsec <= -445'123'422L + 1'000'000'000L;
487 1 : CATCH_REQUIRE(precise_result);
488 : }
489 11 : CATCH_END_SECTION()
490 :
491 11 : CATCH_START_SECTION("timespec_ex_math: negative + negative")
492 : {
493 1 : snapdev::timespec_ex pa(4511L, 913'788'345L);
494 1 : snapdev::timespec_ex pb( 311L, 301'225'198L);
495 :
496 1 : snapdev::timespec_ex na(-pa);
497 1 : snapdev::timespec_ex nb(-pb);
498 :
499 1 : snapdev::timespec_ex sum_ab(na + nb);
500 1 : snapdev::timespec_ex sum_ba(nb + na);
501 1 : snapdev::timespec_ex diff_ab(na - nb);
502 1 : snapdev::timespec_ex diff_ba(nb - na);
503 :
504 1 : CATCH_REQUIRE(sum_ab.tv_sec != -4511L + -311L);
505 1 : CATCH_REQUIRE(sum_ab.tv_sec == -4511L + -1L + -311L + -1L);
506 1 : CATCH_REQUIRE(sum_ab.tv_nsec != -913'788'345L + -301'225'198L);
507 1 : CATCH_REQUIRE(sum_ab.tv_nsec == (1'000'000'000 - 913'788'345L) + (1'000'000'000L - 301'225'198L));
508 :
509 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));
510 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));
511 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));
512 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));
513 :
514 1 : CATCH_REQUIRE(sum_ba.tv_sec != -311L + -4511L);
515 1 : CATCH_REQUIRE(sum_ba.tv_sec == -311L + -1L + -4511L + -1L);
516 1 : CATCH_REQUIRE(sum_ba.tv_nsec != -301'225'198L + -913'788'345L);
517 1 : CATCH_REQUIRE(sum_ba.tv_nsec == (1'000'000'000L - 301'225'198L) + (1'000'000'000 - 913'788'345L));
518 :
519 1 : CATCH_REQUIRE(diff_ab.tv_sec == -4511L + -1L + 311L);
520 1 : CATCH_REQUIRE(diff_ab.tv_nsec == (1'000'000'000 - 913'788'345L) + 301'225'198L);
521 :
522 1 : CATCH_REQUIRE(diff_ab >= (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
523 1 : CATCH_REQUIRE_FALSE(diff_ab > (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
524 1 : CATCH_REQUIRE(diff_ab <= (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
525 1 : CATCH_REQUIRE_FALSE(diff_ab < (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
526 :
527 1 : CATCH_REQUIRE(diff_ba.tv_sec == -311L + -1L + 4511L + 1L);
528 1 : CATCH_REQUIRE(diff_ba.tv_nsec == (((1'000'000'000 - 301'225'198L) + 913'788'345L) - 1'000'000'000));
529 :
530 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));
531 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));
532 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));
533 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));
534 : }
535 11 : CATCH_END_SECTION()
536 :
537 11 : CATCH_START_SECTION("timespec_ex_math: system time")
538 : {
539 1 : snapdev::timespec_ex now;
540 1 : timespec verify = {};
541 :
542 1 : now = snapdev::timespec_ex::gettime();
543 1 : clock_gettime(CLOCK_REALTIME, &verify);
544 :
545 1 : snapdev::timespec_ex const diff(now - verify);
546 1 : snapdev::timespec_ex const max_diff(100L);
547 :
548 1 : CATCH_REQUIRE(diff < max_diff);
549 : }
550 11 : CATCH_END_SECTION()
551 :
552 11 : CATCH_START_SECTION("timespec_ex_math: system time")
553 : {
554 1 : timespec verify = {};
555 :
556 1 : snapdev::timespec_ex const now(snapdev::now());
557 1 : clock_gettime(CLOCK_REALTIME, &verify);
558 :
559 1 : snapdev::timespec_ex const diff(now - verify);
560 1 : snapdev::timespec_ex const max_diff(0, 100L);
561 :
562 1 : CATCH_REQUIRE(diff < max_diff);
563 : }
564 11 : CATCH_END_SECTION()
565 11 : }
566 :
567 :
568 7 : CATCH_TEST_CASE("timespec_ex_string", "[string]")
569 : {
570 7 : CATCH_START_SECTION("timespec_ex_string: ostream")
571 : {
572 : // 4511.913788345
573 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
574 1 : snapdev::timespec_ex b;
575 :
576 1 : std::stringstream ss;
577 1 : ss << a;
578 :
579 1 : CATCH_REQUIRE(ss.str() == "4511.913788345");
580 1 : CATCH_REQUIRE(a.to_timestamp() == "4511.913788345");
581 1 : CATCH_REQUIRE(a.to_timestamp(true) == "4511.913788345");
582 :
583 1 : b.set(ss.str());
584 1 : CATCH_REQUIRE(a == b);
585 :
586 1 : b = "4511.913788345144763"; // ignore digits after 9 decimals
587 1 : CATCH_REQUIRE(a == b);
588 :
589 : // 83207.000000000
590 1 : ss.str(std::string());
591 1 : a.tv_sec = 83207L;
592 1 : a.tv_nsec = 0;
593 1 : ss << a;
594 :
595 1 : CATCH_REQUIRE(ss.str() == "83207.000000000");
596 1 : CATCH_REQUIRE(a.to_timestamp() == "83207.000000000");
597 1 : CATCH_REQUIRE(a.to_timestamp(true) == "83207");
598 :
599 1 : b.set(ss.str());
600 1 : CATCH_REQUIRE(a == b);
601 1 : b.set(" 83207.000000000 ");
602 1 : CATCH_REQUIRE(a == b);
603 1 : b.set(" 83207.0 ");
604 1 : CATCH_REQUIRE(a == b);
605 1 : b.set(" 83207. ");
606 1 : CATCH_REQUIRE(a == b);
607 1 : b.set(" 83207 ");
608 1 : CATCH_REQUIRE(a == b);
609 1 : b.set(" +83207s ");
610 1 : CATCH_REQUIRE(a == b);
611 1 : b.set(" 83207.s ");
612 1 : CATCH_REQUIRE(a == b);
613 1 : b.set(" 83207.0s ");
614 1 : CATCH_REQUIRE(a == b);
615 :
616 1 : snapdev::timespec_ex c("+83207.0s");
617 1 : CATCH_REQUIRE(a == c);
618 :
619 : // 0.000000101
620 1 : ss.str(std::string());
621 1 : a.tv_sec = 0L;
622 1 : a.tv_nsec = 101;
623 1 : ss << a;
624 :
625 1 : CATCH_REQUIRE(ss.str() == "0.000000101");
626 1 : CATCH_REQUIRE(a.to_timestamp() == "0.000000101");
627 1 : CATCH_REQUIRE(a.to_timestamp(true) == "0.000000101");
628 :
629 1 : b.set(ss.str());
630 1 : CATCH_REQUIRE(a == b);
631 :
632 : // 1000000000.781200000
633 1 : ss.str(std::string());
634 1 : a.tv_sec = 1000000000L;
635 1 : a.tv_nsec = 781200000;
636 1 : ss << a;
637 :
638 1 : CATCH_REQUIRE(ss.str() == "1000000000.781200000");
639 1 : CATCH_REQUIRE(a.to_timestamp() == "1000000000.781200000");
640 1 : CATCH_REQUIRE(a.to_timestamp(true) == "1000000000.7812");
641 :
642 1 : b.set(ss.str());
643 1 : CATCH_REQUIRE(a == b);
644 :
645 : // -259.900000000
646 1 : ss.str(std::string());
647 1 : a.tv_sec = -259L;
648 1 : a.tv_nsec = 900000000;
649 1 : ss << a;
650 :
651 1 : CATCH_REQUIRE(ss.str() == "-259.900000000");
652 1 : CATCH_REQUIRE(a.to_timestamp() == "-259.900000000");
653 1 : CATCH_REQUIRE(a.to_timestamp(true) == "-259.9");
654 :
655 1 : b.set(ss.str());
656 1 : CATCH_REQUIRE(a == b);
657 1 : b.set(" -259.900000000 ");
658 1 : CATCH_REQUIRE(a == b);
659 1 : }
660 7 : CATCH_END_SECTION()
661 :
662 7 : CATCH_START_SECTION("timespec_ex_string: convert to string")
663 : {
664 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
665 :
666 : // struct tm date_and_time = {};
667 : // struct tm * ptr(nullptr);
668 : // ptr = localtime_r(&a.tv_sec, &date_and_time);
669 : //std::cerr << "a.tv_sec = " << a.tv_sec << " but " << date_and_time.tm_sec << "\n";
670 :
671 3 : std::string out(a.to_string("%s.%N"));
672 1 : CATCH_REQUIRE(out == "4511.913788345");
673 :
674 1 : out = a.to_string();
675 : //std::cerr << "seconds misplaced in: " << out << "?\n";
676 1 : CATCH_REQUIRE(out.find("11.913788345") != std::string::npos);
677 :
678 1 : a.tv_nsec = 913'000'000;
679 1 : out = a.to_string("%s.%N");
680 1 : CATCH_REQUIRE(out == "4511.913000000");
681 1 : out = a.to_string("%s.%EN");
682 1 : CATCH_REQUIRE(out == "4511.913");
683 :
684 1 : a.tv_nsec = 0;
685 1 : out = a.to_string("%s.%N");
686 1 : CATCH_REQUIRE(out == "4511.000000000");
687 1 : out = a.to_string("%s.%EN");
688 1 : CATCH_REQUIRE(out == "4511.0");
689 1 : }
690 7 : CATCH_END_SECTION()
691 :
692 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"\".")
693 : {
694 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
695 :
696 1 : time_t date(4511L);
697 1 : struct tm t = *localtime(&date);
698 1 : char expected[256];
699 1 : strftime(expected, sizeof(expected), "%a %b %e %H:%M:%S.913788345 %Y", &t);
700 :
701 1 : g_state = 0;
702 1 : g_error = 0;
703 2 : std::string out(a.to_string<wrap_nl_langinfo>());
704 1 : CATCH_REQUIRE(g_error == 0);
705 1 : CATCH_REQUIRE(out == expected);
706 :
707 1 : }
708 7 : CATCH_END_SECTION()
709 :
710 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"%T\".")
711 : {
712 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
713 :
714 1 : time_t date(4511L);
715 1 : struct tm t = *localtime(&date);
716 1 : char expected[256];
717 1 : strftime(expected, sizeof(expected), "%T.913788345", &t);
718 :
719 1 : g_state = 10;
720 1 : g_error = 0;
721 2 : std::string out(a.to_string<wrap_nl_langinfo>());
722 1 : CATCH_REQUIRE(g_error == 0);
723 1 : CATCH_REQUIRE(out == expected);
724 :
725 1 : }
726 7 : CATCH_END_SECTION()
727 :
728 7 : CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"%r %X %EX\".")
729 : {
730 1 : snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
731 :
732 1 : time_t date(4511L);
733 1 : struct tm t = *localtime(&date);
734 1 : char expected[256];
735 1 : strftime(
736 : expected
737 : , sizeof(expected)
738 : , "%I:%M:%S.913788345 %p" // %r
739 : " %H:%M:%S.913788345" // %X
740 : " %H.%M.%S.913788345" // %EX
741 : , &t);
742 :
743 1 : g_state = 20;
744 1 : g_error = 0;
745 2 : std::string out(a.to_string<wrap_nl_langinfo>());
746 1 : CATCH_REQUIRE(g_error == 0);
747 1 : CATCH_REQUIRE(out == expected);
748 1 : }
749 7 : CATCH_END_SECTION()
750 :
751 7 : CATCH_START_SECTION("timespec_ex_string: to and from string.")
752 : {
753 1 : snapdev::timespec_ex a(timespec{ rand(), rand() % 1'000'000'000 });
754 1 : snapdev::timespec_ex b;
755 :
756 2 : std::string format("%D %T");
757 1 : std::string s(a.to_string(format));
758 1 : b.from_string(s, format);
759 :
760 : // we do not have support for %N just yet in the "from_string()"
761 : // so here we instead just test the seconds
762 : //
763 1 : CATCH_REQUIRE(a.tv_sec == b.tv_sec);
764 1 : }
765 7 : CATCH_END_SECTION()
766 :
767 7 : CATCH_START_SECTION("timespec_ex_string: to and from string with %N.")
768 : {
769 1 : snapdev::timespec_ex a(timespec{ rand(), rand() % 1'000'000'000 });
770 1 : snapdev::timespec_ex b;
771 :
772 2 : std::string format("%D %T.%N");
773 1 : std::string s(a.to_string(format));
774 : //b.from_string(s, format);
775 1 : CATCH_REQUIRE_THROWS_MATCHES(
776 : b.from_string(s, format)
777 : , libexcept::fixme
778 : , Catch::Matchers::ExceptionMessage(
779 : "fixme: the from_string() %N extension is not yet implemented."));
780 :
781 : // once it works:
782 : //
783 : //CATCH_REQUIRE(a == b);
784 1 : }
785 7 : CATCH_END_SECTION()
786 7 : }
787 :
788 :
789 5 : CATCH_TEST_CASE("timespec_ex_from_string_error", "[string][error]")
790 : {
791 5 : CATCH_START_SECTION("timespec_ex_from_string_error: string does not start with a sign or digit")
792 : {
793 5 : CATCH_REQUIRE_THROWS_MATCHES(
794 : snapdev::timespec_ex("@34.506")
795 : , snapdev::syntax_error
796 : , Catch::Matchers::ExceptionMessage(
797 : "timespec_ex_exception: number of seconds must include at least one digit, even if '0'."));
798 : }
799 5 : CATCH_END_SECTION()
800 :
801 5 : CATCH_START_SECTION("timespec_ex_from_string_error: seconds overflow")
802 : {
803 5 : CATCH_REQUIRE_THROWS_MATCHES(
804 : snapdev::timespec_ex("-9223372036854775808.506")
805 : , snapdev::overflow
806 : , Catch::Matchers::ExceptionMessage(
807 : "timespec_ex_exception: number of seconds is too large."));
808 : }
809 5 : CATCH_END_SECTION()
810 :
811 5 : CATCH_START_SECTION("timespec_ex_from_string_error: bad unit")
812 : {
813 5 : CATCH_REQUIRE_THROWS_MATCHES(
814 : snapdev::timespec_ex("-2036854775808.506sec")
815 : , snapdev::syntax_error
816 : , Catch::Matchers::ExceptionMessage(
817 : "timespec_ex_exception: number include unexpected characters (ec)."));
818 : }
819 5 : CATCH_END_SECTION()
820 :
821 5 : CATCH_START_SECTION("timespec_ex_from_string_error: bad unit")
822 : {
823 1 : snapdev::timespec_ex t;
824 1 : t.tv_sec = 34471;
825 1 : t.tv_nsec = 1000000000;
826 5 : CATCH_REQUIRE_THROWS_MATCHES(
827 : t.to_string("%s.%N")
828 : , snapdev::overflow
829 : , Catch::Matchers::ExceptionMessage(
830 : "timespec_ex_exception: tv_nsec is 1 billion or more, which is invalid."));
831 : }
832 5 : CATCH_END_SECTION()
833 :
834 5 : CATCH_START_SECTION("timespec_ex_from_string_error: output too long")
835 : {
836 1 : snapdev::timespec_ex t;
837 1 : t.tv_sec = rand();
838 1 : t.tv_nsec = rand() % 1000000000;
839 1 : std::string const format(
840 : "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."
841 : " Our current limit is 256 characters so that limits our message. The truth is that you limit yourself"
842 : " to just a date and time string rather than a whole message in this format string."
843 : " It's probably easier to handle too... The date is: %D. The time is: %T."
844 2 : " And we also have %F, %c, %r, %X, %EX for the alternative format, etc.");
845 1 : CATCH_REQUIRE_THROWS_MATCHES(
846 : t.to_string(format)
847 : , snapdev::overflow
848 : , Catch::Matchers::ExceptionMessage(
849 : "timespec_ex_exception: the specified strftime() format \""
850 : + format
851 : + "\" failed."));
852 1 : }
853 5 : CATCH_END_SECTION()
854 5 : }
855 :
856 :
857 :
858 : // vim: ts=4 sw=4 et
|