]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
added calendar regression tests, fixed german umlaut mixup
authorJuergen Perlinger <perlinger@ntp.org>
Wed, 3 Nov 2010 18:42:16 +0000 (19:42 +0100)
committerJuergen Perlinger <perlinger@ntp.org>
Wed, 3 Nov 2010 18:42:16 +0000 (19:42 +0100)
bk: 4cd1ad08TdTs0splRg-N5J4cF8jSEg

include/ntp_filegen.h
libntp/ntp_calendar.c
ntpd/ntp_filegen.c
tests/libntp/Makefile.am
tests/libntp/calendar.cpp [new file with mode: 0644]

index 369489f22d37489a998c659800d68fa7b10030dd..c4213c46c9478f2130902fe663c2155eb21d1be0 100644 (file)
@@ -5,7 +5,7 @@
  *
  *
  * Copyright (C) 1992, 1996 by Rainer Pruy
- * Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
+ * Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
  *
  * This code may be modified and used freely
  * provided the credits remain intact.
index fefd4cb5da2a3aa4896b63ac61e6c6fc307e6be2..9bed5dc63a50f5cfc764a9e7124a114084a5c2c7 100644 (file)
 #include "ntp_fp.h"
 #include "ntp_unixtime.h"
 
-#if !(defined(ISC_CHECK_ALL) || defined(ISC_CHECK_NONE) || \
-      defined(ISC_CHECK_ENSURE) || defined(ISC_CHECK_INSIST) || \
-      defined(ISC_CHECK_INVARIANT))
-# define ISC_CHECK_ALL
-#endif
-
-#include "ntp_assert.h"
-
 /*
  *---------------------------------------------------------------------
  * basic calendar stuff
@@ -430,8 +422,6 @@ priv_timesplit(
 {
        int32 days = 0;
 
-       NTP_INSIST(NULL != split);
-
        /* make sure we have a positive offset into a day */
        if (ts < 0 || ts >= SECSPERDAY) {
                days = ts / SECSPERDAY;
@@ -441,7 +431,6 @@ priv_timesplit(
                        ts   += SECSPERDAY;
                }
        }
-       NTP_ENSURE(0 <= ts && ts < SECSPERDAY);
 
        /* get secs, mins, hours */
        split[2] = (u_char)(ts % SECSPERMIN);
@@ -449,11 +438,6 @@ priv_timesplit(
        split[1] = (u_char)(ts % MINSPERHR);
        split[0] = (u_char)(ts / MINSPERHR);
 
-       /* check time invariants */
-       NTP_ENSURE(split[0] < HRSPERDAY );
-       NTP_ENSURE(split[1] < MINSPERHR );
-       NTP_ENSURE(split[2] < SECSPERMIN);
-
        return days;
 }
 
@@ -512,9 +496,6 @@ ntpcal_split_eradays(
        res.hi = ((4*n400 + n100)*25 + n004)*4 + n001;
        res.lo = yday;
        
-       NTP_ENSURE(0 <= res.lo && res.lo <= 365);
-       NTP_INVARIANT(ntpcal_days_in_years(res.hi) + res.lo == days);
-
        return res;
 }
 
