From: Juergen Perlinger Date: Wed, 3 Nov 2010 18:42:16 +0000 (+0100) Subject: added calendar regression tests, fixed german umlaut mixup X-Git-Tag: NTP_4_2_7P78~5^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e96bebe8690f2e27567ea57da2683933abafd919;p=thirdparty%2Fntp.git added calendar regression tests, fixed german umlaut mixup bk: 4cd1ad08TdTs0splRg-N5J4cF8jSEg --- diff --git a/include/ntp_filegen.h b/include/ntp_filegen.h index 369489f22..c4213c46c 100644 --- a/include/ntp_filegen.h +++ b/include/ntp_filegen.h @@ -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. diff --git a/libntp/ntp_calendar.c b/libntp/ntp_calendar.c index fefd4cb5d..9bed5dc63 100644 --- a/libntp/ntp_calendar.c +++ b/libntp/ntp_calendar.c @@ -13,14 +13,6 @@ #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; diff --git a/ntpd/ntp_filegen.c b/ntpd/ntp_filegen.c index 85ddcea89..38aeedaec 100644 --- a/ntpd/ntp_filegen.c +++ b/ntpd/ntp_filegen.c @@ -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. diff --git a/tests/libntp/Makefile.am b/tests/libntp/Makefile.am index bc5c2ffde..2e11d4248 100644 --- a/tests/libntp/Makefile.am +++ b/tests/libntp/Makefile.am @@ -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 index 000000000..35b39c7e5 --- /dev/null +++ b/tests/libntp/calendar.cpp @@ -0,0 +1,337 @@ +#include "libntptest.h" + +extern "C" { +#include "ntp_calendar.h" +} + +#include +#include + +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); + } +} +