1 #include "config.h"
2 #include "ntp.h"
3 #include "ntp_stdlib.h"
4 #include "parse.h"
5
6 #include "unity.h"
7 #include "unity_fixture.h"
8
9 #include "caltime.h"
10
11 TEST_GROUP(calendar);
12
TEST_SETUP(calendar)13 TEST_SETUP(calendar) {}
14
TEST_TEAR_DOWN(calendar)15 TEST_TEAR_DOWN(calendar) {}
16
17
18 #include "ntp_calendar.h"
19
20 static const char *DateToString(char *, const struct calendar *);
21
DateToString(char * str,const struct calendar * cal)22 static const char *DateToString(char *str, const struct calendar *cal) {
23 snprintf(str, 255, "%hu-%u-%u(%u)\n", cal->year, (unsigned int)cal->month, (unsigned int)cal->monthday, cal->yearday);
24 return str;
25 }
26
27
IsEqualDate(const struct calendar * expected,const struct calendar * actual)28 static bool IsEqualDate(const struct calendar *expected,
29 const struct calendar *actual) {
30 char str[255];
31 char str1[255];
32 if (expected->year == actual->year &&
33 (!expected->yearday || expected->yearday == actual->yearday) &&
34 expected->month == actual->month &&
35 expected->monthday == actual->monthday) {
36 return true;
37 } else {
38 printf("Expected: %s but was %s\n",
39 DateToString(str, expected),
40 DateToString(str1, actual));
41 return false;
42 }
43 }
44
45
46 // ---------------------------------------------------------------------
47 // test cases
48 // ---------------------------------------------------------------------
49 static const unsigned short real_month_table[2][13] = {
50 /* -*- table for regular years -*- */
51 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
52 /* -*- table for leap years -*- */
53 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
54 };
55
56 // days in month, with one month wrap-around at both ends
57 static const unsigned short real_month_days[2][14] = {
58 /* -*- table for regular years -*- */
59 { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 },
60 /* -*- table for leap years -*- */
61 { 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 }
62 };
63
TEST(calendar,is_leapyear)64 TEST(calendar, is_leapyear) {
65 /* check is_leapyear() */
66 TEST_ASSERT_EQUAL(false, is_leapyear(1900));
67 TEST_ASSERT_EQUAL(false, is_leapyear(1970));
68 TEST_ASSERT_EQUAL(false, is_leapyear(1999));
69 TEST_ASSERT_EQUAL(true, is_leapyear(2000));
70 TEST_ASSERT_EQUAL(false, is_leapyear(2001));
71 TEST_ASSERT_EQUAL(true, is_leapyear(2004));
72 TEST_ASSERT_EQUAL(true, is_leapyear(2040));
73 }
74
TEST(calendar,julian0)75 TEST(calendar, julian0) {
76 /* check julian0() */
77 TEST_ASSERT_EQUAL(693961, julian0(1900));
78 TEST_ASSERT_EQUAL(719528, julian0(1970));
79 TEST_ASSERT_EQUAL(730120, julian0(1999));
80 TEST_ASSERT_EQUAL(730485, julian0(2000));
81 TEST_ASSERT_EQUAL(730851, julian0(2001));
82 TEST_ASSERT_EQUAL(745095, julian0(2040));
83 }
84
TEST(calendar,days_per_year)85 TEST(calendar, days_per_year) {
86 /* check is_leapyear() */
87 TEST_ASSERT_EQUAL(365, days_per_year(1900));
88 TEST_ASSERT_EQUAL(365, days_per_year(1970));
89 TEST_ASSERT_EQUAL(365, days_per_year(1999));
90 TEST_ASSERT_EQUAL(366, days_per_year(2000));
91 TEST_ASSERT_EQUAL(365, days_per_year(2001));
92 TEST_ASSERT_EQUAL(366, days_per_year(2004));
93 TEST_ASSERT_EQUAL(366, days_per_year(2040));
94 }
95
96 #ifdef CLOCK_GENERIC
TEST(calendar,parse_to_unixtime)97 TEST(calendar, parse_to_unixtime) {
98 /* check is_leapyear() */
99 clocktime_t ct;
100 time_t result;
101 unsigned long Flag;
102
103 ct.day = 1;
104 ct.month = 1;
105 ct.year = 1970;
106 ct.hour = ct.minute = ct.second = ct.usecond = 0;
107 ct.utcoffset = 0;
108 ct.utctime = 0;
109 ct.flags = 0;
110
111 Flag = 0;
112 result = parse_to_unixtime( &ct, &Flag );
113
114 TEST_ASSERT_EQUAL(0, result);
115
116 ct.year = 2000;
117 ct.hour = 2;
118 ct.utctime = 0;
119 result = parse_to_unixtime( &ct, &Flag );
120 TEST_ASSERT_EQUAL(946692000L, result);
121
122 ct.year = 2037;
123 ct.minute = 2;
124 ct.second = 3;
125 ct.utctime = 0;
126 result = parse_to_unixtime( &ct, &Flag );
127 TEST_ASSERT_EQUAL(2114388123L, result);
128 }
129 #endif
130
TEST(calendar,PeriodicExtend1)131 TEST(calendar, PeriodicExtend1) {
132 // Test positive cycle, pivot > value
133 TEST_ASSERT_EQUAL(1001, ntpcal_periodic_extend(1000, 5, 2));
134 // Test positive cycle, pivot < value
135 TEST_ASSERT_EQUAL(6, ntpcal_periodic_extend(5, 1000, 2));
136 // Test negative cycle, pivot > value
137 TEST_ASSERT_EQUAL(999, ntpcal_periodic_extend(1000, 5, -2));
138 // Test negative cycle, pivot < value
139 TEST_ASSERT_EQUAL(4, ntpcal_periodic_extend(5, 1000, -2));
140 }
141
142 // test the NTP to 64-bit Unix scale time conversion
TEST(calendar,NtpToTime1)143 TEST(calendar, NtpToTime1) {
144 TEST_ASSERT_EQUAL(2085978538, ntpcal_ntp_to_time(42, 23));
145 }
146
147 // test the NTP to 64-bit NTP scale time conversion
TEST(calendar,NtpToNtp1)148 TEST(calendar, NtpToNtp1) {
149 TEST_ASSERT_EQUAL(4294967338, ntpcal_ntp_to_ntp(42, 23));
150 }
151
152 // test the day/sec join & split ops, making sure that 32bit
153 // intermediate results would definitely overflow and the hi DWORD of
154 // the 'time64_t' is definitely needed.
TEST(calendar,DaySplitMerge)155 TEST(calendar, DaySplitMerge) {
156 int32_t day;
157 int32_t sec;
158
159 for (day = -1000000; day <= 1000000; day += 100) {
160 for (sec = -100000; sec <= 186400; sec += 10000) {
161 time64_t merge = ntpcal_dayjoin(day, sec);
162 ntpcal_split split = ntpcal_daysplit(merge);
163 int32_t eday = day;
164 int32_t esec = sec;
165
166 while (esec >= 86400) {
167 eday += 1;
168 esec -= 86400;
169 }
170 while (esec < 0) {
171 eday -= 1;
172 esec += 86400;
173 }
174
175 TEST_ASSERT_EQUAL(eday, split.hi);
176 TEST_ASSERT_EQUAL(esec, split.lo);
177 }
178 }
179 }
180
TEST(calendar,SplitEraDays1)181 TEST(calendar, SplitEraDays1) {
182 ntpcal_split res;
183 int32_t isleapyear = 42;
184
185 // Test no flag, no-leap, positive
186 res = ntpcal_split_eradays(4, NULL);
187 TEST_ASSERT_EQUAL(0, res.hi);
188 TEST_ASSERT_EQUAL(4, res.lo);
189 TEST_ASSERT_EQUAL(42, isleapyear);
190
191 // Test flag, no-leap, positive
192 res = ntpcal_split_eradays(4, &isleapyear);
193 TEST_ASSERT_EQUAL(0, res.hi);
194 TEST_ASSERT_EQUAL(4, res.lo);
195 TEST_ASSERT_EQUAL(0, isleapyear);
196
197 // Test flag, leap, positive
198 res = ntpcal_split_eradays(1400, &isleapyear);
199 TEST_ASSERT_EQUAL(3, res.hi);
200 TEST_ASSERT_EQUAL(305, res.lo);
201 TEST_ASSERT_EQUAL(1, isleapyear);
202
203 isleapyear = 0;
204
205 // Test flag, leap, negative
206 res = ntpcal_split_eradays(-100, &isleapyear);
207 TEST_ASSERT_EQUAL(-1, res.hi);
208 TEST_ASSERT_EQUAL(266, res.lo);
209 TEST_ASSERT_EQUAL(1, isleapyear);
210 }
211
TEST(calendar,SplitYearDays1)212 TEST(calendar, SplitYearDays1) {
213 int32_t eyd;
214
215 for (eyd = -1; eyd <= 365; eyd++) {
216 ntpcal_split split = ntpcal_split_yeardays(eyd, 0);
217 if (split.lo >= 0 && split.hi >= 0) {
218 TEST_ASSERT_LESS_THAN_INT32(12, split.hi);
219 TEST_ASSERT_LESS_THAN_INT32(real_month_days[0][split.hi+1], split.lo);
220 int32_t tyd = real_month_table[0][split.hi] + split.lo;
221 TEST_ASSERT_EQUAL(eyd, tyd);
222 } else
223 TEST_ASSERT_TRUE(eyd < 0 || eyd > 364);
224 }
225 }
226
TEST(calendar,SplitYearDays2)227 TEST(calendar, SplitYearDays2) {
228 int32_t eyd;
229
230 for (eyd = -1; eyd <= 366; eyd++) {
231 ntpcal_split split = ntpcal_split_yeardays(eyd, 1);
232 if (split.lo >= 0 && split.hi >= 0) {
233 TEST_ASSERT_LESS_THAN_INT32(12, split.hi);
234 TEST_ASSERT_LESS_THAN_INT32(real_month_days[1][split.hi+1], split.lo);
235 int32_t tyd = real_month_table[1][split.hi] + split.lo;
236 TEST_ASSERT_EQUAL(eyd, tyd);
237 } else
238 TEST_ASSERT_TRUE(eyd < 0 || eyd > 365);
239 }
240 }
241
TEST(calendar,RataDie1)242 TEST(calendar, RataDie1) {
243 int32_t testDate = 1; // 0001-01-01 (proleptic date)
244 struct calendar expected = { 1, 1, 1, 1, 0, 0, 0, 0};
245 struct calendar actual;
246
247 ntpcal_rd_to_date(&actual, testDate);
248 TEST_ASSERT_TRUE(IsEqualDate(&expected, &actual));
249 }
250
TEST(calendar,DaysecToDate1)251 TEST(calendar, DaysecToDate1) {
252 struct calendar cal;
253 int32_t days;
254
255 // Test normal date
256 days = ntpcal_daysec_to_date(&cal, 100000);
257 TEST_ASSERT_EQUAL(days, 1);
258 TEST_ASSERT_EQUAL(cal.hour, 3);
259 TEST_ASSERT_EQUAL(cal.minute, 46);
260 TEST_ASSERT_EQUAL(cal.second, 40);
261
262 // Test negative date
263 days = ntpcal_daysec_to_date(&cal, -100000);
264 TEST_ASSERT_EQUAL(-2, days);
265 TEST_ASSERT_EQUAL(20, cal.hour);
266 TEST_ASSERT_EQUAL(13, cal.minute);
267 TEST_ASSERT_EQUAL(20, cal.second);
268 }
269
TEST(calendar,TimeToDate1)270 TEST(calendar, TimeToDate1) {
271 struct calendar jd = {0, 0, 0, 0, 0, 0, 0, 0};
272 int res;
273
274 res = ntpcal_time_to_date(&jd, 1000000);
275 TEST_ASSERT_EQUAL(0, res);
276 TEST_ASSERT_EQUAL(1970, jd.year);
277 TEST_ASSERT_EQUAL(12, jd.yearday);
278 TEST_ASSERT_EQUAL(1, jd.month);
279 TEST_ASSERT_EQUAL(12, jd.monthday);
280 TEST_ASSERT_EQUAL(13, jd.hour);
281 TEST_ASSERT_EQUAL(46, jd.minute);
282 TEST_ASSERT_EQUAL(40, jd.second);
283 TEST_ASSERT_EQUAL(1, jd.weekday);
284 }
285
TEST(calendar,DayJoin1)286 TEST(calendar, DayJoin1) {
287 TEST_ASSERT_EQUAL(4323600, ntpcal_dayjoin(50, 3600));
288 }
289
TEST(calendar,DaysInYears1)290 TEST(calendar, DaysInYears1) {
291 // Test positive less than one gregorian cycle of years
292 TEST_ASSERT_EQUAL(109572, ntpcal_days_in_years(300));
293 // Test positive one gregorian cycle of years
294 TEST_ASSERT_EQUAL(146097, ntpcal_days_in_years(400));
295 // Test positive greater than one gregorian cycle of years
296 TEST_ASSERT_EQUAL(182621, ntpcal_days_in_years(500));
297 // Test negative less than one gregorian cycle of years
298 TEST_ASSERT_EQUAL(-109573, ntpcal_days_in_years(-300));
299 // Test negative one gregorian cycle of years
300 TEST_ASSERT_EQUAL(-146097, ntpcal_days_in_years(-400));
301 // Test negative greater than one gregorian cycle of years
302 TEST_ASSERT_EQUAL(-182622, ntpcal_days_in_years(-500));
303 }
304
TEST(calendar,EdateToEradays1)305 TEST(calendar, EdateToEradays1) {
306 // Test positive, no months
307 TEST_ASSERT_EQUAL(1827, ntpcal_edate_to_eradays(5, 0, 1));
308 // Test positive, with months
309 TEST_ASSERT_EQUAL(1917, ntpcal_edate_to_eradays(5, 3, 1));
310 // Test negative, no months
311 TEST_ASSERT_EQUAL(-1828, ntpcal_edate_to_eradays(-5, 0, -1));
312 // Test negative, with months
313 TEST_ASSERT_EQUAL(-1920, ntpcal_edate_to_eradays(-5, -3, -1));
314 }
315
TEST(calendar,EtimeToSeconds1)316 TEST(calendar, EtimeToSeconds1) {
317 TEST_ASSERT_EQUAL(18181, ntpcal_etime_to_seconds(5, 3, 1));
318 }
319
TEST(calendar,TmToRd1)320 TEST(calendar, TmToRd1) {
321 struct tm utm;
322
323 utm.tm_year = 10;
324 utm.tm_mon = 5;
325 utm.tm_mday = 1;
326 TEST_ASSERT_EQUAL(697399, ntpcal_tm_to_rd(&utm));
327 }
328
329 // check last day of february for first 10000 years
TEST(calendar,LeapYears1)330 TEST(calendar, LeapYears1) {
331 struct calendar dateIn, dateOut;
332
333 for (dateIn.year = 1; dateIn.year < 10000; ++dateIn.year) {
334 dateIn.month = 2;
335 dateIn.monthday = is_leapyear(dateIn.year) ? 29 : 28;
336 dateIn.yearday = 31 + dateIn.monthday;
337
338 ntpcal_rd_to_date(&dateOut, ntpcal_date_to_rd(&dateIn));
339
340 TEST_ASSERT_TRUE(IsEqualDate(&dateIn, &dateOut));
341 }
342 }
343
344 // check first day of march for first 10000 years
TEST(calendar,LeapYears2)345 TEST(calendar, LeapYears2) {
346 struct calendar dateIn, dateOut;
347
348 for (dateIn.year = 1; dateIn.year < 10000; ++dateIn.year) {
349 dateIn.month = 3;
350 dateIn.monthday = 1;
351 dateIn.yearday = is_leapyear(dateIn.year) ? 61 : 60;
352
353 ntpcal_rd_to_date(&dateOut, ntpcal_date_to_rd(&dateIn));
354 TEST_ASSERT_TRUE(IsEqualDate(&dateIn, &dateOut));
355 }
356 }
357
358 // Full roundtrip for 1601-01-01 to 2400-12-31
359 // checks sequence of rata die numbers and validates date output
360 // (since the input is all nominal days of the calendar in that range
361 // and the result of the inverse calculation must match the input no
362 // invalid output can occur.)
TEST(calendar,RoundTripDate)363 TEST(calendar, RoundTripDate) {
364 struct calendar truDate, expDate = { 1600, 0, 12, 31, 0, 0, 0, 0};
365 int32_t truRdn, expRdn = ntpcal_date_to_rd(&expDate);
366 int leaps;
367
368 while (expDate.year < 2400) {
369 expDate.year++;
370 expDate.month = 0;
371 expDate.yearday = 0;
372 leaps = is_leapyear(expDate.year) ? 1 : 0;
373 while (expDate.month < 12) {
374 expDate.month++;
375 expDate.monthday = 0;
376 while (expDate.monthday < real_month_days[leaps][expDate.month]) {
377 expDate.monthday++;
378 expDate.yearday++;
379 expRdn++;
380
381 truRdn = ntpcal_date_to_rd(&expDate);
382 TEST_ASSERT_EQUAL(expRdn, truRdn);
383
384 ntpcal_rd_to_date(&truDate, truRdn);
385 TEST_ASSERT_TRUE(IsEqualDate(&expDate, &truDate));
386 }
387 }
388 }
389 }
390
TEST(calendar,DateToDaysec1)391 TEST(calendar, DateToDaysec1) {
392 struct calendar jd;
393
394 jd.hour = 18;
395 jd.minute = 45;
396 jd.second = 15;
397 TEST_ASSERT_EQUAL(67515, ntpcal_date_to_daysec(&jd));
398 }
399
TEST(calendar,TmToDaysec1)400 TEST(calendar, TmToDaysec1) {
401 struct tm utm;
402
403 utm.tm_hour = 18;
404 utm.tm_min = 45;
405 utm.tm_sec = 15;
406 TEST_ASSERT_EQUAL(67515, ntpcal_tm_to_daysec(&utm));
407 }
408
TEST(calendar,DateToTime1)409 TEST(calendar, DateToTime1) {
410 struct calendar jd;
411
412 jd.year = 2000;
413 jd.month = 2;
414 jd.monthday = 4;
415 jd.hour = 8;
416 jd.minute = 16;
417 jd.second = 32;
418 TEST_ASSERT_EQUAL(949652192, ntpcal_date_to_time(&jd));
419 }
420
TEST(calendar,Ntp64ToDate1)421 TEST(calendar, Ntp64ToDate1) {
422 struct calendar jd;
423
424 TEST_ASSERT_EQUAL(0, ntpcal_ntp64_to_date(&jd, 10000000));
425 TEST_ASSERT_EQUAL(1900, jd.year);
426 TEST_ASSERT_EQUAL(4, jd.month);
427 TEST_ASSERT_EQUAL(26, jd.monthday);
428 TEST_ASSERT_EQUAL(17, jd.hour);
429 TEST_ASSERT_EQUAL(46, jd.minute);
430 TEST_ASSERT_EQUAL(40, jd.second);
431 }
432
TEST(calendar,NtpToDate1)433 TEST(calendar, NtpToDate1) {
434 struct calendar jd;
435
436 TEST_ASSERT_EQUAL(1, ntpcal_ntp_to_date(&jd, 86400, 1000000));
437 TEST_ASSERT_EQUAL(2036, jd.year);
438 TEST_ASSERT_EQUAL(2, jd.month);
439 TEST_ASSERT_EQUAL(8, jd.monthday);
440 TEST_ASSERT_EQUAL(6, jd.hour);
441 TEST_ASSERT_EQUAL(28, jd.minute);
442 TEST_ASSERT_EQUAL(16, jd.second);
443 }
444
445
TEST_GROUP_RUNNER(calendar)446 TEST_GROUP_RUNNER(calendar) {
447 RUN_TEST_CASE(calendar, is_leapyear);
448 RUN_TEST_CASE(calendar, julian0);
449 RUN_TEST_CASE(calendar, days_per_year);
450 #ifdef CLOCK_GENERIC
451 RUN_TEST_CASE(calendar, parse_to_unixtime);
452 #endif
453 RUN_TEST_CASE(calendar, PeriodicExtend1);
454 RUN_TEST_CASE(calendar, NtpToTime1);
455 RUN_TEST_CASE(calendar, NtpToNtp1);
456 RUN_TEST_CASE(calendar, DaySplitMerge);
457 RUN_TEST_CASE(calendar, DaysecToDate1);
458 RUN_TEST_CASE(calendar, SplitEraDays1);
459 RUN_TEST_CASE(calendar, SplitYearDays1);
460 RUN_TEST_CASE(calendar, SplitYearDays2);
461 RUN_TEST_CASE(calendar, RataDie1);
462 RUN_TEST_CASE(calendar, TimeToDate1);
463 RUN_TEST_CASE(calendar, DayJoin1);
464 RUN_TEST_CASE(calendar, DaysInYears1);
465 RUN_TEST_CASE(calendar, EdateToEradays1);
466 RUN_TEST_CASE(calendar, EtimeToSeconds1);
467 RUN_TEST_CASE(calendar, TmToRd1);
468 RUN_TEST_CASE(calendar, LeapYears1);
469 RUN_TEST_CASE(calendar, LeapYears2);
470 RUN_TEST_CASE(calendar, RoundTripDate);
471 RUN_TEST_CASE(calendar, DateToDaysec1);
472 RUN_TEST_CASE(calendar, TmToDaysec1);
473 RUN_TEST_CASE(calendar, DateToTime1);
474 RUN_TEST_CASE(calendar, Ntp64ToDate1);
475 RUN_TEST_CASE(calendar, NtpToDate1);
476 }
477