LCOV - code coverage report
Current view: top level - tests - catch_timespec_ex.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 501 509 98.4 %
Date: 2023-05-29 16:11:08 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14