@@ -523,6 +504,9 @@ ntpcal_split_eradays(
  * Given a number of elapsed days in a year and a leap year indicator,
  * split the number of elapsed days into the number of elapsed months in
  * 'res.hi' and the number of elapsed days of that month in 'res.lo'.
+ *
+ * This function will fail and return {-1,-1} if the number of elapsed
+ * days is not in the valid range!
  *---------------------------------------------------------------------
  */
 ntpcal_split
@@ -533,19 +517,17 @@ ntpcal_split_yeardays(
        ntpcal_split   res;
        const u_short *lt;      /* month length table   */
 
-       NTP_REQUIRE(0 <= eyd && eyd <= 365);
-       
        /* check leap year flag and select proper table */
        lt = real_month_table[(isleapyear != 0)];
-       /* get zero-based month by approximation & correction step */
-       res.hi = eyd >> 5;         /* approx month; might be 1 too low */
-       if (lt[res.hi + 1] <= eyd) /* fixup approximative month value  */
-               res.hi += 1;
-       res.lo = eyd - lt[res.hi];
+       if (0 <= eyd && eyd < lt[12]) {
+               /* get zero-based month by approximation & correction step */
+               res.hi = eyd >> 5;         /* approx month; might be 1 too low */
+               if (lt[res.hi + 1] <= eyd) /* fixup approximative month value  */
+                       res.hi += 1;
+               res.lo = eyd - lt[res.hi];
+       } else
+               res.lo = res.hi = -1;
 
-       NTP_ENSURE(0 <= res.hi && res.hi <= 11);
-       NTP_ENSURE(0 <= res.lo && res.lo <= 30);
-       
        return res;
 }
 
@@ -563,8 +545,6 @@ ntpcal_rd_to_date(
        int          leaps = 0;
        int          retv  = 0;
 
-       NTP_INSIST(NULL != jd);
-
        /* get day-of-week first */
        jd->weekday = rd % 7;
        if (jd->weekday >= 7)   /* unsigned! */
@@ -585,12 +565,6 @@ ntpcal_rd_to_date(
        jd->month    = split.hi + 1;
        jd->monthday = split.lo + 1;
 
-       /* invariants */
-       NTP_ENSURE(1 <= jd->yearday  && jd->yearday  <= 366);
-       NTP_ENSURE(1 <= jd->monthday && jd->monthday <=  31);
-       NTP_ENSURE(1 <= jd->month    && jd->month    <=  12); 
-       NTP_ENSURE(0 <= jd->weekday  && jd->weekday  <= 6  );
-       
        return retv ? retv : leaps;
 }
 
@@ -607,8 +581,6 @@ ntpcal_rd_to_tm(
        ntpcal_split split;
        int          leaps = 0;
 
-       NTP_INSIST(NULL != utm);
-
        /* get day-of-week first */
        utm->tm_wday = rd % 7;
        if (utm->tm_wday < 0)
@@ -624,12 +596,6 @@ ntpcal_rd_to_tm(
        utm->tm_mon  = split.hi;        /* 0-based */
        utm->tm_mday = split.lo + 1;    /* 1-based */
 
-       /* invariants */
-       NTP_ENSURE(0 <= utm->tm_yday && utm->tm_yday <= 365);
-       NTP_ENSURE(1 <= utm->tm_mday && utm->tm_mday <= 31 );
-       NTP_ENSURE(0 <= utm->tm_mon  && utm->tm_mon  <= 11 );
-       NTP_ENSURE(0 <= utm->tm_wday && utm->tm_wday <= 6  );
-
        return leaps;
 }
 
@@ -647,8 +613,6 @@ ntpcal_daysec_to_date(
        int32 days;
        int   ts[3];
        
-       NTP_INSIST(NULL != jd);
-
        days = priv_timesplit(ts, sec);
        jd->hour   = (u_char)ts[0];
        jd->minute = (u_char)ts[1];
@@ -671,8 +635,6 @@ ntpcal_daysec_to_tm(
        int32 days;
        int   ts[3];
        
-       NTP_INSIST(NULL != utm);
-
        days = priv_timesplit(ts, sec);
        utm->tm_hour = ts[0];
        utm->tm_min  = ts[1];
@@ -697,8 +659,6 @@ ntpcal_daysplit_to_date(
        const ntpcal_split *ds ,
        int32               dof)
 {
-       NTP_INSIST(NULL != jd && NULL != ds);
-       
        dof += ntpcal_daysec_to_date(jd, ds->lo);
        return ntpcal_rd_to_date(jd, ds->hi + dof);
 }
@@ -719,8 +679,6 @@ ntpcal_daysplit_to_tm(
        const ntpcal_split *ds ,
        int32               dof)
 {
-       NTP_INSIST(NULL != utm && NULL != ds);
-
        dof += ntpcal_daysec_to_tm(utm, ds->lo);
        return ntpcal_rd_to_tm(utm, ds->hi + dof);
 }
@@ -737,8 +695,6 @@ ntpcal_time_to_date(
 {
        ntpcal_split ds;
 
-       NTP_INSIST(NULL != jd);
-
        ds = ntpcal_daysplit(ts);
        ds.hi += ntpcal_daysec_to_date(jd, ds.lo);
        ds.hi += DAY_UNIX_STARTS;
@@ -985,7 +941,6 @@ int32
 ntpcal_tm_to_rd(
        const struct tm *utm)
 {
-       NTP_INSIST(NULL != utm);
        return ntpcal_edate_to_eradays(utm->tm_year + 1899,
                                       utm->tm_mon,
                                       utm->tm_mday - 1) + 1;
@@ -1001,7 +956,6 @@ int32
 ntpcal_date_to_rd(
        const struct calendar *jd)
 {
-       NTP_INSIST(NULL != jd);
        return ntpcal_edate_to_eradays((int32)jd->year - 1,
                                       (int32)jd->month - 1,
                                       (int32)jd->monthday - 1) + 1;
@@ -1063,7 +1017,6 @@ int32
 ntpcal_date_to_daysec(
        const struct calendar *jd)
 {
-       NTP_INSIST(NULL != jd);
        return ntpcal_etime_to_seconds(jd->hour, jd->minute, jd->second);
 }
 
@@ -1076,7 +1029,6 @@ int32
 ntpcal_tm_to_daysec(
        const struct tm *utm)
 {
-       NTP_INSIST(NULL != utm);
        return ntpcal_etime_to_seconds(utm->tm_hour, utm->tm_min, utm->tm_sec);
 }
 
@@ -1096,8 +1048,6 @@ ntpcal_ntp_to_date(
        vint64       vl;
        ntpcal_split ds;
        
-       NTP_INSIST(NULL != jd);
-
        /*
         * Unfold ntp time around current time into NTP domain. Split
         * into days and seconds, shift days into CE domain and
@@ -1114,8 +1064,6 @@ u_int32
 ntpcal_date_to_ntp(
        const struct calendar *jd)
 {
-       NTP_INSIST(jd != NULL);
-
        /*
         * Convert date to NTP. Ignore yearday, use d/m/y only.
         */
@@ -1248,12 +1196,10 @@ isocal_weeks_in_years(
                cycle -= 1;
                years += 400;
        }
-       NTP_ENSURE(0 <= years  && years < 400);
 
        /* split off full centuries */
        cents = years / 100;
        years = years % 100;
-       NTP_ENSURE(0 <= cents  && cents < 4);
 
        /*
         * calculate elapsed weeks, taking into account that the
@@ -1261,7 +1207,6 @@ isocal_weeks_in_years(
         * second century falls short by one week.
         */
        weeks = (years * 53431 + bctab[cents]) / 1024;
-       NTP_ENSURE(0 <= weeks  && weeks < 5218);
 
        return cycle * GREGORIAN_CYCLE_WEEKS
             + cents * 5218 - (cents > 1)
@@ -1307,14 +1252,11 @@ isocal_split_eraweeks(
        res.lo += (res.lo >= 10435);
        cents   = res.lo / 5218;
        res.lo %= 5218;         /* res.lo is weeks in century now */
-       NTP_ENSURE(0 <= cents  && cents  <    4);
-       NTP_ENSURE(0 <= res.lo && res.lo < 5218);
        
        /* convert elapsed weeks in century to elapsed years and weeks */
        res.lo  = res.lo * 157 + bctab[cents];
        res.hi += cents * 100 + res.lo / 8192;
        res.lo  = (res.lo % 8192) / 157;        
-       NTP_ENSURE(0 <= res.lo && res.lo <= 52);
        
        return res;
 }
@@ -1334,8 +1276,6 @@ isocal_ntp_to_date(
        ntpcal_split ds;
        int          ts[3];
        
-       NTP_INSIST(NULL != id);
-
        /*
         * Unfold ntp time around current time into NTP domain. Split
         * into days and seconds, shift days into CE domain and
@@ -1377,8 +1317,6 @@ isocal_date_to_ntp(
 {
        int32 weeks, days, secs;
 
-       NTP_INSIST(NULL != id);
-
        weeks = isocal_weeks_in_years((int32)id->year - 1)
              + (int32)id->week - 1;
        days = weeks * 7 + (int32)id->weekday;
index 85ddcea89dd4d8e472e2bfc9a3dd8c2b6d18ef37..38aeedaece71c4099f751b534dc7835926df7dad 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * Copyright (C) 1992, 1996 by Rainer Pruy
- * Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
+ * Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
  *
  * This code may be modified and used freely
  * provided credits remain intact.
index bc5c2ffde599a0a630ba1c8ed69cc6dc6d649c90..2e11d424827f9ffe129d7c018849013c1d4a346d 100644 (file)
@@ -9,6 +9,7 @@ tests_SOURCES = $(top_srcdir)/sntp/tests_main.cpp       \
                atouint.cpp             \
                authkeys.cpp            \
                buftvtots.cpp           \
+               calendar.cpp            \
                caljulian.cpp           \
                caltontp.cpp            \
                calyearstart.cpp        \
diff --git a/tests/libntp/calendar.cpp b/tests/libntp/calendar.cpp
new file mode 100644 (file)
index 0000000..35b39c7
--- /dev/null
@@ -0,0 +1,337 @@
+#include "libntptest.h"
+
+extern "C" {
+#include "ntp_calendar.h"
+}
+
+#include <string>
+#include <sstream>
+
+class calendarTest : public libntptest {
+protected:
+       static int leapdays(int year);
+
+       std::string CalendarToString(const calendar &cal);
+       std::string CalendarToString(const isodate &iso);
+       ::testing::AssertionResult IsEqual(const calendar &expected, const calendar &actual);
+       ::testing::AssertionResult IsEqual(const isodate &expected, const isodate &actual);
+
+       std::string DateToString(const calendar &cal);
+       std::string DateToString(const isodate &iso);
+       ::testing::AssertionResult IsEqualDate(const calendar &expected, const calendar &actual);
+       ::testing::AssertionResult IsEqualDate(const isodate &expected, const isodate &actual);
+};
+
+
+// ---------------------------------------------------------------------
+// test support stuff
+// ---------------------------------------------------------------------
+int
+calendarTest::leapdays(int year)
+{
+       if (year % 400 == 0)
+               return 1;
+       if (year % 100 == 0)
+               return 0;
+       if (year % 4 == 0)
+               return 1;
+       return 0;
+}
+
+std::string 
+calendarTest::CalendarToString(const calendar &cal) {
+       std::ostringstream ss;
+       ss << cal.year << "-" << (u_int)cal.month << "-" << (u_int)cal.monthday
+          << " (" << cal.yearday << ") " << (u_int)cal.hour << ":"
+          << (u_int)cal.minute << ":" << (u_int)cal.second;
+       return ss.str();
+}
+
+std::string
+calendarTest:: CalendarToString(const isodate &iso) {
+       std::ostringstream ss;
+       ss << iso.year << "-" << (u_int)iso.week << "-" << (u_int)iso.weekday
+          << (u_int)iso.hour << ":" << (u_int)iso.minute << ":" << (u_int)iso.second;
+       return ss.str();
+}
+
+::testing::AssertionResult
+calendarTest:: IsEqual(const calendar &expected, const calendar &actual) {
+       if (expected.year == actual.year &&
+           (!expected.yearday || expected.yearday == actual.yearday) &&
+           expected.month == actual.month &&
+           expected.monthday == actual.monthday &&
+           expected.hour == actual.hour &&
+           expected.minute == actual.minute &&
+           expected.second == actual.second) {
+               return ::testing::AssertionSuccess();
+       } else {
+               return ::testing::AssertionFailure()
+                   << "expected: " << CalendarToString(expected) << " but was "
+                   << CalendarToString(actual);
+       }
+}
+
+::testing::AssertionResult
+calendarTest:: IsEqual(const isodate &expected, const isodate &actual) {
+       if (expected.year == actual.year &&
+           expected.week == actual.week &&
+           expected.weekday == actual.weekday &&
+           expected.hour == actual.hour &&
+           expected.minute == actual.minute &&
+           expected.second == actual.second) {
+               return ::testing::AssertionSuccess();
+       } else {
+               return ::testing::AssertionFailure()
+                   << "expected: " << CalendarToString(expected) << " but was "
+                   << CalendarToString(actual);
+       }
+}
+
+std::string
+calendarTest:: DateToString(const calendar &cal) {
+       std::ostringstream ss;
+       ss << cal.year << "-" << (u_int)cal.month << "-" << (u_int)cal.monthday
+          << " (" << cal.yearday << ")";
+       return ss.str();
+}
+
+std::string
+calendarTest:: DateToString(const isodate &iso) {
+       std::ostringstream ss;
+       ss << iso.year << "-" << (u_int)iso.week << "-" << (u_int)iso.weekday;
+       return ss.str();
+}
+
+::testing::AssertionResult
+calendarTest:: IsEqualDate(const calendar &expected, const calendar &actual) {
+       if (expected.year == actual.year &&
+           (!expected.yearday || expected.yearday == actual.yearday) &&
+           expected.month == actual.month &&
+           expected.monthday == actual.monthday) {
+               return ::testing::AssertionSuccess();
+       } else {
+               return ::testing::AssertionFailure()
+                   << "expected: " << DateToString(expected) << " but was "
+                   << DateToString(actual);
+       }
+}
+
+::testing::AssertionResult
+calendarTest:: IsEqualDate(const isodate &expected, const isodate &actual) {
+       if (expected.year == actual.year &&
+           expected.week == actual.week &&
+           expected.weekday == actual.weekday) {
+               return ::testing::AssertionSuccess();
+       } else {
+               return ::testing::AssertionFailure()
+                   << "expected: " << DateToString(expected) << " but was "
+                   << DateToString(actual);
+       }
+}
+
+
+// ---------------------------------------------------------------------
+// test cases
+// ---------------------------------------------------------------------
+static const u_short real_month_table[2][13] = {
+       /* -*- table for regular years -*- */
+       { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+       /* -*- table for leap years -*- */
+       { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
+// days in month, with one month wrap-around at both ends
+static const u_short real_month_days[2][14] = {
+       /* -*- table for regular years -*- */
+       { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 },
+       /* -*- table for leap years -*- */
+       { 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 }
+};
+
+// test the day/sec join & split ops, making sure that 32bit
+// intermediate results would definitely overflow and the hi DWORD of
+// the 'vint64' is definitely needed.
+TEST_F(calendarTest, DaySplitMerge) {
+       for (int32 day = -1000000; day <= 1000000; day += 100) {
+               for (int32 sec = -100000; sec <= 186400; sec += 10000) {
+                       vint64       merge = ntpcal_dayjoin(day, sec);
+                       ntpcal_split split = ntpcal_daysplit(&merge);
+                       int32        eday  = day;
+                       int32        esec  = sec;
+
+                       while (esec >= 86400) {
+                               eday += 1;
+                               esec -= 86400;
+                       }
+                       while (esec < 0) {
+                               eday -= 1;
+                               esec += 86400;
+                       }
+
+                       EXPECT_EQ(eday, split.hi);
+                       EXPECT_EQ(esec, split.lo);
+               }
+       }
+}
+
+TEST_F(calendarTest, SplitYearDays1) {
+       for (int32 eyd = -1; eyd <= 365; eyd++) {
+               ntpcal_split split = ntpcal_split_yeardays(eyd, 0);
+               if (split.lo >= 0 && split.hi >= 0) {
+                       EXPECT_GT(12, split.hi);
+                       EXPECT_GT(real_month_days[0][split.hi+1], split.lo);
+                       int32 tyd = real_month_table[0][split.hi] + split.lo;
+                       EXPECT_EQ(eyd, tyd);
+               } else
+                       EXPECT_TRUE(eyd < 0 || eyd > 364);
+       }
+}
+               
+TEST_F(calendarTest, SplitYearDays2) {
+       for (int32 eyd = -1; eyd <= 366; eyd++) {
+               ntpcal_split split = ntpcal_split_yeardays(eyd, 1);
+               if (split.lo >= 0 && split.hi >= 0) {
+                       EXPECT_GT(12, split.hi);
+                       EXPECT_GT(real_month_days[1][split.hi+1], split.lo);
+                       int32 tyd = real_month_table[1][split.hi] + split.lo;
+                       EXPECT_EQ(eyd, tyd);
+               } else
+                       EXPECT_TRUE(eyd < 0 || eyd > 365);
+               }
+}
+               
+TEST_F(calendarTest, RataDie1) {
+       int32    testDate = 1; // 0001-01-01 (proleptic date)
+       calendar expected = { 1, 1, 1, 1 };
+       calendar actual;
+
+       ntpcal_rd_to_date(&actual, testDate);
+       EXPECT_TRUE(IsEqualDate(expected, actual));
+}
+
+// check last day of february for first 10000 years
+TEST_F(calendarTest, LeapYears1) {
+       calendar dateIn, dateOut;
+
+       for (dateIn.year = 1; dateIn.year < 10000; ++dateIn.year) {
+               dateIn.month    = 2;
+               dateIn.monthday = 28 + leapdays(dateIn.year);
+               dateIn.yearday  = 31 + dateIn.monthday;
+
+               ntpcal_rd_to_date(&dateOut, ntpcal_date_to_rd(&dateIn));
+
+               EXPECT_TRUE(IsEqualDate(dateIn, dateOut));
+       }
+}
+
+// check first day of march for first 10000 years
+TEST_F(calendarTest, LeapYears2) {
+       calendar dateIn, dateOut;
+
+       for (dateIn.year = 1; dateIn.year < 10000; ++dateIn.year) {
+               dateIn.month    = 3;
+               dateIn.monthday = 1;
+               dateIn.yearday  = 60 + leapdays(dateIn.year);
+
+               ntpcal_rd_to_date(&dateOut, ntpcal_date_to_rd(&dateIn));
+               EXPECT_TRUE(IsEqualDate(dateIn, dateOut));
+       }
+}
+
+// Full roundtrip for 1601-01-01 to 2400-12-31
+// checks sequence of rata die numbers and validates date output
+// (since the input is all nominal days of the calendar in that range
+// and the result of the inverse calculation must match the input no
+// invalid output can occur.)
+TEST_F(calendarTest, RoundTripDate) {
+       calendar truDate, expDate = { 1600, 0, 12, 31 };;
+       int32    truRdn, expRdn = ntpcal_date_to_rd(&expDate);
+       int      leaps;
+
+       while (expDate.year < 2400) {
+               expDate.year++;
+               expDate.month   = 0;
+               expDate.yearday = 0;
+               leaps = leapdays(expDate.year);
+               while (expDate.month < 12) {
+                       expDate.month++;                        
+                       expDate.monthday = 0;
+                       while (expDate.monthday < real_month_days[leaps][expDate.month]) {
+                               expDate.monthday++;
+                               expDate.yearday++;
+                               expRdn++;
+
+                               truRdn = ntpcal_date_to_rd(&expDate);
+                               EXPECT_EQ(expRdn, truRdn);
+
+                               ntpcal_rd_to_date(&truDate, truRdn);
+                               EXPECT_TRUE(IsEqualDate(expDate, truDate));
+                       }
+               }
+       }
+}
+
+// Roundtrip testing on calyearstart
+TEST_F(calendarTest, RoundTripYearStart) {
+       static const time_t pivot = 0;
+       u_int32 ntp, expys, truys;
+       calendar date;
+
+       for (ntp = 0; ntp < 0xFFFFFFFFu - 30000000u; ntp += 30000000u) {
+               truys = calyearstart(ntp, &pivot);
+               ntpcal_ntp_to_date(&date, ntp, &pivot);
+               date.month = date.monthday = 1;
+               date.hour = date.minute = date.second = 0;
+               expys = ntpcal_date_to_ntp(&date);
+               EXPECT_EQ(expys, truys);
+       }
+}      
+
+// Roundtrip testing on calymonthstart
+TEST_F(calendarTest, RoundTripMonthStart) {
+       static const time_t pivot = 0;
+       u_int32 ntp, expms, trums;
+       calendar date;
+
+       for (ntp = 0; ntp < 0xFFFFFFFFu - 2000000u; ntp += 2000000u) {
+               trums = calmonthstart(ntp, &pivot);
+               ntpcal_ntp_to_date(&date, ntp, &pivot);
+               date.monthday = 1;
+               date.hour = date.minute = date.second = 0;
+               expms = ntpcal_date_to_ntp(&date);
+               EXPECT_EQ(expms, trums);
+       }
+}      
+
+// Roundtrip testing on calweekstart
+TEST_F(calendarTest, RoundTripWeekStart) {
+       static const time_t pivot = 0;
+       u_int32 ntp, expws, truws;
+       isodate date;
+
+       for (ntp = 0; ntp < 0xFFFFFFFFu - 600000u; ntp += 600000u) {
+               truws = calweekstart(ntp, &pivot);
+               isocal_ntp_to_date(&date, ntp, &pivot);
+               date.hour = date.minute = date.second = 0;
+               date.weekday = 1;
+               expws = isocal_date_to_ntp(&date);
+               EXPECT_EQ(expws, truws);
+       }
+}      
+
+// Roundtrip testing on caldaystart
+TEST_F(calendarTest, RoundTripDayStart) {
+       static const time_t pivot = 0;
+       u_int32 ntp, expds, truds;
+       calendar date;
+
+       for (ntp = 0; ntp < 0xFFFFFFFFu - 80000u; ntp += 80000u) {
+               truds = caldaystart(ntp, &pivot);
+               ntpcal_ntp_to_date(&date, ntp, &pivot);
+               date.hour = date.minute = date.second = 0;
+               expds = ntpcal_date_to_ntp(&date);
+               EXPECT_EQ(expds, truds);
+       }
+}      
+