1284990Scy#include "config.h" 2284990Scy 3290000Sglebius#include "ntp_stdlib.h" /* test fail without this include, for some reason */ 4284990Scy#include "ntp_calendar.h" 5310419Sdelphij#include "ntp_unixtime.h" 6284990Scy#include "unity.h" 7284990Scy 8284990Scy#include <string.h> 9284990Scy 10284990Scystatic int leapdays(int year); 11284990Scy 12293894Sglebiusvoid setUp(void); 13293894Sglebiusint isGT(int first, int second); 14293894Sglebiusint leapdays(int year); 15293894Sglebiuschar * CalendarFromCalToString(const struct calendar *cal); 16293894Sglebiuschar * CalendarFromIsoToString(const struct isodate *iso); 17293894Sglebiusint IsEqualCal(const struct calendar *expected, const struct calendar *actual); 18293894Sglebiusint IsEqualIso(const struct isodate *expected, const struct isodate *actual); 19293894Sglebiuschar * DateFromCalToString(const struct calendar *cal); 20293894Sglebiuschar * DateFromIsoToString(const struct isodate *iso); 21293894Sglebiusint IsEqualDateCal(const struct calendar *expected, const struct calendar *actual); 22293894Sglebiusint IsEqualDateIso(const struct isodate *expected, const struct isodate *actual); 23310419Sdelphij 24293894Sglebiusvoid test_DaySplitMerge(void); 25293894Sglebiusvoid test_SplitYearDays1(void); 26293894Sglebiusvoid test_SplitYearDays2(void); 27293894Sglebiusvoid test_RataDie1(void); 28293894Sglebiusvoid test_LeapYears1(void); 29293894Sglebiusvoid test_LeapYears2(void); 30293894Sglebiusvoid test_RoundTripDate(void); 31293894Sglebiusvoid test_RoundTripYearStart(void); 32293894Sglebiusvoid test_RoundTripMonthStart(void); 33293894Sglebiusvoid test_RoundTripWeekStart(void); 34293894Sglebiusvoid test_RoundTripDayStart(void); 35293894Sglebiusvoid test_IsoCalYearsToWeeks(void); 36293894Sglebiusvoid test_IsoCalWeeksToYearStart(void); 37293894Sglebiusvoid test_IsoCalWeeksToYearEnd(void); 38293894Sglebiusvoid test_DaySecToDate(void); 39284990Scy 40310419Sdelphijvoid test_NtpToNtp(void); 41310419Sdelphijvoid test_NtpToTime(void); 42293894Sglebius 43293894Sglebiusvoid 44293894SglebiussetUp(void) 45293894Sglebius{ 46293894Sglebius init_lib(); 47293894Sglebius 48293894Sglebius return; 49293894Sglebius} 50293894Sglebius 51293894Sglebius 52290000Sglebius/* 53290000Sglebius * --------------------------------------------------------------------- 54290000Sglebius * test support stuff 55290000Sglebius * --------------------------------------------------------------------- 56290000Sglebius */ 57290000Sglebiusint 58290000SglebiusisGT(int first, int second) 59290000Sglebius{ 60293894Sglebius if(first > second) { 61290000Sglebius return TRUE; 62290000Sglebius } else { 63290000Sglebius return FALSE; 64284990Scy } 65284990Scy} 66284990Scy 67290000Sglebiusint 68290000Sglebiusleapdays(int year) 69284990Scy{ 70284990Scy if (year % 400 == 0) 71284990Scy return 1; 72284990Scy if (year % 100 == 0) 73284990Scy return 0; 74284990Scy if (year % 4 == 0) 75284990Scy return 1; 76284990Scy return 0; 77284990Scy} 78284990Scy 79290000Sglebiuschar * 80290000SglebiusCalendarFromCalToString( 81290000Sglebius const struct calendar *cal) 82290000Sglebius{ 83290000Sglebius char * str = malloc(sizeof (char) * 100); 84290000Sglebius snprintf(str, 100, "%u-%02u-%02u (%u) %02u:%02u:%02u", 85290000Sglebius cal->year, (u_int)cal->month, (u_int)cal->monthday, 86290000Sglebius cal->yearday, 87290000Sglebius (u_int)cal->hour, (u_int)cal->minute, (u_int)cal->second); 88290000Sglebius str[99] = '\0'; /* paranoia rulez! */ 89290000Sglebius return str; 90284990Scy} 91284990Scy 92290000Sglebiuschar * 93290000SglebiusCalendarFromIsoToString( 94290000Sglebius const struct isodate *iso) 95290000Sglebius{ 96290000Sglebius char * str = emalloc (sizeof (char) * 100); 97290000Sglebius snprintf(str, 100, "%u-W%02u-%02u %02u:%02u:%02u", 98290000Sglebius iso->year, (u_int)iso->week, (u_int)iso->weekday, 99290000Sglebius (u_int)iso->hour, (u_int)iso->minute, (u_int)iso->second); 100290000Sglebius str[99] = '\0'; /* paranoia rulez! */ 101290000Sglebius return str; 102284990Scy} 103284990Scy 104290000Sglebiusint 105290000SglebiusIsEqualCal( 106290000Sglebius const struct calendar *expected, 107290000Sglebius const struct calendar *actual) 108290000Sglebius{ 109290000Sglebius if (expected->year == actual->year && 110290000Sglebius (!expected->yearday || expected->yearday == actual->yearday) && 111290000Sglebius expected->month == actual->month && 112290000Sglebius expected->monthday == actual->monthday && 113290000Sglebius expected->hour == actual->hour && 114290000Sglebius expected->minute == actual->minute && 115290000Sglebius expected->second == actual->second) { 116284990Scy return TRUE; 117284990Scy } else { 118293894Sglebius char *p_exp = CalendarFromCalToString(expected); 119293894Sglebius char *p_act = CalendarFromCalToString(actual); 120293894Sglebius 121293894Sglebius printf("expected: %s but was %s", p_exp, p_act); 122293894Sglebius 123293894Sglebius free(p_exp); 124293894Sglebius free(p_act); 125293894Sglebius 126284990Scy return FALSE; 127284990Scy } 128284990Scy} 129284990Scy 130290000Sglebiusint 131290000SglebiusIsEqualIso( 132290000Sglebius const struct isodate *expected, 133290000Sglebius const struct isodate *actual) 134290000Sglebius{ 135290000Sglebius if (expected->year == actual->year && 136290000Sglebius expected->week == actual->week && 137290000Sglebius expected->weekday == actual->weekday && 138290000Sglebius expected->hour == actual->hour && 139290000Sglebius expected->minute == actual->minute && 140290000Sglebius expected->second == actual->second) { 141284990Scy return TRUE; 142284990Scy } else { 143290000Sglebius printf("expected: %s but was %s", 144290000Sglebius CalendarFromIsoToString(expected), 145290000Sglebius CalendarFromIsoToString(actual)); 146284990Scy return FALSE; 147284990Scy } 148284990Scy} 149284990Scy 150290000Sglebiuschar * 151290000SglebiusDateFromCalToString( 152290000Sglebius const struct calendar *cal) 153290000Sglebius{ 154284990Scy 155290000Sglebius char * str = emalloc (sizeof (char) * 100); 156290000Sglebius snprintf(str, 100, "%u-%02u-%02u (%u)", 157290000Sglebius cal->year, (u_int)cal->month, (u_int)cal->monthday, 158290000Sglebius cal->yearday); 159290000Sglebius str[99] = '\0'; /* paranoia rulez! */ 160290000Sglebius return str; 161284990Scy} 162284990Scy 163290000Sglebiuschar * 164290000SglebiusDateFromIsoToString( 165290000Sglebius const struct isodate *iso) 166290000Sglebius{ 167284990Scy 168290000Sglebius char * str = emalloc (sizeof (char) * 100); 169290000Sglebius snprintf(str, 100, "%u-W%02u-%02u", 170290000Sglebius iso->year, (u_int)iso->week, (u_int)iso->weekday); 171290000Sglebius str[99] = '\0'; /* paranoia rulez! */ 172290000Sglebius return str; 173284990Scy} 174284990Scy 175290000Sglebiusint/*BOOL*/ 176290000SglebiusIsEqualDateCal( 177290000Sglebius const struct calendar *expected, 178290000Sglebius const struct calendar *actual) 179290000Sglebius{ 180290000Sglebius if (expected->year == actual->year && 181290000Sglebius (!expected->yearday || expected->yearday == actual->yearday) && 182290000Sglebius expected->month == actual->month && 183290000Sglebius expected->monthday == actual->monthday) { 184284990Scy return TRUE; 185284990Scy } else { 186290000Sglebius printf("expected: %s but was %s", 187290000Sglebius DateFromCalToString(expected), 188290000Sglebius DateFromCalToString(actual)); 189284990Scy return FALSE; 190284990Scy } 191284990Scy} 192284990Scy 193290000Sglebiusint/*BOOL*/ 194290000SglebiusIsEqualDateIso( 195290000Sglebius const struct isodate *expected, 196290000Sglebius const struct isodate *actual) 197290000Sglebius{ 198290000Sglebius if (expected->year == actual->year && 199290000Sglebius expected->week == actual->week && 200290000Sglebius expected->weekday == actual->weekday) { 201284990Scy return TRUE; 202284990Scy } else { 203290000Sglebius printf("expected: %s but was %s", 204290000Sglebius DateFromIsoToString(expected), 205290000Sglebius DateFromIsoToString(actual)); 206284990Scy return FALSE; 207284990Scy } 208284990Scy} 209284990Scy 210284990Scy 211290000Sglebius/* 212290000Sglebius * --------------------------------------------------------------------- 213290000Sglebius * test cases 214290000Sglebius * --------------------------------------------------------------------- 215290000Sglebius */ 216290000Sglebius 217290000Sglebius/* days before month, with a full-year pad at the upper end */ 218284990Scystatic const u_short real_month_table[2][13] = { 219284990Scy /* -*- table for regular years -*- */ 220284990Scy { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, 221284990Scy /* -*- table for leap years -*- */ 222284990Scy { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } 223284990Scy}; 224284990Scy 225290000Sglebius/* days in month, with one month wrap-around at both ends */ 226284990Scystatic const u_short real_month_days[2][14] = { 227284990Scy /* -*- table for regular years -*- */ 228284990Scy { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 }, 229284990Scy /* -*- table for leap years -*- */ 230284990Scy { 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 } 231284990Scy}; 232284990Scy 233290000Sglebius/* test the day/sec join & split ops, making sure that 32bit 234290000Sglebius * intermediate results would definitely overflow and the hi DWORD of 235290000Sglebius * the 'vint64' is definitely needed. 236290000Sglebius */ 237290000Sglebiusvoid 238293894Sglebiustest_DaySplitMerge(void) 239293894Sglebius{ 240284990Scy int32 day,sec; 241293894Sglebius 242284990Scy for (day = -1000000; day <= 1000000; day += 100) { 243284990Scy for (sec = -100000; sec <= 186400; sec += 10000) { 244290000Sglebius vint64 merge; 245290000Sglebius ntpcal_split split; 246290000Sglebius int32 eday; 247290000Sglebius int32 esec; 248284990Scy 249290000Sglebius merge = ntpcal_dayjoin(day, sec); 250290000Sglebius split = ntpcal_daysplit(&merge); 251290000Sglebius eday = day; 252290000Sglebius esec = sec; 253290000Sglebius 254284990Scy while (esec >= 86400) { 255284990Scy eday += 1; 256284990Scy esec -= 86400; 257284990Scy } 258284990Scy while (esec < 0) { 259284990Scy eday -= 1; 260284990Scy esec += 86400; 261284990Scy } 262284990Scy 263284990Scy TEST_ASSERT_EQUAL(eday, split.hi); 264284990Scy TEST_ASSERT_EQUAL(esec, split.lo); 265284990Scy } 266284990Scy } 267293894Sglebius 268293894Sglebius return; 269284990Scy} 270284990Scy 271290000Sglebiusvoid 272293894Sglebiustest_SplitYearDays1(void) 273293894Sglebius{ 274284990Scy int32 eyd; 275293894Sglebius 276284990Scy for (eyd = -1; eyd <= 365; eyd++) { 277284990Scy ntpcal_split split = ntpcal_split_yeardays(eyd, 0); 278284990Scy if (split.lo >= 0 && split.hi >= 0) { 279290000Sglebius TEST_ASSERT_TRUE(isGT(12,split.hi)); 280290000Sglebius TEST_ASSERT_TRUE(isGT(real_month_days[0][split.hi+1], split.lo)); 281284990Scy int32 tyd = real_month_table[0][split.hi] + split.lo; 282284990Scy TEST_ASSERT_EQUAL(eyd, tyd); 283284990Scy } else 284284990Scy TEST_ASSERT_TRUE(eyd < 0 || eyd > 364); 285284990Scy } 286293894Sglebius 287293894Sglebius return; 288284990Scy} 289293894Sglebius 290290000Sglebiusvoid 291293894Sglebiustest_SplitYearDays2(void) 292293894Sglebius{ 293284990Scy int32 eyd; 294293894Sglebius 295284990Scy for (eyd = -1; eyd <= 366; eyd++) { 296284990Scy ntpcal_split split = ntpcal_split_yeardays(eyd, 1); 297284990Scy if (split.lo >= 0 && split.hi >= 0) { 298290000Sglebius /* basic checks do not work on compunds :( */ 299290000Sglebius /* would like: TEST_ASSERT_TRUE(12 > split.hi); */ 300290000Sglebius TEST_ASSERT_TRUE(isGT(12,split.hi)); 301290000Sglebius TEST_ASSERT_TRUE(isGT(real_month_days[1][split.hi+1], split.lo)); 302284990Scy int32 tyd = real_month_table[1][split.hi] + split.lo; 303284990Scy TEST_ASSERT_EQUAL(eyd, tyd); 304284990Scy } else 305284990Scy TEST_ASSERT_TRUE(eyd < 0 || eyd > 365); 306284990Scy } 307293894Sglebius 308293894Sglebius return; 309284990Scy} 310293894Sglebius 311290000Sglebiusvoid 312293894Sglebiustest_RataDie1(void) 313293894Sglebius{ 314290000Sglebius int32 testDate = 1; /* 0001-01-01 (proleptic date) */ 315284990Scy struct calendar expected = { 1, 1, 1, 1 }; 316284990Scy struct calendar actual; 317284990Scy 318284990Scy ntpcal_rd_to_date(&actual, testDate); 319290000Sglebius TEST_ASSERT_TRUE(IsEqualDateCal(&expected, &actual)); 320293894Sglebius 321293894Sglebius return; 322284990Scy} 323284990Scy 324290000Sglebius/* check last day of february for first 10000 years */ 325290000Sglebiusvoid 326293894Sglebiustest_LeapYears1(void) 327293894Sglebius{ 328284990Scy struct calendar dateIn, dateOut; 329284990Scy 330284990Scy for (dateIn.year = 1; dateIn.year < 10000; ++dateIn.year) { 331284990Scy dateIn.month = 2; 332284990Scy dateIn.monthday = 28 + leapdays(dateIn.year); 333284990Scy dateIn.yearday = 31 + dateIn.monthday; 334284990Scy 335284990Scy ntpcal_rd_to_date(&dateOut, ntpcal_date_to_rd(&dateIn)); 336284990Scy 337290000Sglebius TEST_ASSERT_TRUE(IsEqualDateCal(&dateIn, &dateOut)); 338284990Scy } 339293894Sglebius 340293894Sglebius return; 341284990Scy} 342284990Scy 343290000Sglebius/* check first day of march for first 10000 years */ 344290000Sglebiusvoid 345293894Sglebiustest_LeapYears2(void) 346293894Sglebius{ 347284990Scy struct calendar dateIn, dateOut; 348284990Scy 349284990Scy for (dateIn.year = 1; dateIn.year < 10000; ++dateIn.year) { 350284990Scy dateIn.month = 3; 351284990Scy dateIn.monthday = 1; 352284990Scy dateIn.yearday = 60 + leapdays(dateIn.year); 353284990Scy 354284990Scy ntpcal_rd_to_date(&dateOut, ntpcal_date_to_rd(&dateIn)); 355290000Sglebius TEST_ASSERT_TRUE(IsEqualDateCal(&dateIn, &dateOut)); 356284990Scy } 357293894Sglebius 358293894Sglebius return; 359284990Scy} 360284990Scy 361290000Sglebius/* Full roundtrip from 1601-01-01 to 2400-12-31 362290000Sglebius * checks sequence of rata die numbers and validates date output 363290000Sglebius * (since the input is all nominal days of the calendar in that range 364290000Sglebius * and the result of the inverse calculation must match the input no 365290000Sglebius * invalid output can occur.) 366290000Sglebius */ 367290000Sglebiusvoid 368293894Sglebiustest_RoundTripDate(void) 369293894Sglebius{ 370284990Scy struct calendar truDate, expDate = { 1600, 0, 12, 31 };; 371290000Sglebius int leaps; 372284990Scy int32 truRdn, expRdn = ntpcal_date_to_rd(&expDate); 373284990Scy 374284990Scy while (expDate.year < 2400) { 375284990Scy expDate.year++; 376284990Scy expDate.month = 0; 377284990Scy expDate.yearday = 0; 378284990Scy leaps = leapdays(expDate.year); 379284990Scy while (expDate.month < 12) { 380293894Sglebius expDate.month++; 381284990Scy expDate.monthday = 0; 382284990Scy while (expDate.monthday < real_month_days[leaps][expDate.month]) { 383284990Scy expDate.monthday++; 384284990Scy expDate.yearday++; 385284990Scy expRdn++; 386284990Scy 387284990Scy truRdn = ntpcal_date_to_rd(&expDate); 388284990Scy TEST_ASSERT_EQUAL(expRdn, truRdn); 389284990Scy 390284990Scy ntpcal_rd_to_date(&truDate, truRdn); 391290000Sglebius TEST_ASSERT_TRUE(IsEqualDateCal(&expDate, &truDate)); 392284990Scy } 393284990Scy } 394284990Scy } 395293894Sglebius 396293894Sglebius return; 397284990Scy} 398284990Scy 399290000Sglebius/* Roundtrip testing on calyearstart */ 400290000Sglebiusvoid 401293894Sglebiustest_RoundTripYearStart(void) 402293894Sglebius{ 403284990Scy static const time_t pivot = 0; 404284990Scy u_int32 ntp, expys, truys; 405284990Scy struct calendar date; 406284990Scy 407284990Scy for (ntp = 0; ntp < 0xFFFFFFFFu - 30000000u; ntp += 30000000u) { 408284990Scy truys = calyearstart(ntp, &pivot); 409284990Scy ntpcal_ntp_to_date(&date, ntp, &pivot); 410284990Scy date.month = date.monthday = 1; 411284990Scy date.hour = date.minute = date.second = 0; 412284990Scy expys = ntpcal_date_to_ntp(&date); 413284990Scy TEST_ASSERT_EQUAL(expys, truys); 414284990Scy } 415284990Scy 416293894Sglebius return; 417293894Sglebius} 418293894Sglebius 419290000Sglebius/* Roundtrip testing on calmonthstart */ 420290000Sglebiusvoid 421293894Sglebiustest_RoundTripMonthStart(void) 422293894Sglebius{ 423284990Scy static const time_t pivot = 0; 424284990Scy u_int32 ntp, expms, trums; 425284990Scy struct calendar date; 426284990Scy 427284990Scy for (ntp = 0; ntp < 0xFFFFFFFFu - 2000000u; ntp += 2000000u) { 428284990Scy trums = calmonthstart(ntp, &pivot); 429284990Scy ntpcal_ntp_to_date(&date, ntp, &pivot); 430284990Scy date.monthday = 1; 431284990Scy date.hour = date.minute = date.second = 0; 432284990Scy expms = ntpcal_date_to_ntp(&date); 433284990Scy TEST_ASSERT_EQUAL(expms, trums); 434284990Scy } 435284990Scy 436293894Sglebius return; 437293894Sglebius} 438293894Sglebius 439290000Sglebius/* Roundtrip testing on calweekstart */ 440290000Sglebiusvoid 441293894Sglebiustest_RoundTripWeekStart(void) 442293894Sglebius{ 443284990Scy static const time_t pivot = 0; 444284990Scy u_int32 ntp, expws, truws; 445284990Scy struct isodate date; 446284990Scy 447284990Scy for (ntp = 0; ntp < 0xFFFFFFFFu - 600000u; ntp += 600000u) { 448284990Scy truws = calweekstart(ntp, &pivot); 449284990Scy isocal_ntp_to_date(&date, ntp, &pivot); 450284990Scy date.hour = date.minute = date.second = 0; 451284990Scy date.weekday = 1; 452284990Scy expws = isocal_date_to_ntp(&date); 453284990Scy TEST_ASSERT_EQUAL(expws, truws); 454284990Scy } 455284990Scy 456293894Sglebius return; 457293894Sglebius} 458293894Sglebius 459290000Sglebius/* Roundtrip testing on caldaystart */ 460290000Sglebiusvoid 461293894Sglebiustest_RoundTripDayStart(void) 462293894Sglebius{ 463284990Scy static const time_t pivot = 0; 464284990Scy u_int32 ntp, expds, truds; 465284990Scy struct calendar date; 466284990Scy 467284990Scy for (ntp = 0; ntp < 0xFFFFFFFFu - 80000u; ntp += 80000u) { 468284990Scy truds = caldaystart(ntp, &pivot); 469284990Scy ntpcal_ntp_to_date(&date, ntp, &pivot); 470284990Scy date.hour = date.minute = date.second = 0; 471284990Scy expds = ntpcal_date_to_ntp(&date); 472284990Scy TEST_ASSERT_EQUAL(expds, truds); 473284990Scy } 474293894Sglebius 475293894Sglebius return; 476290000Sglebius} 477284990Scy 478290000Sglebius/* --------------------------------------------------------------------- 479290000Sglebius * ISO8601 week calendar internals 480290000Sglebius * 481290000Sglebius * The ISO8601 week calendar implementation is simple in the terms of 482290000Sglebius * the math involved, but the implementation of the calculations must 483290000Sglebius * take care of a few things like overflow, floor division, and sign 484290000Sglebius * corrections. 485290000Sglebius * 486290000Sglebius * Most of the functions are straight forward, but converting from years 487290000Sglebius * to weeks and from weeks to years warrants some extra tests. These use 488290000Sglebius * an independent reference implementation of the conversion from years 489290000Sglebius * to weeks. 490290000Sglebius * --------------------------------------------------------------------- 491290000Sglebius */ 492290000Sglebius 493290000Sglebius/* helper / reference implementation for the first week of year in the 494290000Sglebius * ISO8601 week calendar. This is based on the reference definition of 495290000Sglebius * the ISO week calendar start: The Monday closest to January,1st of the 496290000Sglebius * corresponding year in the Gregorian calendar. 497290000Sglebius */ 498290000Sglebiusstatic int32_t 499290000Sglebiusrefimpl_WeeksInIsoYears( 500290000Sglebius int32_t years) 501290000Sglebius{ 502290000Sglebius int32_t days, weeks; 503293894Sglebius 504290000Sglebius days = ntpcal_weekday_close( 505290000Sglebius ntpcal_days_in_years(years) + 1, 506290000Sglebius CAL_MONDAY) - 1; 507290000Sglebius /* the weekday functions operate on RDN, while we want elapsed 508290000Sglebius * units here -- we have to add / sub 1 in the midlle / at the 509290000Sglebius * end of the operation that gets us the first day of the ISO 510290000Sglebius * week calendar day. 511290000Sglebius */ 512290000Sglebius weeks = days / 7; 513290000Sglebius days = days % 7; 514290000Sglebius TEST_ASSERT_EQUAL(0, days); /* paranoia check... */ 515293894Sglebius 516290000Sglebius return weeks; 517290000Sglebius} 518290000Sglebius 519290000Sglebius/* The next tests loop over 5000yrs, but should still be very fast. If 520290000Sglebius * they are not, the calendar needs a better implementation... 521290000Sglebius */ 522290000Sglebiusvoid 523293894Sglebiustest_IsoCalYearsToWeeks(void) 524293894Sglebius{ 525290000Sglebius int32_t years; 526290000Sglebius int32_t wref, wcal; 527293894Sglebius 528290000Sglebius for (years = -1000; years < 4000; ++years) { 529290000Sglebius /* get number of weeks before years (reference) */ 530290000Sglebius wref = refimpl_WeeksInIsoYears(years); 531290000Sglebius /* get number of weeks before years (object-under-test) */ 532290000Sglebius wcal = isocal_weeks_in_years(years); 533290000Sglebius TEST_ASSERT_EQUAL(wref, wcal); 534290000Sglebius } 535293894Sglebius 536293894Sglebius return; 537290000Sglebius} 538290000Sglebius 539290000Sglebiusvoid 540293894Sglebiustest_IsoCalWeeksToYearStart(void) 541293894Sglebius{ 542290000Sglebius int32_t years; 543290000Sglebius int32_t wref; 544290000Sglebius ntpcal_split ysplit; 545293894Sglebius 546290000Sglebius for (years = -1000; years < 4000; ++years) { 547290000Sglebius /* get number of weeks before years (reference) */ 548290000Sglebius wref = refimpl_WeeksInIsoYears(years); 549290000Sglebius /* reverse split */ 550290000Sglebius ysplit = isocal_split_eraweeks(wref); 551290000Sglebius /* check invariants: same year, week 0 */ 552290000Sglebius TEST_ASSERT_EQUAL(years, ysplit.hi); 553290000Sglebius TEST_ASSERT_EQUAL(0, ysplit.lo); 554290000Sglebius } 555293894Sglebius 556293894Sglebius return; 557290000Sglebius} 558290000Sglebius 559290000Sglebiusvoid 560293894Sglebiustest_IsoCalWeeksToYearEnd(void) 561293894Sglebius{ 562290000Sglebius int32_t years; 563290000Sglebius int32_t wref; 564290000Sglebius ntpcal_split ysplit; 565293894Sglebius 566290000Sglebius for (years = -1000; years < 4000; ++years) { 567290000Sglebius /* get last week of previous year */ 568290000Sglebius wref = refimpl_WeeksInIsoYears(years) - 1; 569290000Sglebius /* reverse split */ 570290000Sglebius ysplit = isocal_split_eraweeks(wref); 571290000Sglebius /* check invariants: previous year, week 51 or 52 */ 572290000Sglebius TEST_ASSERT_EQUAL(years-1, ysplit.hi); 573290000Sglebius TEST_ASSERT(ysplit.lo == 51 || ysplit.lo == 52); 574290000Sglebius } 575293894Sglebius 576293894Sglebius return; 577290000Sglebius} 578290000Sglebius 579290000Sglebiusvoid 580293894Sglebiustest_DaySecToDate(void) 581293894Sglebius{ 582290000Sglebius struct calendar cal; 583290000Sglebius int32_t days; 584290000Sglebius 585290000Sglebius days = ntpcal_daysec_to_date(&cal, -86400); 586290000Sglebius TEST_ASSERT_MESSAGE((days==-1 && cal.hour==0 && cal.minute==0 && cal.second==0), 587290000Sglebius "failed for -86400"); 588290000Sglebius 589290000Sglebius days = ntpcal_daysec_to_date(&cal, -86399); 590290000Sglebius TEST_ASSERT_MESSAGE((days==-1 && cal.hour==0 && cal.minute==0 && cal.second==1), 591290000Sglebius "failed for -86399"); 592290000Sglebius 593290000Sglebius days = ntpcal_daysec_to_date(&cal, -1); 594290000Sglebius TEST_ASSERT_MESSAGE((days==-1 && cal.hour==23 && cal.minute==59 && cal.second==59), 595290000Sglebius "failed for -1"); 596290000Sglebius 597290000Sglebius days = ntpcal_daysec_to_date(&cal, 0); 598290000Sglebius TEST_ASSERT_MESSAGE((days==0 && cal.hour==0 && cal.minute==0 && cal.second==0), 599290000Sglebius "failed for 0"); 600290000Sglebius 601290000Sglebius days = ntpcal_daysec_to_date(&cal, 1); 602290000Sglebius TEST_ASSERT_MESSAGE((days==0 && cal.hour==0 && cal.minute==0 && cal.second==1), 603290000Sglebius "failed for 1"); 604290000Sglebius 605290000Sglebius days = ntpcal_daysec_to_date(&cal, 86399); 606290000Sglebius TEST_ASSERT_MESSAGE((days==0 && cal.hour==23 && cal.minute==59 && cal.second==59), 607290000Sglebius "failed for 86399"); 608290000Sglebius 609290000Sglebius days = ntpcal_daysec_to_date(&cal, 86400); 610290000Sglebius TEST_ASSERT_MESSAGE((days==1 && cal.hour==0 && cal.minute==0 && cal.second==0), 611290000Sglebius "failed for 86400"); 612293894Sglebius 613293894Sglebius return; 614290000Sglebius} 615310419Sdelphij 616310419Sdelphij/* -------------------------------------------------------------------- 617310419Sdelphij * unfolding of (truncated) NTP time stamps to full 64bit values. 618310419Sdelphij * 619310419Sdelphij * Note: These tests need a 64bit time_t to be useful. 620310419Sdelphij */ 621310419Sdelphij 622310419Sdelphijvoid 623310419Sdelphijtest_NtpToNtp(void) 624310419Sdelphij{ 625310419Sdelphij# if SIZEOF_TIME_T <= 4 626310419Sdelphij 627310419Sdelphij TEST_IGNORE_MESSAGE("test only useful for sizeof(time_t) > 4, skipped"); 628310419Sdelphij 629310419Sdelphij# else 630310419Sdelphij 631310419Sdelphij static const uint32_t ntp_vals[6] = { 632310419Sdelphij UINT32_C(0x00000000), 633310419Sdelphij UINT32_C(0x00000001), 634310419Sdelphij UINT32_C(0x7FFFFFFF), 635310419Sdelphij UINT32_C(0x80000000), 636310419Sdelphij UINT32_C(0x80000001), 637310419Sdelphij UINT32_C(0xFFFFFFFF) 638310419Sdelphij }; 639310419Sdelphij 640310419Sdelphij static char lbuf[128]; 641310419Sdelphij vint64 hold; 642310419Sdelphij time_t pivot, texp, diff; 643310419Sdelphij int loops, iloop; 644310419Sdelphij 645310419Sdelphij pivot = 0; 646310419Sdelphij for (loops = 0; loops < 16; ++loops) { 647310419Sdelphij for (iloop = 0; iloop < 6; ++iloop) { 648310419Sdelphij hold = ntpcal_ntp_to_ntp( 649310419Sdelphij ntp_vals[iloop], &pivot); 650310419Sdelphij texp = vint64_to_time(&hold); 651310419Sdelphij 652310419Sdelphij /* constraint 1: texp must be in the 653310419Sdelphij * (right-open) intervall [p-(2^31), p+(2^31)[, 654310419Sdelphij * but the pivot 'p' must be taken in full NTP 655310419Sdelphij * time scale! 656310419Sdelphij */ 657310419Sdelphij diff = texp - (pivot + JAN_1970); 658310419Sdelphij snprintf(lbuf, sizeof(lbuf), 659310419Sdelphij "bounds check: piv=%lld exp=%lld dif=%lld", 660310419Sdelphij (long long)pivot, 661310419Sdelphij (long long)texp, 662310419Sdelphij (long long)diff); 663310419Sdelphij TEST_ASSERT_MESSAGE((diff >= INT32_MIN) && (diff <= INT32_MAX), 664310419Sdelphij lbuf); 665310419Sdelphij 666310419Sdelphij /* constraint 2: low word must be equal to 667310419Sdelphij * input 668310419Sdelphij */ 669310419Sdelphij snprintf(lbuf, sizeof(lbuf), 670310419Sdelphij "low check: ntp(in)=$%08lu ntp(out[0:31])=$%08lu", 671310419Sdelphij (unsigned long)ntp_vals[iloop], 672310419Sdelphij (unsigned long)hold.D_s.lo); 673310419Sdelphij TEST_ASSERT_EQUAL_MESSAGE(ntp_vals[iloop], hold.D_s.lo, lbuf); 674310419Sdelphij } 675310419Sdelphij pivot += 0x20000000; 676310419Sdelphij } 677310419Sdelphij# endif 678310419Sdelphij} 679310419Sdelphij 680310419Sdelphijvoid 681310419Sdelphijtest_NtpToTime(void) 682310419Sdelphij{ 683310419Sdelphij# if SIZEOF_TIME_T <= 4 684310419Sdelphij 685310419Sdelphij TEST_IGNORE_MESSAGE("test only useful for sizeof(time_t) > 4, skipped"); 686310419Sdelphij 687310419Sdelphij# else 688310419Sdelphij 689310419Sdelphij static const uint32_t ntp_vals[6] = { 690310419Sdelphij UINT32_C(0x00000000), 691310419Sdelphij UINT32_C(0x00000001), 692310419Sdelphij UINT32_C(0x7FFFFFFF), 693310419Sdelphij UINT32_C(0x80000000), 694310419Sdelphij UINT32_C(0x80000001), 695310419Sdelphij UINT32_C(0xFFFFFFFF) 696310419Sdelphij }; 697310419Sdelphij 698310419Sdelphij static char lbuf[128]; 699310419Sdelphij vint64 hold; 700310419Sdelphij time_t pivot, texp, diff; 701310419Sdelphij uint32_t back; 702310419Sdelphij int loops, iloop; 703310419Sdelphij 704310419Sdelphij pivot = 0; 705310419Sdelphij for (loops = 0; loops < 16; ++loops) { 706310419Sdelphij for (iloop = 0; iloop < 6; ++iloop) { 707310419Sdelphij hold = ntpcal_ntp_to_time( 708310419Sdelphij ntp_vals[iloop], &pivot); 709310419Sdelphij texp = vint64_to_time(&hold); 710310419Sdelphij 711310419Sdelphij /* constraint 1: texp must be in the 712310419Sdelphij * (right-open) intervall [p-(2^31), p+(2^31)[ 713310419Sdelphij */ 714310419Sdelphij diff = texp - pivot; 715310419Sdelphij snprintf(lbuf, sizeof(lbuf), 716310419Sdelphij "bounds check: piv=%lld exp=%lld dif=%lld", 717310419Sdelphij (long long)pivot, 718310419Sdelphij (long long)texp, 719310419Sdelphij (long long)diff); 720310419Sdelphij TEST_ASSERT_MESSAGE((diff >= INT32_MIN) && (diff <= INT32_MAX), 721310419Sdelphij lbuf); 722310419Sdelphij 723310419Sdelphij /* constraint 2: conversion from full time back 724310419Sdelphij * to truncated NTP time must yield same result 725310419Sdelphij * as input. 726310419Sdelphij */ 727310419Sdelphij back = (uint32_t)texp + JAN_1970; 728310419Sdelphij snprintf(lbuf, sizeof(lbuf), 729310419Sdelphij "modulo check: ntp(in)=$%08lu ntp(out)=$%08lu", 730310419Sdelphij (unsigned long)ntp_vals[iloop], 731310419Sdelphij (unsigned long)back); 732310419Sdelphij TEST_ASSERT_EQUAL_MESSAGE(ntp_vals[iloop], back, lbuf); 733310419Sdelphij } 734310419Sdelphij pivot += 0x20000000; 735310419Sdelphij } 736310419Sdelphij# endif 737310419Sdelphij} 738