LCOV - code coverage report
Current view: top level - tests - catch_timespec_ex.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 505 513 98.4 %
Date: 2024-05-10 21:04:00 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14

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