Line data Source code
1 : // Copyright (c) 2018-2021 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 2 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 along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : /** \file
21 : * \brief Verify that the timespec operators function.
22 : *
23 : * This file implements test for the timespec operator functions.
24 : */
25 :
26 : // self
27 : //
28 : #include <snapdev/timespec_operations.h>
29 :
30 : #include "catch_main.h"
31 :
32 :
33 : // C++ lib
34 : //
35 : #include <iomanip>
36 :
37 :
38 : // last include
39 : //
40 : #include <snapdev/poison.h>
41 :
42 :
43 :
44 :
45 :
46 :
47 12 : CATCH_TEST_CASE("timespec-operations", "[math]")
48 : {
49 20 : CATCH_START_SECTION("timespec-operations: simple add")
50 : {
51 1 : timespec a{ 5L, 345L };
52 1 : timespec b{ 13L, 701L };
53 :
54 1 : CATCH_REQUIRE(valid_timespec(a));
55 1 : CATCH_REQUIRE(valid_timespec(b));
56 1 : CATCH_REQUIRE_FALSE(negative_timespec(a));
57 1 : CATCH_REQUIRE_FALSE(negative_timespec(b));
58 :
59 1 : timespec c(a + b);
60 :
61 1 : a += b;
62 :
63 1 : CATCH_REQUIRE(a.tv_sec == 5L + 13L);
64 1 : CATCH_REQUIRE(a.tv_nsec == 345L + 701L);
65 :
66 1 : CATCH_REQUIRE(b.tv_sec == 13L);
67 1 : CATCH_REQUIRE(b.tv_nsec == 701L);
68 :
69 1 : CATCH_REQUIRE(c.tv_sec == 5L + 13L);
70 1 : CATCH_REQUIRE(c.tv_nsec == 345L + 701L);
71 1 : CATCH_REQUIRE(a == c);
72 1 : CATCH_REQUIRE(c == a);
73 : }
74 : CATCH_END_SECTION()
75 :
76 20 : CATCH_START_SECTION("timespec-operations: simple subtract")
77 : {
78 1 : timespec a{ 25L, 1'345L };
79 1 : timespec b{ 13L, 701L };
80 :
81 1 : CATCH_REQUIRE(valid_timespec(a));
82 1 : CATCH_REQUIRE(valid_timespec(b));
83 :
84 1 : timespec c(a - b);
85 1 : timespec d(-b);
86 1 : timespec e(a + d);
87 1 : timespec f(a - 1'000L); // -1us
88 :
89 1 : a -= b;
90 :
91 1 : CATCH_REQUIRE(a.tv_sec == 25L - 13L);
92 1 : CATCH_REQUIRE(a.tv_nsec == 1'345L - 701L);
93 :
94 1 : CATCH_REQUIRE(b.tv_sec == 13L);
95 1 : CATCH_REQUIRE(b.tv_nsec == 701L);
96 :
97 1 : CATCH_REQUIRE(c.tv_sec == 25L - 13L);
98 1 : CATCH_REQUIRE(c.tv_nsec == 1'345L - 701L);
99 1 : CATCH_REQUIRE(a == c);
100 1 : CATCH_REQUIRE(c == a);
101 1 : CATCH_REQUIRE(a == e);
102 1 : CATCH_REQUIRE(e == c);
103 :
104 1 : CATCH_REQUIRE(f.tv_sec == 25L);
105 1 : CATCH_REQUIRE(f.tv_nsec == 1'345L - 1'000L);
106 : }
107 : CATCH_END_SECTION()
108 :
109 20 : CATCH_START_SECTION("timespec-operations: add \"minus one day\"")
110 : {
111 1 : timespec now{ 1629652541L, 345L };
112 1 : timespec backward{ -86400L, 0L }; // -1 day
113 :
114 1 : CATCH_REQUIRE(!!now);
115 1 : CATCH_REQUIRE_FALSE(!backward);
116 1 : CATCH_REQUIRE(negative_timespec(backward));
117 :
118 1 : now += backward;
119 :
120 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L - 86400L);
121 1 : CATCH_REQUIRE(now.tv_nsec == 345L);
122 :
123 1 : CATCH_REQUIRE(backward.tv_sec == -86400L);
124 1 : CATCH_REQUIRE(backward.tv_nsec == 0L);
125 : }
126 : CATCH_END_SECTION()
127 :
128 20 : CATCH_START_SECTION("timespec-operations: add with nano overflow")
129 : {
130 1 : timespec now{ 1629652541L, 913'788'345L };
131 1 : timespec backward{ 86400L, 500'000'000L }; // +1 day and 0.5 seconds
132 :
133 1 : CATCH_REQUIRE(!!now);
134 1 : CATCH_REQUIRE(!!backward);
135 :
136 1 : now += backward;
137 :
138 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 86400L + 1L); // +1 for the overflow
139 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L);
140 :
141 1 : CATCH_REQUIRE(backward.tv_sec == 86400L);
142 1 : CATCH_REQUIRE(backward.tv_nsec == 500'000'000L);
143 : }
144 : CATCH_END_SECTION()
145 :
146 20 : CATCH_START_SECTION("timespec-operations: subtract with nano underflow")
147 : {
148 1 : timespec a{ 13L, 701L };
149 1 : timespec b{ 25L, 1'345L };
150 :
151 1 : CATCH_REQUIRE(valid_timespec(a));
152 1 : CATCH_REQUIRE(valid_timespec(b));
153 :
154 1 : a -= b;
155 :
156 1 : CATCH_REQUIRE(a.tv_sec == 13L - 25L - 1L);
157 1 : CATCH_REQUIRE(a.tv_nsec == 701L - 1'345L + 1'000'000'000L);
158 :
159 1 : CATCH_REQUIRE(b.tv_sec == 25L);
160 1 : CATCH_REQUIRE(b.tv_nsec == 1'345L);
161 : }
162 : CATCH_END_SECTION()
163 :
164 20 : CATCH_START_SECTION("timespec-operations: -1, 0, +1")
165 : {
166 1 : timespec a = {};
167 :
168 1 : CATCH_REQUIRE(!a);
169 1 : CATCH_REQUIRE_FALSE(negative_timespec(a));
170 :
171 1 : --a;
172 :
173 1 : CATCH_REQUIRE_FALSE(!a);
174 1 : CATCH_REQUIRE(negative_timespec(a));
175 1 : CATCH_REQUIRE(a.tv_sec == -1L);
176 1 : CATCH_REQUIRE(a.tv_nsec == 999'999'999L);
177 :
178 1 : ++a;
179 :
180 1 : CATCH_REQUIRE(!a);
181 1 : CATCH_REQUIRE(a.tv_sec == 0L);
182 1 : CATCH_REQUIRE(a.tv_nsec == 0L);
183 :
184 1 : ++a;
185 :
186 1 : CATCH_REQUIRE(!!a);
187 1 : CATCH_REQUIRE_FALSE(negative_timespec(a));
188 1 : CATCH_REQUIRE(a.tv_sec == 0L);
189 1 : CATCH_REQUIRE(a.tv_nsec == 1L);
190 :
191 1 : --a;
192 :
193 1 : CATCH_REQUIRE(!a);
194 1 : CATCH_REQUIRE(a.tv_sec == 0L);
195 1 : CATCH_REQUIRE(a.tv_nsec == 0L);
196 : }
197 : CATCH_END_SECTION()
198 :
199 20 : CATCH_START_SECTION("timespec-operations: add nanos")
200 : {
201 1 : timespec now{ 1629652541L, 913'788'345L };
202 1 : std::int64_t nsec(500'000'000L);
203 :
204 1 : CATCH_REQUIRE(!!now);
205 :
206 1 : timespec sum(now + nsec);
207 :
208 1 : now += nsec;
209 :
210 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 1L); // +1 for the overflow
211 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L);
212 :
213 1 : CATCH_REQUIRE(now == sum);
214 1 : CATCH_REQUIRE_FALSE(now != sum);
215 1 : CATCH_REQUIRE_FALSE(now < sum);
216 1 : CATCH_REQUIRE(now <= sum);
217 1 : CATCH_REQUIRE_FALSE(now > sum);
218 1 : CATCH_REQUIRE(now >= sum);
219 :
220 1 : CATCH_REQUIRE(nsec == 500'000'000L);
221 :
222 1 : nsec += 86400L * 1'000'000'000L;
223 :
224 1 : timespec total(sum + nsec);
225 :
226 1 : now += nsec;
227 :
228 1 : CATCH_REQUIRE(now.tv_sec == 1629652541L + 1L + 86400L); // +1 for the overflow above
229 1 : CATCH_REQUIRE(now.tv_nsec == 913'788'345L + 500'000'000L - 1'000'000'000L + 500'000'000L);
230 :
231 1 : CATCH_REQUIRE(nsec == 500'000'000L + 86400L * 1'000'000'000L);
232 :
233 1 : CATCH_REQUIRE_FALSE(now == sum);
234 1 : CATCH_REQUIRE(now != sum);
235 1 : CATCH_REQUIRE_FALSE(now < sum);
236 1 : CATCH_REQUIRE_FALSE(now <= sum);
237 1 : CATCH_REQUIRE(now > sum);
238 1 : CATCH_REQUIRE(now >= sum);
239 :
240 1 : CATCH_REQUIRE(now == total);
241 1 : CATCH_REQUIRE_FALSE(now != total);
242 1 : CATCH_REQUIRE_FALSE(now < total);
243 1 : CATCH_REQUIRE(now <= total);
244 1 : CATCH_REQUIRE_FALSE(now > total);
245 1 : CATCH_REQUIRE(now >= total);
246 :
247 1 : timespec pre(++total);
248 :
249 1 : CATCH_REQUIRE(pre == total);
250 1 : CATCH_REQUIRE_FALSE(pre != total);
251 1 : CATCH_REQUIRE_FALSE(pre < total);
252 1 : CATCH_REQUIRE(pre <= total);
253 1 : CATCH_REQUIRE_FALSE(pre > total);
254 1 : CATCH_REQUIRE(pre >= total);
255 :
256 1 : CATCH_REQUIRE_FALSE(now == total);
257 1 : CATCH_REQUIRE(now != total);
258 1 : CATCH_REQUIRE(now < total);
259 1 : CATCH_REQUIRE(now <= total);
260 1 : CATCH_REQUIRE_FALSE(now > total);
261 1 : CATCH_REQUIRE_FALSE(now >= total);
262 :
263 1 : timespec post(now++);
264 :
265 1 : CATCH_REQUIRE_FALSE(post == total);
266 1 : CATCH_REQUIRE(post != total);
267 1 : CATCH_REQUIRE(post < total);
268 1 : CATCH_REQUIRE(post <= total);
269 1 : CATCH_REQUIRE_FALSE(post > total);
270 1 : CATCH_REQUIRE_FALSE(post >= total);
271 :
272 1 : CATCH_REQUIRE(now == total);
273 1 : CATCH_REQUIRE_FALSE(now != total);
274 1 : CATCH_REQUIRE_FALSE(now < total);
275 1 : CATCH_REQUIRE(now <= total);
276 1 : CATCH_REQUIRE_FALSE(now > total);
277 1 : CATCH_REQUIRE(now >= total);
278 :
279 1 : pre = --total;
280 :
281 1 : CATCH_REQUIRE(pre == total);
282 1 : CATCH_REQUIRE_FALSE(pre != total);
283 1 : CATCH_REQUIRE_FALSE(pre < total);
284 1 : CATCH_REQUIRE(pre <= total);
285 1 : CATCH_REQUIRE_FALSE(pre > total);
286 1 : CATCH_REQUIRE(pre >= total);
287 :
288 1 : CATCH_REQUIRE_FALSE(now == total);
289 1 : CATCH_REQUIRE(now != total);
290 1 : CATCH_REQUIRE_FALSE(now < total);
291 1 : CATCH_REQUIRE_FALSE(now <= total);
292 1 : CATCH_REQUIRE(now > total);
293 1 : CATCH_REQUIRE(now >= total);
294 :
295 1 : post = now--;
296 :
297 1 : CATCH_REQUIRE_FALSE(post == total);
298 1 : CATCH_REQUIRE(post != total);
299 1 : CATCH_REQUIRE_FALSE(post < total);
300 1 : CATCH_REQUIRE_FALSE(post <= total);
301 1 : CATCH_REQUIRE(post > total);
302 1 : CATCH_REQUIRE(post >= total);
303 :
304 1 : CATCH_REQUIRE(now == total);
305 1 : CATCH_REQUIRE_FALSE(now != total);
306 1 : CATCH_REQUIRE_FALSE(now < total);
307 1 : CATCH_REQUIRE(now <= total);
308 1 : CATCH_REQUIRE_FALSE(now > total);
309 1 : CATCH_REQUIRE(now >= total);
310 :
311 : }
312 : CATCH_END_SECTION()
313 :
314 20 : CATCH_START_SECTION("timespec-operations: load/save")
315 : {
316 1 : timespec now{ 1629652549L, 913'788'345L };
317 :
318 1 : std::int64_t nsec(0);
319 1 : now >>= nsec;
320 :
321 1 : CATCH_REQUIRE(nsec == 1629652549L * 1'000'000'000L + 913'788'345L);
322 :
323 1 : timespec save = {};
324 1 : CATCH_REQUIRE(!save);
325 1 : CATCH_REQUIRE(valid_timespec(save));
326 1 : save <<= nsec;
327 :
328 1 : CATCH_REQUIRE(nsec == 1629652549L * 1'000'000'000L + 913'788'345L);
329 1 : CATCH_REQUIRE(save.tv_sec == 1629652549L);
330 1 : CATCH_REQUIRE(save.tv_nsec == 913'788'345L);
331 :
332 1 : double seconds(33.0);
333 1 : save <<= seconds;
334 1 : CATCH_REQUIRE(save.tv_sec == 33L);
335 1 : CATCH_REQUIRE(save.tv_nsec == 0L);
336 :
337 1 : double precise_time(0.0);
338 1 : save >>= precise_time;
339 1 : bool precise_result(precise_time >= 33.0 && precise_time <= 33.0);
340 1 : CATCH_REQUIRE(precise_result);
341 :
342 1 : seconds = 81.325611932;
343 1 : save <<= seconds;
344 1 : CATCH_REQUIRE(save.tv_sec == 81L);
345 1 : CATCH_REQUIRE(save.tv_nsec == 325'611'932L);
346 :
347 1 : save >>= precise_time;
348 1 : precise_result = precise_time >= 81.325611932 && precise_time <= 81.325611932;
349 1 : CATCH_REQUIRE(precise_result);
350 1 : CATCH_REQUIRE(save == 81.325611932);
351 1 : CATCH_REQUIRE_FALSE(save == 83.5);
352 1 : CATCH_REQUIRE(save != 83.5);
353 1 : CATCH_REQUIRE_FALSE(save != 81.325611932);
354 1 : CATCH_REQUIRE(save < 83.5);
355 1 : CATCH_REQUIRE(save <= 81.33);
356 1 : CATCH_REQUIRE(save <= 81.325611932);
357 1 : CATCH_REQUIRE(save > 71.5);
358 1 : CATCH_REQUIRE(save >= 81.324);
359 1 : CATCH_REQUIRE(save >= 81.325611932);
360 :
361 1 : timespec plus(save + 3.000101);
362 1 : plus >>= precise_time;
363 1 : precise_result = precise_time >= 84.325712930 && precise_time <= 84.325712931; // we lose some precision here
364 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
365 : //<< " expected " << 81.325611932 + 3.000101 << "\n";
366 1 : CATCH_REQUIRE(precise_result);
367 :
368 1 : save += 3.000101;
369 1 : save >>= precise_time;
370 1 : precise_result = precise_time >= 84.325712930 && precise_time <= 84.325712931; // we lose some precision here
371 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
372 : //<< " expected " << 81.325611932 + 3.000101 << "\n";
373 1 : CATCH_REQUIRE(precise_result);
374 1 : CATCH_REQUIRE(save == plus);
375 :
376 1 : timespec minus(save - 1.20050001);
377 1 : minus >>= precise_time;
378 1 : precise_result = precise_time >= 83.125212920 && precise_time <= 83.125212921;
379 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
380 : //<< " expected " << 81.325611932 + 3.000101 - 1.20050001 << "\n";
381 1 : CATCH_REQUIRE(precise_result);
382 :
383 1 : save -= 1.20050001;
384 1 : save >>= precise_time;
385 1 : precise_result = precise_time >= 83.125212920 && precise_time <= 83.125212921;
386 : //std::cerr << "precise = " << std::setprecision(20) << std::setw(9) << precise_time
387 : //<< " expected " << 81.325611932 + 3.000101 - 1.20050001 << "\n";
388 1 : CATCH_REQUIRE(precise_result);
389 1 : CATCH_REQUIRE(save == minus);
390 : }
391 : CATCH_END_SECTION()
392 :
393 20 : CATCH_START_SECTION("timespec-operations: negative + negative")
394 : {
395 1 : timespec pa{ 4511L, 913'788'345L };
396 1 : timespec pb{ 311L, 301'225'198L };
397 :
398 1 : timespec na(-pa);
399 1 : timespec nb(-pb);
400 :
401 1 : timespec sum_ab(na + nb);
402 1 : timespec sum_ba(nb + na);
403 1 : timespec diff_ab(na - nb);
404 1 : timespec diff_ba(nb - na);
405 :
406 1 : CATCH_REQUIRE(sum_ab.tv_sec != -4511L + -311L);
407 1 : CATCH_REQUIRE(sum_ab.tv_sec == -4511L + -1L + -311L + -1L);
408 1 : CATCH_REQUIRE(sum_ab.tv_nsec != -913'788'345L + -301'225'198L);
409 1 : CATCH_REQUIRE(sum_ab.tv_nsec == (1'000'000'000 - 913'788'345L) + (1'000'000'000L - 301'225'198L));
410 :
411 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));
412 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));
413 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));
414 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));
415 :
416 1 : CATCH_REQUIRE(sum_ba.tv_sec != -311L + -4511L);
417 1 : CATCH_REQUIRE(sum_ba.tv_sec == -311L + -1L + -4511L + -1L);
418 1 : CATCH_REQUIRE(sum_ba.tv_nsec != -301'225'198L + -913'788'345L);
419 1 : CATCH_REQUIRE(sum_ba.tv_nsec == (1'000'000'000L - 301'225'198L) + (1'000'000'000 - 913'788'345L));
420 :
421 1 : CATCH_REQUIRE(diff_ab.tv_sec == -4511L + -1L + 311L);
422 1 : CATCH_REQUIRE(diff_ab.tv_nsec == (1'000'000'000 - 913'788'345L) + 301'225'198L);
423 :
424 1 : CATCH_REQUIRE(diff_ab >= (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
425 1 : CATCH_REQUIRE_FALSE(diff_ab > (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
426 1 : CATCH_REQUIRE(diff_ab <= (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
427 1 : CATCH_REQUIRE_FALSE(diff_ab < (-4511L + -1L + 311L) * 1'000'000'000 + (1'000'000'000 - 913'788'345L) + 301'225'198L);
428 :
429 1 : CATCH_REQUIRE(diff_ba.tv_sec == -311L + -1L + 4511L + 1L);
430 1 : CATCH_REQUIRE(diff_ba.tv_nsec == (((1'000'000'000 - 301'225'198L) + 913'788'345L) - 1'000'000'000));
431 :
432 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));
433 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));
434 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));
435 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));
436 : }
437 : CATCH_END_SECTION()
438 :
439 20 : CATCH_START_SECTION("timespec-operations: ostream")
440 : {
441 1 : timespec a{ 4511L, 913'788'345L };
442 :
443 2 : std::stringstream ss;
444 1 : ss << a;
445 :
446 1 : CATCH_REQUIRE(ss.str() == "4511.913788345");
447 :
448 1 : ss.str(std::string());
449 1 : a.tv_sec = 83207L;
450 1 : a.tv_nsec = 0;
451 1 : ss << a;
452 :
453 1 : CATCH_REQUIRE(ss.str() == "83207.000000000");
454 :
455 1 : ss.str(std::string());
456 1 : a.tv_sec = 0L;
457 1 : a.tv_nsec = 101;
458 1 : ss << a;
459 :
460 1 : CATCH_REQUIRE(ss.str() == "0.000000101");
461 : }
462 : CATCH_END_SECTION()
463 16 : }
464 :
465 :
466 :
467 : // vim: ts=4 sw=4 et
|