LCOV - code coverage report
Current view: top level - test - timestamp-test.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 310 344 90.1 %
Date: 2017-04-30 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Present - Date/Time Library
       3             :  *
       4             :  * Tests for the Timestamp C++ class and C-compatible methods
       5             :  *
       6             :  * Licensed under the MIT License.
       7             :  * For details, see LICENSE.
       8             :  */
       9             : 
      10             : #include "catch.hpp"
      11             : #include "test-utils.hpp"
      12             : 
      13             : #include "present.h"
      14             : 
      15             : #include "utils/constants.h"
      16             : #include "utils/time-utils.h"
      17             : 
      18             : // If we're using GCC, disable the annoying warning about missing initializers
      19             : #ifdef __GNUC__
      20             : # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
      21             : #endif
      22             : 
      23             : static const struct Timestamp EMPTY_TIMESTAMP = {};
      24             : 
      25             : /** Absolute value for time_t's */
      26             : #define ABS(a) (((a) < (time_t) 0) ? -(a) : (a))
      27             : 
      28             : /**
      29             :  * Shortcut macro to compare timestamp_seconds and additional_nanoseconds all
      30             :  * in one.
      31             :  * Expects that the Timestamp is "t".
      32             :  */
      33             : #define IS(test_timestamp_seconds, test_additional_nanoseconds) \
      34             :     REQUIRE_FALSE(t.has_error);                                 \
      35             :     CHECK(t.data_.timestamp_seconds == test_timestamp_seconds); \
      36             :     CHECK(t.data_.additional_nanoseconds == test_additional_nanoseconds);
      37             : 
      38             : /**
      39             :  * Shortcut macro to check if there's a certain error.
      40             :  * Expects that the Timestamp is "t".
      41             :  */
      42             : #define IS_ERROR(eRR_tYPE)      \
      43             :     CHECK(t.has_error);         \
      44             :     CHECK(t.errors.eRR_tYPE);
      45             : 
      46             : /**
      47             :  * Check that creating a Timestamp from a struct tm works correctly.
      48             :  */
      49             : #define TEST_CREATE_FROM_STRUCT_TM(yr, mon, mday, hr, min, sec, \
      50             :         tz_offset, expected_unix_timestamp)                     \
      51             :     do {                                                        \
      52             :         struct tm tm = {};                                      \
      53             :         tm.tm_year = yr - STRUCT_TM_YEAR_OFFSET;                \
      54             :         tm.tm_mon = mon - STRUCT_TM_MONTH_OFFSET;               \
      55             :         tm.tm_mday = mday;                                      \
      56             :         tm.tm_hour = hr;                                        \
      57             :         tm.tm_min = min;                                        \
      58             :         tm.tm_sec = sec;                                        \
      59             :         tm.tm_isdst = 0;                                        \
      60             :         REQUIRE(mktime(&tm) != -1);                             \
      61             :         {                                                       \
      62             :             Timestamp t = EMPTY_TIMESTAMP;                      \
      63             :             t = Timestamp::create(tm,                           \
      64             :                     TimeDelta::from_hours(tz_offset));          \
      65             :             REQUIRE_FALSE(t.has_error);                         \
      66             :             IS(expected_unix_timestamp, 0);                     \
      67             :             CHECK(t.get_clock_time_utc().minute() == min);      \
      68             :             CHECK(t.get_clock_time_utc().second() == sec);      \
      69             :             CHECK(t.get_clock_time_utc().nanosecond() == 0);    \
      70             :         }                                                       \
      71             :         {                                                       \
      72             :             Timestamp t = EMPTY_TIMESTAMP;                      \
      73             :             TimeDelta delta = TimeDelta::from_hours(tz_offset); \
      74             :             t = Timestamp_from_struct_tm(tm, &delta);           \
      75             :             REQUIRE_FALSE(t.has_error);                         \
      76             :             IS(expected_unix_timestamp, 0);                     \
      77             :             CHECK(t.get_clock_time_utc().minute() == min);      \
      78             :             CHECK(t.get_clock_time_utc().second() == sec);      \
      79             :             CHECK(t.get_clock_time_utc().nanosecond() == 0);    \
      80             :         }                                                       \
      81             :         {                                                       \
      82             :             Timestamp t = EMPTY_TIMESTAMP;                      \
      83             :             TimeDelta delta = TimeDelta::from_hours(tz_offset); \
      84             :             Timestamp_ptr_from_struct_tm(&t, tm, &delta);       \
      85             :             REQUIRE_FALSE(t.has_error);                         \
      86             :             IS(expected_unix_timestamp, 0);                     \
      87             :             CHECK(t.get_clock_time_utc().minute() == min);      \
      88             :             CHECK(t.get_clock_time_utc().second() == sec);      \
      89             :             CHECK(t.get_clock_time_utc().nanosecond() == 0);    \
      90             :         }                                                       \
      91             :     } while (0)
      92             : 
      93             : /**
      94             :  * Check that creating a Timestamp from a Date and a ClockTime works
      95             :  * correctly. This tests the C++ @p Timestamp::create function and the C
      96             :  * @p Timestamp_create and @p Timestamp_ptr_create functions.
      97             :  */
      98             : #define TEST_CREATE_FROM_DATE_TIME(yr, mon, mday, hr, min, sec,         \
      99             :         tz_offset, expected_unix_timestamp)                             \
     100             :     do {                                                                \
     101             :         const Date testDate = Date::create(yr, mon, mday);              \
     102             :         const ClockTime testTime = ClockTime::create(hr, min, sec);     \
     103             :         const TimeDelta testDelta = TimeDelta::from_hours(tz_offset);   \
     104             :         {                                                               \
     105             :             Timestamp t = EMPTY_TIMESTAMP;                              \
     106             :             t = Timestamp::create(testDate, testTime, testDelta);       \
     107             :             REQUIRE_FALSE(t.has_error);                                 \
     108             :             IS(expected_unix_timestamp, 0);                             \
     109             :             CHECK(t.get_clock_time_utc().minute() == min);              \
     110             :             CHECK(t.get_clock_time_utc().second() == sec);              \
     111             :             CHECK(t.get_clock_time_utc().nanosecond() == 0);            \
     112             :         }                                                               \
     113             :         {                                                               \
     114             :             Timestamp t = EMPTY_TIMESTAMP;                              \
     115             :             t = Timestamp_create(&testDate, &testTime, &testDelta);     \
     116             :             REQUIRE_FALSE(t.has_error);                                 \
     117             :             IS(expected_unix_timestamp, 0);                             \
     118             :             CHECK(t.get_clock_time_utc().minute() == min);              \
     119             :             CHECK(t.get_clock_time_utc().second() == sec);              \
     120             :             CHECK(t.get_clock_time_utc().nanosecond() == 0);            \
     121             :         }                                                               \
     122             :         {                                                               \
     123             :             Timestamp t = EMPTY_TIMESTAMP;                              \
     124             :             Timestamp_ptr_create(&t, &testDate, &testTime, &testDelta); \
     125             :             REQUIRE_FALSE(t.has_error);                                 \
     126             :             IS(expected_unix_timestamp, 0);                             \
     127             :             CHECK(t.get_clock_time_utc().minute() == min);              \
     128             :             CHECK(t.get_clock_time_utc().second() == sec);              \
     129             :             CHECK(t.get_clock_time_utc().nanosecond() == 0);            \
     130             :         }                                                               \
     131             :     } while (0)
     132             : 
     133             : /**
     134             :  * This test case tests all the overloads of the "create" method (which also
     135             :  * tests the C "Timestamp_create_..." functions).
     136             :  */
     137           7 : TEST_CASE("Timestamp creators", "[timestamp]") {
     138             :     Timestamp t;
     139             : 
     140             :     // create(time_t)
     141             :     // from_time_t(time_t)
     142           6 :     SECTION("creating from a time_t") {
     143           1 :         t = Timestamp::create((time_t) 0);
     144           1 :         IS(0, 0);
     145           1 :         t = Timestamp::create((time_t) 1325376000);
     146           1 :         IS(1325376000, 0);
     147             : 
     148           1 :         t = Timestamp_from_time_t((time_t) 0);
     149           1 :         IS(0, 0);
     150           1 :         t = Timestamp_from_time_t((time_t) 918491000);
     151           1 :         IS(918491000, 0);
     152             : 
     153           1 :         Timestamp_ptr_from_time_t(&t, (time_t) 0);
     154           1 :         IS(0, 0);
     155           1 :         Timestamp_ptr_from_time_t(&t, (time_t) 1);
     156           1 :         IS(1, 0);
     157           6 :     }
     158             : 
     159             :     // create(struct tm, TimeDelta)
     160             :     // create(Date, ClockTime, TimeDelta)
     161             :     // from_struct_tm(struct tm, TimeDelta)
     162           6 :     SECTION("creating from a struct tm, or from a Date/ClockTime/TimeDelta") {
     163           1 :         TEST_CREATE_FROM_STRUCT_TM(
     164             :                 1970, 1, 1,     // date
     165             :                 0, 0, 0,        // time
     166             :                 0,              // time zone offset
     167             :                 0);             // expected UNIX timestamp
     168           1 :         TEST_CREATE_FROM_DATE_TIME(1970, 1, 1, 0, 0, 0,     0, 0);
     169             : 
     170           1 :         TEST_CREATE_FROM_STRUCT_TM(1969, 12, 31, 0, 0, 0,   0, -86400);
     171           1 :         TEST_CREATE_FROM_DATE_TIME(1969, 12, 31, 0, 0, 0,   0, -86400);
     172             : 
     173           1 :         TEST_CREATE_FROM_STRUCT_TM(1970, 1, 2, 0, 0, 0,     0, 86400);
     174           1 :         TEST_CREATE_FROM_DATE_TIME(1970, 1, 2, 0, 0, 0,     0, 86400);
     175             : 
     176             :         // All the same timestamp (197589599):
     177             :         // Apr. 5, 1976 21:59:59 UTC
     178             :         // Apr. 5, 1976 16:59:59 EST (UTC-05:00)
     179             :         // Apr. 6, 1976 00:59:59 MSK (UTC+03:00)
     180           1 :         TEST_CREATE_FROM_STRUCT_TM(1976, 4, 5, 21, 59, 59,  0,  197589599);
     181           1 :         TEST_CREATE_FROM_DATE_TIME(1976, 4, 5, 21, 59, 59,  0,  197589599);
     182             : 
     183           1 :         TEST_CREATE_FROM_STRUCT_TM(1976, 4, 5, 16, 59, 59,  -5, 197589599);
     184           1 :         TEST_CREATE_FROM_DATE_TIME(1976, 4, 5, 16, 59, 59,  -5, 197589599);
     185             : 
     186           1 :         TEST_CREATE_FROM_STRUCT_TM(1976, 4, 6, 0, 59, 59,   +3, 197589599);
     187           1 :         TEST_CREATE_FROM_DATE_TIME(1976, 4, 6, 0, 59, 59,   +3, 197589599);
     188           6 :     }
     189             : 
     190             :     // create_utc(struct tm)
     191             :     // from_struct_tm_utc(struct tm)
     192           6 :     SECTION("creating from a struct tm in UTC") {
     193           1 :         struct tm nicks_bday = {};
     194           1 :         nicks_bday.tm_year = 2000 - STRUCT_TM_YEAR_OFFSET;
     195           1 :         nicks_bday.tm_mon = 8 - STRUCT_TM_MONTH_OFFSET;
     196           1 :         nicks_bday.tm_mday = 18;
     197           1 :         nicks_bday.tm_hour = 17;
     198           1 :         nicks_bday.tm_min = 12;
     199           1 :         nicks_bday.tm_sec = 59;
     200           1 :         nicks_bday.tm_isdst = -1;
     201             : 
     202           1 :         t = Timestamp_from_struct_tm_utc(nicks_bday);
     203           1 :         CHECK(t.get_date_utc() == Date::create(2000, 8, 18));
     204           1 :         CHECK(t.get_clock_time_utc() == ClockTime::create(17, 12, 59));
     205             : 
     206           1 :         t = Timestamp::create_utc(nicks_bday);
     207           1 :         CHECK(t.get_date_utc() == Date::create(2000, 8, 18));
     208           1 :         CHECK(t.get_clock_time_utc() == ClockTime::create(17, 12, 59));
     209           6 :     }
     210             : 
     211           6 :     SECTION("creating from a Date/ClockTime with a bad Date or ClockTime") {
     212           1 :         Date bad_d = Date::create(0, 0, 0);
     213           1 :         REQUIRE(bad_d.has_error);
     214           1 :         Date good_d = Date::create(2000, 1, 1);
     215           1 :         REQUIRE_FALSE(good_d.has_error);
     216             : 
     217           1 :         ClockTime bad_ct = ClockTime::create(99, 99, 99);
     218           1 :         REQUIRE(bad_ct.has_error);
     219           1 :         ClockTime good_ct = ClockTime::noon();
     220           1 :         REQUIRE_FALSE(good_ct.has_error);
     221             : 
     222           1 :         t = Timestamp::create(bad_d, good_ct, TimeDelta::zero());
     223           1 :         IS_ERROR(invalid_date);
     224           1 :         t = Timestamp::create_utc(bad_d, good_ct);
     225           1 :         IS_ERROR(invalid_date);
     226           1 :         t = Timestamp::create_local(bad_d, good_ct);
     227           1 :         IS_ERROR(invalid_date);
     228             : 
     229           1 :         t = Timestamp::create(good_d, bad_ct, TimeDelta::zero());
     230           1 :         IS_ERROR(invalid_clock_time);
     231           1 :         t = Timestamp::create_utc(good_d, bad_ct);
     232           1 :         IS_ERROR(invalid_clock_time);
     233           1 :         t = Timestamp::create_local(good_d, bad_ct);
     234           1 :         IS_ERROR(invalid_clock_time);
     235           6 :     }
     236             : 
     237           6 :     SECTION("now()") {
     238             :         // (change what present_now() returns to 1999-2-28 05:34:41.986 UTC)
     239             :         struct PresentNowStruct test_now = {
     240             :             (time_t) 920180081,
     241             :             (long)   986000000
     242           1 :         };
     243           1 :         present_set_test_time(test_now);
     244             : 
     245           1 :         t = EMPTY_TIMESTAMP;
     246           1 :         t = Timestamp::now();
     247           1 :         IS(920180081, 986000000);
     248             : 
     249           1 :         t = EMPTY_TIMESTAMP;
     250           1 :         t = Timestamp_now();
     251           1 :         IS(920180081, 986000000);
     252             : 
     253           1 :         t = EMPTY_TIMESTAMP;
     254           1 :         Timestamp_ptr_now(&t);
     255           1 :         IS(920180081, 986000000);
     256             : 
     257           1 :         present_reset_test_time();
     258             : 
     259             :         // (make sure it returns something different now)
     260           1 :         t = EMPTY_TIMESTAMP;
     261           1 :         t = Timestamp::now();
     262           1 :         REQUIRE_FALSE(t.has_error);
     263           1 :         CHECK(t.data_.timestamp_seconds != 920180081);
     264           6 :     }
     265             : 
     266           6 :     SECTION("epoch()") {
     267           1 :         t = EMPTY_TIMESTAMP;
     268           1 :         t = Timestamp::epoch();
     269           1 :         IS(0, 0);
     270             : 
     271           1 :         t = EMPTY_TIMESTAMP;
     272           1 :         t = Timestamp_epoch();
     273           1 :         IS(0, 0);
     274             : 
     275           1 :         t = EMPTY_TIMESTAMP;
     276           1 :         Timestamp_ptr_epoch(&t);
     277           1 :         IS(0, 0);
     278           6 :     }
     279           6 : }
     280             : 
     281           2 : TEST_CASE("Timestamp creators edge case finder", "[timestamp]") {
     282             :     Timestamp t;
     283             : 
     284         601 :     for (int_year year = 2099; year >= 1500; year--) {
     285             :         t = Timestamp::create_utc(
     286             :                 Date::create(year, 1, 1),
     287         600 :                 ClockTime::midnight());
     288         600 :         CHECK(t.get_date_utc() == Date::create(year, 1, 1));
     289             : 
     290             :         t = Timestamp::create_utc(
     291             :                 Date::create(year, 3, 1),
     292         600 :                 ClockTime::midnight());
     293         600 :         CHECK(t.get_date_utc() == Date::create(year, 3, 1));
     294             :     }
     295           1 : }
     296             : 
     297           4 : TEST_CASE("Timestamp accessors", "[timestamp]") {
     298             :     // All the same timestamp (197589599):
     299             :     // Apr. 5, 1976 21:59:59 UTC
     300             :     // Apr. 5, 1976 16:59:59 EST (UTC-05:00)
     301             :     // Apr. 6, 1976 00:59:59 MSK (UTC+03:00)
     302             : 
     303           3 :     Timestamp t = Timestamp::create((time_t) 197589599);
     304           3 :     REQUIRE_FALSE(t.has_error);
     305             : 
     306             :     // get_time_t
     307           3 :     CHECK(t.get_time_t() == 197589599);
     308             : 
     309           3 :     SECTION("get_struct_tm family") {
     310           1 :         struct tm tm_utc = t.get_struct_tm_utc();
     311           1 :         CHECK(tm_utc.tm_year == 1976 - STRUCT_TM_YEAR_OFFSET);
     312           1 :         CHECK(tm_utc.tm_mon == 4 - STRUCT_TM_MONTH_OFFSET);
     313           1 :         CHECK(tm_utc.tm_mday == 5);
     314           1 :         CHECK(tm_utc.tm_hour == 21);
     315           1 :         CHECK(tm_utc.tm_min == 59);
     316           1 :         CHECK(tm_utc.tm_sec == 59);
     317             : 
     318           1 :         struct tm tm_est = t.get_struct_tm(TimeDelta::from_hours(-5));
     319           1 :         CHECK(tm_est.tm_year == 1976 - STRUCT_TM_YEAR_OFFSET);
     320           1 :         CHECK(tm_est.tm_mon == 4 - STRUCT_TM_MONTH_OFFSET);
     321           1 :         CHECK(tm_est.tm_mday == 5);
     322           1 :         CHECK(tm_est.tm_hour == 16);
     323           1 :         CHECK(tm_est.tm_min == 59);
     324           1 :         CHECK(tm_est.tm_sec == 59);
     325             : 
     326           1 :         struct tm tm_msk = t.get_struct_tm(TimeDelta::from_hours(3));
     327           1 :         CHECK(tm_msk.tm_year == 1976 - STRUCT_TM_YEAR_OFFSET);
     328           1 :         CHECK(tm_msk.tm_mon == 4 - STRUCT_TM_MONTH_OFFSET);
     329           1 :         CHECK(tm_msk.tm_mday == 6);
     330           1 :         CHECK(tm_msk.tm_hour == 0);
     331           1 :         CHECK(tm_msk.tm_min == 59);
     332           1 :         CHECK(tm_msk.tm_sec == 59);
     333           3 :     }
     334             : 
     335           3 :     SECTION("get_date family") {
     336           1 :         CHECK(t.get_date_utc() == Date::create(1976, 4, 5));
     337           1 :         CHECK(t.get_date(TimeDelta::zero()) == Date::create(1976, 4, 5));
     338           1 :         CHECK(t.get_date(TimeDelta::from_hours(-5)) ==
     339             :                 Date::create(1976, 4, 5));
     340           1 :         CHECK(t.get_date(TimeDelta::from_hours(3)) ==
     341             :                 Date::create(1976, 4, 6));
     342           3 :     }
     343             : 
     344           3 :     SECTION("get_clock_time family") {
     345           1 :         CHECK(t.get_clock_time_utc() == ClockTime::create(21, 59, 59));
     346           1 :         CHECK(t.get_clock_time(TimeDelta::zero()) ==
     347             :                 ClockTime::create(21, 59, 59));
     348           1 :         CHECK(t.get_clock_time(TimeDelta::from_hours(-5)) ==
     349             :                 ClockTime::create(16, 59, 59));
     350           1 :         CHECK(t.get_clock_time(TimeDelta::from_hours(3)) ==
     351             :                 ClockTime::create(0, 59, 59));
     352           3 :     }
     353           3 : }
     354             : 
     355           3 : TEST_CASE("Timestamp creators and accessors in local time", "[timestamp]") {
     356           2 :     SECTION("create in local time, access in local time (winter)") {
     357             :         // create with the C function, from a Date and ClockTime
     358           1 :         const Date date_input = Date::create(1959, 1, 17);
     359           1 :         const ClockTime clock_time_input = ClockTime::create(14, 39, 45);
     360           1 :         Timestamp t = Timestamp_create_local(&date_input, &clock_time_input);
     361           1 :         REQUIRE_FALSE(t.has_error);
     362             : 
     363           1 :         struct tm tm_local = t.get_struct_tm_local();
     364           1 :         CHECK(tm_local.tm_year == 1959 - STRUCT_TM_YEAR_OFFSET);
     365           1 :         CHECK(tm_local.tm_mon == 1 - STRUCT_TM_MONTH_OFFSET);
     366           1 :         CHECK(tm_local.tm_mday == 17);
     367           1 :         CHECK(tm_local.tm_hour == 14);
     368           1 :         CHECK(tm_local.tm_min == 39);
     369           1 :         CHECK(tm_local.tm_sec == 45);
     370             : 
     371           1 :         CHECK(t.get_date_local() == date_input);
     372           1 :         CHECK(t.get_clock_time_local() == clock_time_input);
     373           2 :     }
     374             : 
     375           2 :     SECTION("create in local time, access in local time (summer)") {
     376           1 :         struct tm tm_input = {};
     377           1 :         tm_input.tm_year = 1959 - STRUCT_TM_YEAR_OFFSET;
     378           1 :         tm_input.tm_mon = 7 - STRUCT_TM_MONTH_OFFSET;
     379           1 :         tm_input.tm_mday = 17;
     380           1 :         tm_input.tm_hour = 14;
     381           1 :         tm_input.tm_min = 39;
     382           1 :         tm_input.tm_sec = 45;
     383           1 :         tm_input.tm_isdst = -1;
     384             : 
     385             :         // create with the C function, from a struct tm
     386           1 :         Timestamp t = Timestamp_from_struct_tm_local(tm_input);
     387           1 :         REQUIRE_FALSE(t.has_error);
     388             : 
     389           1 :         struct tm tm_local = t.get_struct_tm_local();
     390           1 :         CHECK(tm_local.tm_year == 1959 - STRUCT_TM_YEAR_OFFSET);
     391           1 :         CHECK(tm_local.tm_mon == 7 - STRUCT_TM_MONTH_OFFSET);
     392           1 :         CHECK(tm_local.tm_mday == 17);
     393           1 :         CHECK(tm_local.tm_hour == 14);
     394           1 :         CHECK(tm_local.tm_min == 39);
     395           1 :         CHECK(tm_local.tm_sec == 45);
     396             : 
     397           1 :         CHECK(t.get_date_local() == Date::create(1959, 7, 17));
     398           1 :         CHECK(t.get_clock_time_local() == ClockTime::create(14, 39, 45));
     399           2 :     }
     400             : 
     401             :     // This test won't work if the absolute value of the time zone offset is
     402             :     // greater than 12 hours :(
     403           2 :     time_t time_zone_offset_winter = get_local_time_zone_offset_for_january();
     404           2 :     if (ABS(time_zone_offset_winter) < 12 * SECONDS_IN_HOUR) {
     405             :         TimeDelta time_zone_offset(
     406           0 :                 TimeDelta::from_seconds(time_zone_offset_winter));
     407             : 
     408           0 :         SECTION("create in UTC, access in local time (winter)") {
     409             :             Timestamp t = Timestamp::create_utc(
     410             :                     Date::create(1987, 1, 4),
     411           0 :                     ClockTime::noon());
     412           0 :             REQUIRE_FALSE(t.has_error);
     413             : 
     414           0 :             CHECK(t.get_date_local() == Date::create(1987, 1, 4));
     415           0 :             CHECK(t.get_clock_time_local() - time_zone_offset
     416             :                     == ClockTime::noon());
     417             : 
     418             :             // Sanity check
     419           0 :             CHECK((t - time_zone_offset).get_date_local() ==
     420             :                     Date::create(1987, 1, 4));
     421           0 :             CHECK((t - time_zone_offset).get_clock_time_local() ==
     422             :                     ClockTime::noon());
     423           0 :         }
     424             : 
     425           0 :         SECTION("create in local time, access in UTC (winter)") {
     426             :             Timestamp t = Timestamp::create_local(
     427             :                     Date::create(1987, 1, 4),
     428           0 :                     ClockTime::noon());
     429           0 :             REQUIRE_FALSE(t.has_error);
     430             : 
     431           0 :             CHECK(t.get_date_utc() == Date::create(1987, 1, 4));
     432           0 :             CHECK(t.get_clock_time_utc() + time_zone_offset
     433             :                     == ClockTime::noon());
     434             : 
     435             :             // Sanity check
     436           0 :             CHECK((t + time_zone_offset).get_date_utc() ==
     437             :                     Date::create(1987, 1, 4));
     438           0 :             CHECK((t + time_zone_offset).get_clock_time_utc() ==
     439             :                     ClockTime::noon());
     440           0 :         }
     441             :     }
     442             : 
     443             :     // Now, do the same thing for summer
     444           2 :     time_t time_zone_offset_summer = get_local_time_zone_offset_for_july();
     445           2 :     if (ABS(time_zone_offset_summer) < 12 * SECONDS_IN_HOUR) {
     446             :         TimeDelta time_zone_offset(
     447           0 :                 TimeDelta::from_seconds(time_zone_offset_summer));
     448             : 
     449           0 :         SECTION("create in UTC, access in local time (summer)") {
     450             :             Timestamp t = Timestamp::create_utc(
     451             :                     Date::create(1992, 7, 4),
     452           0 :                     ClockTime::noon());
     453           0 :             REQUIRE_FALSE(t.has_error);
     454             : 
     455           0 :             CHECK(t.get_date_local() == Date::create(1992, 7, 4));
     456           0 :             CHECK(t.get_clock_time_local() - time_zone_offset
     457             :                     == ClockTime::noon());
     458             : 
     459             :             // Sanity check
     460           0 :             CHECK((t - time_zone_offset).get_date_local() ==
     461             :                     Date::create(1992, 7, 4));
     462           0 :             CHECK((t - time_zone_offset).get_clock_time_local() ==
     463             :                     ClockTime::noon());
     464           0 :         }
     465             : 
     466           0 :         SECTION("create in local time, access in UTC (summer)") {
     467             :             Timestamp t = Timestamp::create_local(
     468             :                     Date::create(1992, 7, 4),
     469           0 :                     ClockTime::noon());
     470           0 :             REQUIRE_FALSE(t.has_error);
     471             : 
     472           0 :             CHECK(t.get_date_utc() == Date::create(1992, 7, 4));
     473           0 :             CHECK(t.get_clock_time_utc() + time_zone_offset
     474             :                     == ClockTime::noon());
     475             : 
     476             :             // Sanity check
     477           0 :             CHECK((t + time_zone_offset).get_date_utc() ==
     478             :                     Date::create(1992, 7, 4));
     479           0 :             CHECK((t + time_zone_offset).get_clock_time_utc() ==
     480             :                     ClockTime::noon());
     481           0 :         }
     482             :     }
     483             : 
     484           2 : }
     485             : 
     486           2 : TEST_CASE("Timestamp 'difference' functions", "[timestamp]") {
     487           1 :     const time_t base = 197589599;
     488           1 :     Timestamp t1 = Timestamp::create(base),
     489           1 :               t2 = Timestamp::create(base + 86400 + 3600);  // + 1 day, 1 hour
     490           1 :     REQUIRE_FALSE(t1.has_error);
     491           1 :     REQUIRE_FALSE(t2.has_error);
     492             : 
     493           1 :     TimeDelta exp_diff = TimeDelta::from_seconds(86400 + 3600);
     494           1 :     CHECK(t1.difference(t2) == -exp_diff);
     495           1 :     CHECK(t2.difference(t1) == exp_diff);
     496           1 :     CHECK(t1.absolute_difference(t2) == exp_diff);
     497           1 :     CHECK(t2.absolute_difference(t1) == exp_diff);
     498           1 : }
     499             : 
     500           2 : TEST_CASE("Timestamp arithmetic operators with TimeDelta", "[timestamp]") {
     501           1 :     const time_t base_time = 197589599;
     502           1 :     TimeDelta seconds_plus4 = TimeDelta::from_seconds(4),
     503           1 :               hours_minus4 = TimeDelta::from_hours(-4);
     504             : 
     505           1 :     Timestamp orig_t = Timestamp::create(base_time),
     506             :               t;
     507           1 :     REQUIRE_FALSE(orig_t.has_error);
     508             : 
     509           1 :     t = orig_t;
     510           1 :     t += seconds_plus4;
     511           1 :     CHECK(t.get_time_t() == base_time + 4);
     512             : 
     513           1 :     t = orig_t;
     514           1 :     t -= seconds_plus4;
     515           1 :     CHECK(t.get_time_t() == base_time - 4);
     516             : 
     517           1 :     t = orig_t;
     518           1 :     t += hours_minus4;
     519           1 :     CHECK(t.get_time_t() == base_time + (3600 * -4));
     520             : 
     521           1 :     t = orig_t;
     522           1 :     t -= hours_minus4;
     523           1 :     CHECK(t.get_time_t() == base_time - (3600 * -4));
     524             : 
     525             :     // TODO: more...
     526           1 : }
     527             : 
     528           2 : TEST_CASE("Timestamp arithmetic operators with DayDelta", "[timestamp]") {
     529           1 :     DayDelta days_plus5 = DayDelta::from_days(5),
     530           1 :              weeks_minus2 = DayDelta::from_weeks(-2);
     531             : 
     532             :     Timestamp orig_t = Timestamp::create_utc(Date::create(1981, 4, 1),
     533           1 :             ClockTime::midnight());
     534           1 :     REQUIRE_FALSE(orig_t.has_error);
     535             :     Timestamp t;
     536             : 
     537           1 :     t = orig_t;
     538           1 :     t += days_plus5;
     539           1 :     CHECK(t.get_date_utc() == Date::create(1981, 4, 6));
     540           1 :     t += days_plus5;
     541           1 :     CHECK(t.get_date_utc() == Date::create(1981, 4, 11));
     542             : 
     543           1 :     t = orig_t;
     544           1 :     t -= days_plus5;
     545           1 :     CHECK(t.get_date_utc() == Date::create(1981, 3, 27));
     546           1 :     t -= days_plus5;
     547           1 :     CHECK(t.get_date_utc() == Date::create(1981, 3, 22));
     548             : 
     549           1 :     t = orig_t;
     550           1 :     t += weeks_minus2;
     551           1 :     CHECK(t.get_date_utc() == Date::create(1981, 3, 18));
     552             : 
     553           1 :     t = orig_t;
     554           1 :     t -= weeks_minus2;
     555           1 :     CHECK(t.get_date_utc() == Date::create(1981, 4, 15));
     556           1 :     t += weeks_minus2;
     557           1 :     CHECK(t.get_date_utc() == Date::create(1981, 4, 1));
     558             : 
     559             : 
     560           2 :     t = Timestamp::create_utc(Date::create(1995, 6, 23), ClockTime::midnight())
     561           3 :             + DayDelta::from_days(4);
     562           1 :     CHECK(t.get_date_utc() == Date::create(1995, 6, 27));
     563             : 
     564           2 :     t = Timestamp::create_utc(Date::create(1968, 2, 24), ClockTime::midnight())
     565           3 :             - DayDelta::from_days(16);
     566           1 :     CHECK(t.get_date_utc() == Date::create(1968, 2, 8));
     567             : 
     568           2 :     t = (Timestamp::create_utc(Date::create(2002, 1, 1), ClockTime::midnight())
     569           4 :             - DayDelta::from_days(3))
     570           3 :             + DayDelta::from_weeks(2);
     571           1 :     CHECK(t.get_date_utc() == Date::create(2002, 1, 12));
     572             : 
     573           1 :     t = DayDelta::from_days(8) + orig_t;
     574           1 :     CHECK(t.get_date_utc() == Date::create(1981, 4, 9));
     575           1 : }
     576             : 
     577           2 : TEST_CASE("Timestamp arithmetic operators with MonthDelta", "[timestamp]") {
     578           1 :     MonthDelta months_plus2 = MonthDelta::from_months(2),
     579           1 :                months_minus5 = MonthDelta::from_months(-5),
     580           1 :                years_plus4 = MonthDelta::from_years(4),
     581           1 :                years_minus16 = MonthDelta::from_years(-16);
     582             : 
     583             :     Timestamp orig_t = Timestamp::create_utc(Date::create(1982, 11, 13),
     584           1 :             ClockTime::midnight());
     585             :     Timestamp t;
     586             : 
     587           1 :     t = orig_t;
     588           1 :     t += months_plus2;
     589           1 :     CHECK(t.get_date_utc() == Date::create(1983, 1, 13));
     590           1 :     t += months_minus5;
     591           1 :     CHECK(t.get_date_utc() == Date::create(1982, 8, 13));
     592             : 
     593           1 :     t = orig_t;
     594           1 :     t -= months_plus2;
     595           1 :     CHECK(t.get_date_utc() == Date::create(1982, 9, 13));
     596           1 :     t -= months_minus5;
     597           1 :     CHECK(t.get_date_utc() == Date::create(1983, 2, 13));
     598             : 
     599           1 :     t = orig_t;
     600           1 :     t += years_plus4;
     601           1 :     CHECK(t.get_date_utc() == Date::create(1986, 11, 13));
     602           1 :     t += years_minus16;
     603           1 :     CHECK(t.get_date_utc() == Date::create(1970, 11, 13));
     604             : 
     605           1 :     t = orig_t;
     606           1 :     t -= years_plus4;
     607           1 :     CHECK(t.get_date_utc() == Date::create(1978, 11, 13));
     608           1 :     t -= years_minus16;
     609           1 :     CHECK(t.get_date_utc() == Date::create(1994, 11, 13));
     610             : 
     611           1 :     t = orig_t + MonthDelta::from_months(7);
     612           1 :     CHECK(t.get_date_utc() == Date::create(1983, 6, 13));
     613             : 
     614           1 :     t = orig_t - MonthDelta::from_months(3);
     615           1 :     CHECK(t.get_date_utc() == Date::create(1982, 8, 13));
     616             : 
     617           1 :     t = MonthDelta::from_years(4) + orig_t;
     618           1 :     CHECK(t.get_date_utc() == Date::create(1986, 11, 13));
     619           1 : }
     620             : 
     621           2 : TEST_CASE("Timestamp arithmetic operators edge cases", "[timestamp]") {
     622           1 :     DayDelta days_plus8 = DayDelta::from_days(8);
     623           1 :     MonthDelta months_plus5 = MonthDelta::from_months(5),
     624           1 :                months_minus11 = MonthDelta::from_months(-11);
     625             : 
     626             :     Timestamp orig_t = Timestamp::create_utc(
     627           1 :             Date::create(1934, 8, 16), ClockTime::create(23, 37, 48));
     628             :     Timestamp t;
     629             : 
     630           1 :     t = orig_t;
     631           1 :     t += days_plus8;
     632           1 :     CHECK(t.get_date_utc() == Date::create(1934, 8, 24));
     633             : 
     634           1 :     t = orig_t;
     635           1 :     t -= days_plus8;
     636           1 :     CHECK(t.get_date_utc() == Date::create(1934, 8, 8));
     637             : 
     638           1 :     t = orig_t;
     639           1 :     t += months_plus5;
     640           1 :     CHECK(t.get_date_utc() == Date::create(1935, 1, 16));
     641             : 
     642           1 :     t = orig_t;
     643           1 :     t -= months_plus5;
     644           1 :     CHECK(t.get_date_utc() == Date::create(1934, 3, 16));
     645             : 
     646           1 :     t = orig_t;
     647           1 :     t += months_minus11;
     648           1 :     CHECK(t.get_date_utc() == Date::create(1933, 9, 16));
     649             : 
     650           1 :     t = orig_t;
     651           1 :     t -= months_minus11;
     652           1 :     CHECK(t.get_date_utc() == Date::create(1935, 7, 16));
     653           4 : }
     654             : 

Generated by: LCOV version 1.10