1284990Scy#include "config.h" 2284990Scy 3289997Sglebius#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 12293650Sglebiusvoid setUp(void); 13293650Sglebiusint isGT(int first, int second); 14293650Sglebiusint leapdays(int year); 15293650Sglebiuschar * CalendarFromCalToString(const struct calendar *cal); 16293650Sglebiuschar * CalendarFromIsoToString(const struct isodate *iso); 17293650Sglebiusint IsEqualCal(const struct calendar *expected, const struct calendar *actual); 18293650Sglebiusint IsEqualIso(const struct isodate *expected, const struct isodate *actual); 19293650Sglebiuschar * DateFromCalToString(const struct calendar *cal); 20293650Sglebiuschar * DateFromIsoToString(const struct isodate *iso); 21293650Sglebiusint IsEqualDateCal(const struct calendar *expected, const struct calendar *actual); 22293650Sglebiusint IsEqualDateIso(const struct isodate *expected, const struct isodate *actual); 23310419Sdelphij 24293650Sglebiusvoid test_DaySplitMerge(void); 25293650Sglebiusvoid test_SplitYearDays1(void); 26293650Sglebiusvoid test_SplitYearDays2(void); 27293650Sglebiusvoid test_RataDie1(void); 28293650Sglebiusvoid test_LeapYears1(void); 29293650Sglebiusvoid test_LeapYears2(void); 30293650Sglebiusvoid test_RoundTripDate(void); 31293650Sglebiusvoid test_RoundTripYearStart(void); 32293650Sglebiusvoid test_RoundTripMonthStart(void); 33293650Sglebiusvoid test_RoundTripWeekStart(void); 34293650Sglebiusvoid test_RoundTripDayStart(void); 35293650Sglebiusvoid test_IsoCalYearsToWeeks(void); 36293650Sglebiusvoid test_IsoCalWeeksToYearStart(void); 37293650Sglebiusvoid test_IsoCalWeeksToYearEnd(void); 38293650Sglebiusvoid test_DaySecToDate(void); 39284990Scy 40310419Sdelphijvoid test_NtpToNtp(void); 41310419Sdelphijvoid test_NtpToTime(void); 42293650Sglebius 43293650Sglebiusvoid 44293650SglebiussetUp(void) 45293650Sglebius{ 46293650Sglebius init_lib(); 47293650Sglebius 48293650Sglebius return; 49293650Sglebius} 50293650Sglebius 51293650Sglebius 52289997Sglebius/* 53289997Sglebius * --------------------------------------------------------------------- 54289997Sglebius * test support stuff 55289997Sglebius * --------------------------------------------------------------------- 56289997Sglebius */ 57289997Sglebiusint 58289997SglebiusisGT(int first, int second) 59289997Sglebius{ 60293650Sglebius if(first > second) { 61289997Sglebius return TRUE; 62289997Sglebius } else { 63289997Sglebius return FALSE; 64284990Scy } 65284990Scy} 66284990Scy 67289997Sglebiusint 68289997Sglebiusleapdays(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 79289997Sglebiuschar * 80289997SglebiusCalendarFromCalToString( 81289997Sglebius const struct calendar *cal) 82289997Sglebius{ 83289997Sglebius char * str = malloc(sizeof (char) * 100); 84289997Sglebius snprintf(str, 100, "%u-%02u-%02u (%u) %02u:%02u:%02u", 85289997Sglebius cal->year, (u_int)cal->month, (u_int)cal->monthday, 86289997Sglebius cal->yearday, 87289997Sglebius (u_int)cal->hour, (u_int)cal->minute, (u_int)cal->second); 88289997Sglebius str[99] = '\0'; /* paranoia rulez! */ 89289997Sglebius return str; 90284990Scy} 91284990Scy 92289997Sglebiuschar * 93289997SglebiusCalendarFromIsoToString( 94289997Sglebius const struct isodate *iso) 95289997Sglebius{ 96289997Sglebius char * str = emalloc (sizeof (char) * 100); 97289997Sglebius snprintf(str, 100, "%u-W%02u-%02u %02u:%02u:%02u", 98289997Sglebius iso->year, (u_int)iso->week, (u_int)iso->weekday, 99289997Sglebius (u_int)iso->hour, (u_int)iso->minute, (u_int)iso->second); 100289997Sglebius str[99] = '\0'; /* paranoia rulez! */ 101289997Sglebius return str; 102284990Scy} 103284990Scy 104289997Sglebiusint 105289997SglebiusIsEqualCal( 106289997Sglebius const struct calendar *expected, 107289997Sglebius const struct calendar *actual) 108289997Sglebius{ 109289997Sglebius if (expected->year == actual->year && 110289997Sglebius (!expected->yearday || expected->yearday == actual->yearday) && 111289997Sglebius expected->month == actual->month && 112289997Sglebius expected->monthday == actual->monthday && 113289997Sglebius expected->hour == actual->hour && 114289997Sglebius expected->minute == actual->minute && 115289997Sglebius expected->second == actual->second) { 116284990Scy return TRUE; 117284990Scy } else { 118293650Sglebius char *p_exp = CalendarFromCalToString(expected); 119293650Sglebius char *p_act = CalendarFromCalToString(actual); 120293650Sglebius 121293650Sglebius printf("expected: %s but was %s", p_exp, p_act); 122293650Sglebius 123293650Sglebius free(p_exp); 124293650Sglebius free(p_act); 125293650Sglebius 126284990Scy return FALSE; 127284990Scy } 128284990Scy} 129284990Scy 130289997Sglebiusint 131289997SglebiusIsEqualIso( 132289997Sglebius const struct isodate *expected, 133289997Sglebius const struct isodate *actual) 134289997Sglebius{ 135289997Sglebius if (expected->year == actual->year && 136289997Sglebius expected->week == actual->week && 137289997Sglebius expected->weekday == actual->weekday && 138289997Sglebius expected->hour == actual->hour && 139289997Sglebius expected->minute == actual->minute && 140289997Sglebius expected->second == actual->second) { 141284990Scy return TRUE; 142284990Scy } else { 143289997Sglebius printf("expected: %s but was %s", 144289997Sglebius CalendarFromIsoToString(expected), 145289997Sglebius CalendarFromIsoToString(actual)); 146284990Scy return FALSE; 147284990Scy } 148284990Scy} 149284990Scy 150289997Sglebiuschar * 151289997SglebiusDateFromCalToString( 152289997Sglebius const struct calendar *cal) 153289997Sglebius{ 154284990Scy 155289997Sglebius char * str = emalloc (sizeof (char) * 100); 156289997Sglebius snprintf(str, 100, "%u-%02u-%02u (%u)", 157289997Sglebius cal->year, (u_int)cal->month, (u_int)cal->monthday, 158289997Sglebius cal->yearday); 159289997Sglebius str[99] = '\0'; /* paranoia rulez! */ 160289997Sglebius return str; 161284990Scy} 162284990Scy 163289997Sglebiuschar * 164289997SglebiusDateFromIsoToString( 165289997Sglebius const struct isodate *iso) 166289997Sglebius{ 167284990Scy 168289997Sglebius char * str = emalloc (sizeof (char) * 100); 169289997Sglebius snprintf(str, 100, "%u-W%02u-%02u", 170289997Sglebius iso->year, (u_int)iso->week, (u_int)iso->weekday); 171289997Sglebius str[99] = '\0'; /* paranoia rulez! */ 172289997Sglebius return str; 173284990Scy} 174284990Scy 175289997Sglebiusint/*BOOL*/ 176289997SglebiusIsEqualDateCal( 177289997Sglebius const struct calendar *expected, 178289997Sglebius const struct calendar *actual) 179289997Sglebius{ 180289997Sglebius if (expected->year == actual->year && 181289997Sglebius (!expected->yearday || expected->yearday == actual->yearday) && 182289997Sglebius expected->month == actual->month && 183289997Sglebius expected->monthday == actual->monthday) { 184284990Scy return TRUE; 185284990Scy } else { 186289997Sglebius printf("expected: %s but was %s", 187289997Sglebius DateFromCalToString(expected), 188289997Sglebius DateFromCalToString(actual)); 189284990Scy return FALSE; 190284990Scy } 191284990Scy} 192284990Scy 193289997Sglebiusint/*BOOL*/ 194289997SglebiusIsEqualDateIso( 195289997Sglebius const struct isodate *expected, 196289997Sglebius const struct isodate *actual) 197289997Sglebius{ 198289997Sglebius if (expected->year == actual->year && 199289997Sglebius expected->week == actual->week && 200289997Sglebius expected->weekday == actual->weekday) { 201284990Scy return TRUE; 202284990Scy } else { 203289997Sglebius printf("expected: %s but was %s", 204289997Sglebius DateFromIsoToString(expected), 205289997Sglebius DateFromIsoToString(actual)); 206284990Scy return FALSE; 207284990Scy } 208284990Scy} 209284990Scy 210284990Scy 211289997Sglebius/* 212289997Sglebius * --------------------------------------------------------------------- 213289997Sglebius * test cases 214289997Sglebius * --------------------------------------------------------------------- 215289997Sglebius */ 216289997Sglebius 217289997Sglebius/* 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 225289997Sglebius/* 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 233289997Sglebius/* test the day/sec join & split ops, making sure that 32bit 234289997Sglebius * intermediate results would definitely overflow and the hi DWORD of 235289997Sglebius * the 'vint64' is definitely needed. 236289997Sglebius */ 237289997Sglebiusvoid 238293650Sglebiustest_DaySplitMerge(void) 239293650Sglebius{ 240284990Scy int32 day,sec; 241293650Sglebius 242284990Scy for (day = -1000000; day <= 1000000; day += 100) { 243284990Scy for (sec = -100000; sec <= 186400; sec += 10000) { 244289997Sglebius vint64 merge; 245289997Sglebius ntpcal_split split; 246289997Sglebius int32 eday; 247289997Sglebius int32 esec; 248284990Scy 249289997Sglebius merge = ntpcal_dayjoin(day, sec); 250289997Sglebius split = ntpcal_daysplit(&merge); 251289997Sglebius eday = day; 252289997Sglebius esec = sec; 253289997Sglebius 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 } 267293650Sglebius 268293650Sglebius return; 269284990Scy} 270284990Scy 271289997Sglebiusvoid 272293650Sglebiustest_SplitYearDays1(void) 273293650Sglebius{ 274284990Scy int32 eyd; 275293650Sglebius 276284990Scy for (eyd = -1; eyd <= 365; eyd++) { 277284990Scy ntpcal_split split = ntpcal_split_yeardays(eyd, 0); 278284990Scy if (split.lo >= 0 && split.hi >= 0) { 279289997Sglebius TEST_ASSERT_TRUE(isGT(12,split.hi)); 280289997Sglebius 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 } 286293650Sglebius 287293650Sglebius return; 288284990Scy} 289293650Sglebius 290289997Sglebiusvoid 291293650Sglebiustest_SplitYearDays2(void) 292293650Sglebius{ 293284990Scy int32 eyd; 294293650Sglebius 295284990Scy for (eyd = -1; eyd <= 366; eyd++) { 296284990Scy ntpcal_split split = ntpcal_split_yeardays(eyd, 1); 297284990Scy if (split.lo >= 0 && split.hi >= 0) { 298289997Sglebius /* basic checks do not work on compunds :( */ 299289997Sglebius /* would like: TEST_ASSERT_TRUE(12 > split.hi); */ 300289997Sglebius TEST_ASSERT_TRUE(isGT(12,split.hi)); 301289997Sglebius 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 } 307293650Sglebius 308293650Sglebius return; 309284990Scy} 310293650Sglebius 311289997Sglebiusvoid 312293650Sglebiustest_RataDie1(void) 313293650Sglebius{ 314289997Sglebius 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); 319289997Sglebius TEST_ASSERT_TRUE(IsEqualDateCal(&expected, &actual)); 320293650Sglebius 321293650Sglebius return; 322284990Scy} 323284990Scy 324289997Sglebius/* check last day of february for first 10000 years */ 325289997Sglebiusvoid 326293650Sglebiustest_LeapYears1(void) 327293650Sglebius{ 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 337289997Sglebius TEST_ASSERT_TRUE(IsEqualDateCal(&dateIn, &dateOut)); 338284990Scy } 339293650Sglebius 340293650Sglebius return; 341284990Scy} 342284990Scy 343289997Sglebius/* check first day of march for first 10000 years */ 344289997Sglebiusvoid 345293650Sglebiustest_LeapYears2(void) 346293650Sglebius{ 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)); 355289997Sglebius TEST_ASSERT_TRUE(IsEqualDateCal(&dateIn, &dateOut)); 356284990Scy } 357293650Sglebius 358293650Sglebius return; 359284990Scy} 360284990Scy 361289997Sglebius/* Full roundtrip from 1601-01-01 to 2400-12-31 362289997Sglebius * checks sequence of rata die numbers and validates date output 363289997Sglebius * (since the input is all nominal days of the calendar in that range 364289997Sglebius * and the result of the inverse calculation must match the input no 365289997Sglebius * invalid output can occur.) 366289997Sglebius */ 367289997Sglebiusvoid 368293650Sglebiustest_RoundTripDate(void) 369293650Sglebius{ 370284990Scy struct calendar truDate, expDate = { 1600, 0, 12, 31 };; 371289997Sglebius 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) { 380293650Sglebius 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); 391289997Sglebius TEST_ASSERT_TRUE(IsEqualDateCal(&expDate, &truDate)); 392284990Scy } 393284990Scy } 394284990Scy } 395293650Sglebius 396293650Sglebius return; 397284990Scy} 398284990Scy 399289997Sglebius/* Roundtrip testing on calyearstart */ 400289997Sglebiusvoid 401293650Sglebiustest_RoundTripYearStart(void) 402293650Sglebius{ 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 416293650Sglebius return; 417293650Sglebius} 418293650Sglebius 419289997Sglebius/* Roundtrip testing on calmonthstart */ 420289997Sglebiusvoid 421293650Sglebiustest_RoundTripMonthStart(void) 422293650Sglebius{ 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 436293650Sglebius return; 437293650Sglebius} 438293650Sglebius 439289997Sglebius/* Roundtrip testing on calweekstart */ 440289997Sglebiusvoid 441293650Sglebiustest_RoundTripWeekStart(void) 442293650Sglebius{ 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 456293650Sglebius return; 457293650Sglebius} 458293650Sglebius 459289997Sglebius/* Roundtrip testing on caldaystart */ 460289997Sglebiusvoid 461293650Sglebiustest_RoundTripDayStart(void) 462293650Sglebius{ 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 } 474293650Sglebius 475293650Sglebius return; 476289997Sglebius} 477284990Scy 478289997Sglebius/* --------------------------------------------------------------------- 479289997Sglebius * ISO8601 week calendar internals 480289997Sglebius * 481289997Sglebius * The ISO8601 week calendar implementation is simple in the terms of 482289997Sglebius * the math involved, but the implementation of the calculations must 483289997Sglebius * take care of a few things like overflow, floor division, and sign 484289997Sglebius * corrections. 485289997Sglebius * 486289997Sglebius * Most of the functions are straight forward, but converting from years 487289997Sglebius * to weeks and from weeks to years warrants some extra tests. These use 488289997Sglebius * an independent reference implementation of the conversion from years 489289997Sglebius * to weeks. 490289997Sglebius * --------------------------------------------------------------------- 491289997Sglebius */ 492289997Sglebius 493289997Sglebius/* helper / reference implementation for the first week of year in the 494289997Sglebius * ISO8601 week calendar. This is based on the reference definition of 495289997Sglebius * the ISO week calendar start: The Monday closest to January,1st of the 496289997Sglebius * corresponding year in the Gregorian calendar. 497289997Sglebius */ 498289997Sglebiusstatic int32_t 499289997Sglebiusrefimpl_WeeksInIsoYears( 500289997Sglebius int32_t years) 501289997Sglebius{ 502289997Sglebius int32_t days, weeks; 503293650Sglebius 504289997Sglebius days = ntpcal_weekday_close( 505289997Sglebius ntpcal_days_in_years(years) + 1, 506289997Sglebius CAL_MONDAY) - 1; 507289997Sglebius /* the weekday functions operate on RDN, while we want elapsed 508289997Sglebius * units here -- we have to add / sub 1 in the midlle / at the 509289997Sglebius * end of the operation that gets us the first day of the ISO 510289997Sglebius * week calendar day. 511289997Sglebius */ 512289997Sglebius weeks = days / 7; 513289997Sglebius days = days % 7; 514289997Sglebius TEST_ASSERT_EQUAL(0, days); /* paranoia check... */ 515293650Sglebius 516289997Sglebius return weeks; 517289997Sglebius} 518289997Sglebius 519289997Sglebius/* The next tests loop over 5000yrs, but should still be very fast. If 520289997Sglebius * they are not, the calendar needs a better implementation... 521289997Sglebius */ 522289997Sglebiusvoid 523293650Sglebiustest_IsoCalYearsToWeeks(void) 524293650Sglebius{ 525289997Sglebius int32_t years; 526289997Sglebius int32_t wref, wcal; 527293650Sglebius 528289997Sglebius for (years = -1000; years < 4000; ++years) { 529289997Sglebius /* get number of weeks before years (reference) */ 530289997Sglebius wref = refimpl_WeeksInIsoYears(years); 531289997Sglebius /* get number of weeks before years (object-under-test) */ 532289997Sglebius wcal = isocal_weeks_in_years(years); 533289997Sglebius TEST_ASSERT_EQUAL(wref, wcal); 534289997Sglebius } 535293650Sglebius 536293650Sglebius return; 537289997Sglebius} 538289997Sglebius 539289997Sglebiusvoid 540293650Sglebiustest_IsoCalWeeksToYearStart(void) 541293650Sglebius{ 542289997Sglebius int32_t years; 543289997Sglebius int32_t wref; 544289997Sglebius ntpcal_split ysplit; 545293650Sglebius 546289997Sglebius for (years = -1000; years < 4000; ++years) { 547289997Sglebius /* get number of weeks before years (reference) */ 548289997Sglebius wref = refimpl_WeeksInIsoYears(years); 549289997Sglebius /* reverse split */ 550289997Sglebius ysplit = isocal_split_eraweeks(wref); 551289997Sglebius /* check invariants: same year, week 0 */ 552289997Sglebius TEST_ASSERT_EQUAL(years, ysplit.hi); 553289997Sglebius TEST_ASSERT_EQUAL(0, ysplit.lo); 554289997Sglebius } 555293650Sglebius 556293650Sglebius return; 557289997Sglebius} 558289997Sglebius 559289997Sglebiusvoid 560293650Sglebiustest_IsoCalWeeksToYearEnd(void) 561293650Sglebius{ 562289997Sglebius int32_t years; 563289997Sglebius int32_t wref; 564289997Sglebius ntpcal_split ysplit; 565293650Sglebius 566289997Sglebius for (years = -1000; years < 4000; ++years) { 567289997Sglebius /* get last week of previous year */ 568289997Sglebius wref = refimpl_WeeksInIsoYears(years) - 1; 569289997Sglebius /* reverse split */ 570289997Sglebius ysplit = isocal_split_eraweeks(wref); 571289997Sglebius /* check invariants: previous year, week 51 or 52 */ 572289997Sglebius TEST_ASSERT_EQUAL(years-1, ysplit.hi); 573289997Sglebius TEST_ASSERT(ysplit.lo == 51 || ysplit.lo == 52); 574289997Sglebius } 575293650Sglebius 576293650Sglebius return; 577289997Sglebius} 578289997Sglebius 579289997Sglebiusvoid 580293650Sglebiustest_DaySecToDate(void) 581293650Sglebius{ 582289997Sglebius struct calendar cal; 583289997Sglebius int32_t days; 584289997Sglebius 585289997Sglebius days = ntpcal_daysec_to_date(&cal, -86400); 586289997Sglebius TEST_ASSERT_MESSAGE((days==-1 && cal.hour==0 && cal.minute==0 && cal.second==0), 587289997Sglebius "failed for -86400"); 588289997Sglebius 589289997Sglebius days = ntpcal_daysec_to_date(&cal, -86399); 590289997Sglebius TEST_ASSERT_MESSAGE((days==-1 && cal.hour==0 && cal.minute==0 && cal.second==1), 591289997Sglebius "failed for -86399"); 592289997Sglebius 593289997Sglebius days = ntpcal_daysec_to_date(&cal, -1); 594289997Sglebius TEST_ASSERT_MESSAGE((days==-1 && cal.hour==23 && cal.minute==59 && cal.second==59), 595289997Sglebius "failed for -1"); 596289997Sglebius 597289997Sglebius days = ntpcal_daysec_to_date(&cal, 0); 598289997Sglebius TEST_ASSERT_MESSAGE((days==0 && cal.hour==0 && cal.minute==0 && cal.second==0), 599289997Sglebius "failed for 0"); 600289997Sglebius 601289997Sglebius days = ntpcal_daysec_to_date(&cal, 1); 602289997Sglebius TEST_ASSERT_MESSAGE((days==0 && cal.hour==0 && cal.minute==0 && cal.second==1), 603289997Sglebius "failed for 1"); 604289997Sglebius 605289997Sglebius days = ntpcal_daysec_to_date(&cal, 86399); 606289997Sglebius TEST_ASSERT_MESSAGE((days==0 && cal.hour==23 && cal.minute==59 && cal.second==59), 607289997Sglebius "failed for 86399"); 608289997Sglebius 609289997Sglebius days = ntpcal_daysec_to_date(&cal, 86400); 610289997Sglebius TEST_ASSERT_MESSAGE((days==1 && cal.hour==0 && cal.minute==0 && cal.second==0), 611289997Sglebius "failed for 86400"); 612293650Sglebius 613293650Sglebius return; 614289997Sglebius} 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