LCOV - code coverage report
Current view: top level - tests - catch_timespec_ex.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 98.4 % 515 507
Test Date: 2025-07-03 19:05:49 Functions: 100.0 % 4 4
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2018-2025  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", "[time][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", "[time][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            3 :         b = "4511.913788345144763"; // ignore digits after 9 decimals
     587            1 :         CATCH_REQUIRE(a == b);
     588              : 
     589            3 :         b = "4511.91378834598771"; // try again with an odd number of digits
     590            1 :         CATCH_REQUIRE(a == b);
     591              : 
     592              :         // 83207.000000000
     593            1 :         ss.str(std::string());
     594            1 :         a.tv_sec = 83207L;
     595            1 :         a.tv_nsec = 0;
     596            1 :         ss << a;
     597              : 
     598            1 :         CATCH_REQUIRE(ss.str() == "83207");
     599            1 :         CATCH_REQUIRE(a.to_timestamp() == "83207.000000000");
     600            1 :         CATCH_REQUIRE(a.to_timestamp(true) == "83207");
     601              : 
     602            1 :         b.set(ss.str());
     603            1 :         CATCH_REQUIRE(a == b);
     604            3 :         b.set("   83207.000000000  ");
     605            1 :         CATCH_REQUIRE(a == b);
     606            3 :         b.set("   83207.0  ");
     607            1 :         CATCH_REQUIRE(a == b);
     608            3 :         b.set("   83207.  ");
     609            1 :         CATCH_REQUIRE(a == b);
     610            3 :         b.set("   83207  ");
     611            1 :         CATCH_REQUIRE(a == b);
     612            3 :         b.set("   +83207s  ");
     613            1 :         CATCH_REQUIRE(a == b);
     614            3 :         b.set("   83207.s  ");
     615            1 :         CATCH_REQUIRE(a == b);
     616            3 :         b.set("   83207.0s  ");
     617            1 :         CATCH_REQUIRE(a == b);
     618              : 
     619            3 :         snapdev::timespec_ex c("+83207.0s");
     620            1 :         CATCH_REQUIRE(a == c);
     621              : 
     622              :         // 0.000000101
     623            1 :         ss.str(std::string());
     624            1 :         a.tv_sec = 0L;
     625            1 :         a.tv_nsec = 101;
     626            1 :         ss << a;
     627              : 
     628            1 :         CATCH_REQUIRE(ss.str() == "0.000000101");
     629            1 :         CATCH_REQUIRE(a.to_timestamp() == "0.000000101");
     630            1 :         CATCH_REQUIRE(a.to_timestamp(true) == "0.000000101");
     631              : 
     632            1 :         b.set(ss.str());
     633            1 :         CATCH_REQUIRE(a == b);
     634              : 
     635              :         // 1000000000.781200000
     636            1 :         ss.str(std::string());
     637            1 :         a.tv_sec = 1000000000L;
     638            1 :         a.tv_nsec = 781200000;
     639            1 :         ss << snapdev::setremovetrailingzeroes(false) << a;
     640              : 
     641            1 :         CATCH_REQUIRE(ss.str() == "1000000000.781200000");
     642            1 :         CATCH_REQUIRE(a.to_timestamp() == "1000000000.781200000");
     643            1 :         CATCH_REQUIRE(a.to_timestamp(true) == "1000000000.7812");
     644              : 
     645            1 :         b.set(ss.str());
     646            1 :         CATCH_REQUIRE(a == b);
     647              : 
     648              :         // -259.900000000
     649            1 :         ss.str(std::string());
     650            1 :         a.tv_sec = -259L;
     651            1 :         a.tv_nsec = 900000000;
     652            1 :         ss << a;
     653              : 
     654            1 :         CATCH_REQUIRE(ss.str() == "-259.900000000");
     655            1 :         CATCH_REQUIRE(a.to_timestamp() == "-259.900000000");
     656            1 :         CATCH_REQUIRE(a.to_timestamp(true) == "-259.9");
     657              : 
     658            1 :         b.set(ss.str());
     659            1 :         CATCH_REQUIRE(a == b);
     660            3 :         b.set("    -259.900000000   ");
     661            1 :         CATCH_REQUIRE(a == b);
     662            1 :     }
     663            7 :     CATCH_END_SECTION()
     664              : 
     665            7 :     CATCH_START_SECTION("timespec_ex_string: convert to string")
     666              :     {
     667            1 :         snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
     668              : 
     669              : //        struct tm date_and_time = {};
     670              : //        localtime_r(&a.tv_sec, &date_and_time);
     671              : //std::cerr << "a.tv_sec = " << a.tv_sec << " but localtime.tm_sec = " << date_and_time.tm_sec;
     672              : //        gmtime_r(&a.tv_sec, &date_and_time);
     673              : //std::cerr << " and gmtime.tm_sec = " << date_and_time.tm_sec << "\n";
     674              : 
     675              :         // for these tests, we change the timezone to UTC so localtime_r()
     676              :         // and gmtime_r() both return the same thing
     677              :         //
     678            3 :         std::string out(a.to_string("%s.%N", true));
     679            1 :         CATCH_REQUIRE(out == "4511.913788345");
     680              : 
     681            3 :         out = a.to_string("%s.%N", false);
     682            1 :         CATCH_REQUIRE(out == "4511.913788345");
     683              : 
     684            1 :         out = a.to_string();
     685              : //std::cerr << "seconds misplaced in: " << out << "?\n";
     686            1 :         CATCH_REQUIRE(out.find("11.913788345") != std::string::npos);
     687              : 
     688            1 :         a.tv_nsec = 913'000'000;
     689            3 :         out = a.to_string("%s.%N");
     690            1 :         CATCH_REQUIRE(out == "4511.913000000");
     691            3 :         out = a.to_string("%s.%EN");
     692            1 :         CATCH_REQUIRE(out == "4511.913");
     693              : 
     694            1 :         a.tv_nsec = 0;
     695            3 :         out = a.to_string("%s.%N");
     696            1 :         CATCH_REQUIRE(out == "4511.000000000");
     697            3 :         out = a.to_string("%s.%EN");
     698            1 :         CATCH_REQUIRE(out == "4511.0");
     699            1 :     }
     700            7 :     CATCH_END_SECTION()
     701              : 
     702            7 :     CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"\".")
     703              :     {
     704            1 :         snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
     705              : 
     706            1 :         time_t date(4511L);
     707            1 :         struct tm t = *gmtime(&date);
     708            1 :         char expected[256];
     709            1 :         strftime(expected, sizeof(expected), "%a %b %e %H:%M:%S.913788345 %Y", &t);
     710              : 
     711            1 :         g_state = 0;
     712            1 :         g_error = 0;
     713            1 :         std::string out(a.to_string<wrap_nl_langinfo>());
     714            1 :         CATCH_REQUIRE(g_error == 0);
     715            1 :         CATCH_REQUIRE(out == expected);
     716              : 
     717            1 :     }
     718            7 :     CATCH_END_SECTION()
     719              : 
     720            7 :     CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"%T\".")
     721              :     {
     722            1 :         snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
     723              : 
     724            1 :         time_t date(4511L);
     725            1 :         struct tm t = *gmtime(&date);
     726            1 :         char expected[256];
     727            1 :         strftime(expected, sizeof(expected), "%T.913788345", &t);
     728              : 
     729            1 :         g_state = 10;
     730            1 :         g_error = 0;
     731            1 :         std::string out(a.to_string<wrap_nl_langinfo>());
     732            1 :         CATCH_REQUIRE(g_error == 0);
     733            1 :         CATCH_REQUIRE(out == expected);
     734              : 
     735            1 :     }
     736            7 :     CATCH_END_SECTION()
     737              : 
     738            7 :     CATCH_START_SECTION("timespec_ex_string: convert to string when nl_langinfo(\"D_T_FMT\") returns \"%r %X %EX\".")
     739              :     {
     740            1 :         snapdev::timespec_ex a(timespec{ 4511L, 913'788'345L });
     741              : 
     742            1 :         time_t date(4511L);
     743            1 :         struct tm t = *gmtime(&date);
     744            1 :         char expected[256];
     745            1 :         strftime(
     746              :               expected
     747              :             , sizeof(expected)
     748              :             , "%I:%M:%S.913788345 %p"       // %r
     749              :               " %H:%M:%S.913788345"         // %X
     750              :               " %H.%M.%S.913788345"         // %EX
     751              :             , &t);
     752              : 
     753            1 :         g_state = 20;
     754            1 :         g_error = 0;
     755            1 :         std::string out(a.to_string<wrap_nl_langinfo>());
     756            1 :         CATCH_REQUIRE(g_error == 0);
     757            1 :         CATCH_REQUIRE(out == expected);
     758            1 :     }
     759            7 :     CATCH_END_SECTION()
     760              : 
     761            7 :     CATCH_START_SECTION("timespec_ex_string: to and from string.")
     762              :     {
     763            1 :         snapdev::timespec_ex a(timespec{ rand(), rand() % 1'000'000'000 });
     764            1 :         snapdev::timespec_ex b;
     765              : 
     766            3 :         std::string const format("%D %T");
     767            1 :         std::string const s(a.to_string(format));
     768            1 :         b.from_string(s, format);
     769              : 
     770              :         // we do not have support for %N just yet in the "from_string()"
     771              :         // so here we instead just test the seconds
     772              :         //
     773            1 :         int const diff(labs(a.tv_sec - b.tv_sec));
     774            1 :         bool const result(diff == 0 || diff == 3600);
     775            1 :         CATCH_REQUIRE(result); // this is not correct, many countries are "off" the timezone by 30 or 15 min.
     776            1 :     }
     777            7 :     CATCH_END_SECTION()
     778              : 
     779            7 :     CATCH_START_SECTION("timespec_ex_string: to and from string with %N.")
     780              :     {
     781            1 :         snapdev::timespec_ex a(timespec{ rand(), rand() % 1'000'000'000 });
     782            1 :         snapdev::timespec_ex b;
     783              : 
     784            3 :         std::string format("%D %T.%N");
     785            1 :         std::string s(a.to_string(format));
     786              :         //b.from_string(s, format);
     787            3 :         CATCH_REQUIRE_THROWS_MATCHES(
     788              :                   b.from_string(s, format)
     789              :                 , libexcept::fixme
     790              :                 , Catch::Matchers::ExceptionMessage(
     791              :                           "fixme: the from_string() %N extension is not yet implemented."));
     792              : 
     793              :         // once it works:
     794              :         //
     795              :         //CATCH_REQUIRE(a == b);
     796            1 :     }
     797            7 :     CATCH_END_SECTION()
     798            7 : }
     799              : 
     800              : 
     801            5 : CATCH_TEST_CASE("timespec_ex_from_string_error", "[time][string][error]")
     802              : {
     803            5 :     CATCH_START_SECTION("timespec_ex_from_string_error: string does not start with a sign or digit")
     804              :     {
     805            8 :         CATCH_REQUIRE_THROWS_MATCHES(
     806              :                   snapdev::timespec_ex("@34.506")
     807              :                 , snapdev::syntax_error
     808              :                 , Catch::Matchers::ExceptionMessage(
     809              :                           "timespec_ex_exception: number of seconds must include at least one digit, even if '0'."));
     810              :     }
     811            5 :     CATCH_END_SECTION()
     812              : 
     813            5 :     CATCH_START_SECTION("timespec_ex_from_string_error: seconds overflow")
     814              :     {
     815            8 :         CATCH_REQUIRE_THROWS_MATCHES(
     816              :                   snapdev::timespec_ex("-9223372036854775808.506")
     817              :                 , snapdev::overflow
     818              :                 , Catch::Matchers::ExceptionMessage(
     819              :                           "timespec_ex_exception: number of seconds is too large."));
     820              :     }
     821            5 :     CATCH_END_SECTION()
     822              : 
     823            5 :     CATCH_START_SECTION("timespec_ex_from_string_error: bad unit")
     824              :     {
     825            8 :         CATCH_REQUIRE_THROWS_MATCHES(
     826              :                   snapdev::timespec_ex("-2036854775808.506sec")
     827              :                 , snapdev::syntax_error
     828              :                 , Catch::Matchers::ExceptionMessage(
     829              :                           "timespec_ex_exception: number include unexpected characters (ec)."));
     830              :     }
     831            5 :     CATCH_END_SECTION()
     832              : 
     833            5 :     CATCH_START_SECTION("timespec_ex_from_string_error: bad unit")
     834              :     {
     835            1 :         snapdev::timespec_ex t;
     836            1 :         t.tv_sec = 34471;
     837            1 :         t.tv_nsec = 1000000000;
     838            8 :         CATCH_REQUIRE_THROWS_MATCHES(
     839              :                   t.to_string("%s.%N")
     840              :                 , snapdev::overflow
     841              :                 , Catch::Matchers::ExceptionMessage(
     842              :                           "timespec_ex_exception: tv_nsec is 1 billion or more, which is invalid."));
     843              :     }
     844            5 :     CATCH_END_SECTION()
     845              : 
     846            5 :     CATCH_START_SECTION("timespec_ex_from_string_error: output too long")
     847              :     {
     848            1 :         snapdev::timespec_ex t;
     849            1 :         t.tv_sec = rand();
     850            1 :         t.tv_nsec = rand() % 1000000000;
     851            1 :         std::string const format(
     852              :                 "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."
     853              :                 " Our current limit is 256 characters so that limits our message. The truth is that you limit yourself"
     854              :                 " to just a date and time string rather than a whole message in this format string."
     855              :                 " It's probably easier to handle too... The date is: %D. The time is: %T."
     856            3 :                 " And we also have %F, %c, %r, %X, %EX for the alternative format, etc.");
     857            2 :         CATCH_REQUIRE_THROWS_MATCHES(
     858              :                   t.to_string(format)
     859              :                 , snapdev::overflow
     860              :                 , Catch::Matchers::ExceptionMessage(
     861              :                           "timespec_ex_exception: the specified strftime() format \""
     862              :                         + format
     863              :                         + "\" failed."));
     864            1 :     }
     865            5 :     CATCH_END_SECTION()
     866            5 : }
     867              : 
     868              : 
     869              : 
     870              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions