xref: /netbsd-src/external/bsd/ntp/dist/tests/libntp/calendar.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1 /*	$NetBSD: calendar.c,v 1.3 2024/08/18 20:47:26 christos Exp $	*/
2 
3 #include "config.h"
4 
5 #include "ntp_stdlib.h" /* test fail without this include, for some reason */
6 #include "ntp_calendar.h"
7 #include "ntp_calgps.h"
8 #include "ntp_unixtime.h"
9 #include "ntp_fp.h"
10 #include "unity.h"
11 
12 #include <string.h>
13 
14 static char mbuf[128];
15 
16 static int leapdays(int year);
17 
18 void	setUp(void);
19 int	isGT(int first, int second);
20 int	leapdays(int year);
21 char *	CalendarFromCalToString(const struct calendar *cal);
22 char *	CalendarFromIsoToString(const struct isodate *iso);
23 int	IsEqualCal(const struct calendar *expected, const struct calendar *actual);
24 int	IsEqualIso(const struct isodate *expected, const struct isodate *actual);
25 char *	DateFromCalToString(const struct calendar *cal);
26 char *	DateFromIsoToString(const struct isodate *iso);
27 int	IsEqualDateCal(const struct calendar *expected, const struct calendar *actual);
28 int	IsEqualDateIso(const struct isodate *expected, const struct isodate *actual);
29 
30 void	test_Constants(void);
31 void	test_DaySplitMerge(void);
32 void	test_WeekSplitMerge(void);
33 void	test_SplitYearDays1(void);
34 void	test_SplitYearDays2(void);
35 void	test_SplitEraDays(void);
36 void	test_SplitEraWeeks(void);
37 void	test_RataDie1(void);
38 void	test_LeapYears1(void);
39 void	test_LeapYears2(void);
40 void	test_LeapYears3(void);
41 void	test_RoundTripDate(void);
42 void	test_RoundTripYearStart(void);
43 void	test_RoundTripMonthStart(void);
44 void	test_RoundTripWeekStart(void);
45 void	test_RoundTripDayStart(void);
46 void	test_IsoCalYearsToWeeks(void);
47 void	test_IsoCalWeeksToYearStart(void);
48 void	test_IsoCalWeeksToYearEnd(void);
49 void	test_DaySecToDate(void);
50 void	test_GpsRollOver(void);
51 void	test_GpsRemapFunny(void);
52 
53 void	test_GpsNtpFixpoints(void);
54 void	test_NtpToNtp(void);
55 void	test_NtpToTime(void);
56 
57 void	test_CalUMod7(void);
58 void	test_CalIMod7(void);
59 void	test_RellezCentury1_1(void);
60 void	test_RellezCentury3_1(void);
61 void	test_RellezYearZero(void);
62 
63 
64 void
65 setUp(void)
66 {
67 	init_lib();
68 
69 	return;
70 }
71 
72 
73 /*
74  * ---------------------------------------------------------------------
75  * test support stuff
76  * ---------------------------------------------------------------------
77  */
78 int
79 isGT(int first, int second)
80 {
81 	if(first > second) {
82 		return TRUE;
83 	} else {
84 		return FALSE;
85 	}
86 }
87 
88 int
89 leapdays(int year)
90 {
91 	if (year % 400 == 0)
92 		return 1;
93 	if (year % 100 == 0)
94 		return 0;
95 	if (year % 4 == 0)
96 		return 1;
97 	return 0;
98 }
99 
100 char *
101 CalendarFromCalToString(
102     const struct calendar *cal)
103 {
104 	char * str = malloc(sizeof (char) * 100);
105 	snprintf(str, 100, "%u-%02u-%02u (%u) %02u:%02u:%02u",
106 		 cal->year, (u_int)cal->month, (u_int)cal->monthday,
107 		 cal->yearday,
108 		 (u_int)cal->hour, (u_int)cal->minute, (u_int)cal->second);
109 	str[99] = '\0'; /* paranoia rulez! */
110 	return str;
111 }
112 
113 char *
114 CalendarFromIsoToString(
115 	const struct isodate *iso)
116 {
117 	char * str = emalloc (sizeof (char) * 100);
118 	snprintf(str, 100, "%u-W%02u-%02u %02u:%02u:%02u",
119 		 iso->year, (u_int)iso->week, (u_int)iso->weekday,
120 		 (u_int)iso->hour, (u_int)iso->minute, (u_int)iso->second);
121 	str[99] = '\0'; /* paranoia rulez! */
122 	return str;
123 }
124 
125 int
126 IsEqualCal(
127 	const struct calendar *expected,
128 	const struct calendar *actual)
129 {
130 	if (expected->year == actual->year &&
131 	    (!expected->yearday || expected->yearday == actual->yearday) &&
132 	    expected->month == actual->month &&
133 	    expected->monthday == actual->monthday &&
134 	    expected->hour == actual->hour &&
135 	    expected->minute == actual->minute &&
136 	    expected->second == actual->second) {
137 		return TRUE;
138 	} else {
139 		char *p_exp = CalendarFromCalToString(expected);
140 		char *p_act = CalendarFromCalToString(actual);
141 
142 		printf("expected: %s but was %s", p_exp, p_act);
143 
144 		free(p_exp);
145 		free(p_act);
146 
147 		return FALSE;
148 	}
149 }
150 
151 int
152 IsEqualIso(
153 	const struct isodate *expected,
154 	const struct isodate *actual)
155 {
156 	if (expected->year == actual->year &&
157 	    expected->week == actual->week &&
158 	    expected->weekday == actual->weekday &&
159 	    expected->hour == actual->hour &&
160 	    expected->minute == actual->minute &&
161 	    expected->second == actual->second) {
162 		return TRUE;
163 	} else {
164 		printf("expected: %s but was %s",
165 		       CalendarFromIsoToString(expected),
166 		       CalendarFromIsoToString(actual));
167 		return FALSE;
168 	}
169 }
170 
171 char *
172 DateFromCalToString(
173 	const struct calendar *cal)
174 {
175 
176 	char * str = emalloc (sizeof (char) * 100);
177 	snprintf(str, 100, "%u-%02u-%02u (%u)",
178 		 cal->year, (u_int)cal->month, (u_int)cal->monthday,
179 		 cal->yearday);
180 	str[99] = '\0'; /* paranoia rulez! */
181 	return str;
182 }
183 
184 char *
185 DateFromIsoToString(
186 	const struct isodate *iso)
187 {
188 
189 	char * str = emalloc (sizeof (char) * 100);
190 	snprintf(str, 100, "%u-W%02u-%02u",
191 		 iso->year, (u_int)iso->week, (u_int)iso->weekday);
192 	str[99] = '\0'; /* paranoia rulez! */
193 	return str;
194 }
195 
196 int/*BOOL*/
197 IsEqualDateCal(
198 	const struct calendar *expected,
199 	const struct calendar *actual)
200 {
201 	if (expected->year == actual->year &&
202 	    (!expected->yearday || expected->yearday == actual->yearday) &&
203 	    expected->month == actual->month &&
204 	    expected->monthday == actual->monthday) {
205 		return TRUE;
206 	} else {
207 		printf("expected: %s but was %s",
208 		       DateFromCalToString(expected),
209 		       DateFromCalToString(actual));
210 		return FALSE;
211 	}
212 }
213 
214 int/*BOOL*/
215 IsEqualDateIso(
216 	const struct isodate *expected,
217 	const struct isodate *actual)
218 {
219 	if (expected->year == actual->year &&
220 	    expected->week == actual->week &&
221 	    expected->weekday == actual->weekday) {
222 		return TRUE;
223 	} else {
224 		printf("expected: %s but was %s",
225 		       DateFromIsoToString(expected),
226 		       DateFromIsoToString(actual));
227 		return FALSE;
228 	}
229 }
230 
231 static int/*BOOL*/
232 strToCal(
233 	struct calendar * jd,
234 	const char * str
235 	)
236 {
237 	unsigned short y,m,d, H,M,S;
238 
239 	if (6 == sscanf(str, "%hu-%2hu-%2huT%2hu:%2hu:%2hu",
240 			&y, &m, &d, &H, &M, &S)) {
241 		memset(jd, 0, sizeof(*jd));
242 		jd->year     = y;
243 		jd->month    = (uint8_t)m;
244 		jd->monthday = (uint8_t)d;
245 		jd->hour     = (uint8_t)H;
246 		jd->minute   = (uint8_t)M;
247 		jd->second   = (uint8_t)S;
248 
249 		return TRUE;
250 	}
251 	return FALSE;
252 }
253 
254 /*
255  * ---------------------------------------------------------------------
256  * test cases
257  * ---------------------------------------------------------------------
258  */
259 
260 /* days before month, with a full-year pad at the upper end */
261 static const u_short real_month_table[2][13] = {
262 	/* -*- table for regular years -*- */
263 	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
264 	/* -*- table for leap years -*- */
265 	{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
266 };
267 
268 /* days in month, with one month wrap-around at both ends */
269 static const u_short real_month_days[2][14] = {
270 	/* -*- table for regular years -*- */
271 	{ 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 },
272 	/* -*- table for leap years -*- */
273 	{ 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31 }
274 };
275 
276 void
277 test_Constants(void)
278 {
279 	int32_t		rdn;
280 	struct calendar	jdn;
281 
282 	jdn.year     = 1900;
283 	jdn.month    = 1;
284 	jdn.monthday = 1;
285 	rdn = ntpcal_date_to_rd(&jdn);
286 	TEST_ASSERT_EQUAL_MESSAGE(DAY_NTP_STARTS, rdn, "(NTP EPOCH)");
287 
288 	jdn.year     = 1980;
289 	jdn.month    = 1;
290 	jdn.monthday = 6;
291 	rdn = ntpcal_date_to_rd(&jdn);
292 	TEST_ASSERT_EQUAL_MESSAGE(DAY_GPS_STARTS, rdn, "(GPS EPOCH)");
293 }
294 
295 /* test the day/sec join & split ops, making sure that 32bit
296  * intermediate results would definitely overflow and the hi DWORD of
297  * the 'vint64' is definitely needed.
298  */
299 void
300 test_DaySplitMerge(void)
301 {
302 	int32 day,sec;
303 
304 	for (day = -1000000; day <= 1000000; day += 100) {
305 		for (sec = -100000; sec <= 186400; sec += 10000) {
306 			vint64		merge;
307 			ntpcal_split	split;
308 			int32		eday;
309 			int32		esec;
310 
311 			merge = ntpcal_dayjoin(day, sec);
312 			split = ntpcal_daysplit(&merge);
313 			eday  = day;
314 			esec  = sec;
315 
316 			while (esec >= 86400) {
317 				eday += 1;
318 				esec -= 86400;
319 			}
320 			while (esec < 0) {
321 				eday -= 1;
322 				esec += 86400;
323 			}
324 
325 			TEST_ASSERT_EQUAL(eday, split.hi);
326 			TEST_ASSERT_EQUAL(esec, split.lo);
327 		}
328 	}
329 
330 	return;
331 }
332 
333 void
334 test_WeekSplitMerge(void)
335 {
336 	int32 wno,sec;
337 
338 	for (wno = -1000000; wno <= 1000000; wno += 100) {
339 		for (sec = -100000; sec <= 2*SECSPERWEEK; sec += 10000) {
340 			vint64		merge;
341 			ntpcal_split	split;
342 			int32		ewno;
343 			int32		esec;
344 
345 			merge = ntpcal_weekjoin(wno, sec);
346 			split = ntpcal_weeksplit(&merge);
347 			ewno  = wno;
348 			esec  = sec;
349 
350 			while (esec >= SECSPERWEEK) {
351 				ewno += 1;
352 				esec -= SECSPERWEEK;
353 			}
354 			while (esec < 0) {
355 				ewno -= 1;
356 				esec += SECSPERWEEK;
357 			}
358 
359 			TEST_ASSERT_EQUAL(ewno, split.hi);
360 			TEST_ASSERT_EQUAL(esec, split.lo);
361 		}
362 	}
363 
364 	return;
365 }
366 
367 void
368 test_SplitYearDays1(void)
369 {
370 	int32 eyd;
371 
372 	for (eyd = -1; eyd <= 365; eyd++) {
373 		ntpcal_split split = ntpcal_split_yeardays(eyd, 0);
374 		if (split.lo >= 0 && split.hi >= 0) {
375 			TEST_ASSERT_TRUE(isGT(12,split.hi));
376 			TEST_ASSERT_TRUE(isGT(real_month_days[0][split.hi+1], split.lo));
377 			int32 tyd = real_month_table[0][split.hi] + split.lo;
378 			TEST_ASSERT_EQUAL(eyd, tyd);
379 		} else
380 			TEST_ASSERT_TRUE(eyd < 0 || eyd > 364);
381 	}
382 
383 	return;
384 }
385 
386 void
387 test_SplitYearDays2(void)
388 {
389 	int32 eyd;
390 
391 	for (eyd = -1; eyd <= 366; eyd++) {
392 		ntpcal_split split = ntpcal_split_yeardays(eyd, 1);
393 		if (split.lo >= 0 && split.hi >= 0) {
394 			/* basic checks do not work on compunds :( */
395 			/* would like: TEST_ASSERT_TRUE(12 > split.hi); */
396 			TEST_ASSERT_TRUE(isGT(12,split.hi));
397 			TEST_ASSERT_TRUE(isGT(real_month_days[1][split.hi+1], split.lo));
398 			int32 tyd = real_month_table[1][split.hi] + split.lo;
399 			TEST_ASSERT_EQUAL(eyd, tyd);
400 		} else
401 			TEST_ASSERT_TRUE(eyd < 0 || eyd > 365);
402 		}
403 
404 	return;
405 }
406 
407 void
408 test_SplitEraDays(void)
409 {
410 	int32_t		ed, rd;
411 	ntpcal_split	sd;
412 	for (ed = -10000; ed < 1000000; ++ed) {
413 		sd = ntpcal_split_eradays(ed, NULL);
414 		rd = ntpcal_days_in_years(sd.hi) + sd.lo;
415 		TEST_ASSERT_EQUAL(ed, rd);
416 		TEST_ASSERT_TRUE(0 <= sd.lo && sd.lo <= 365);
417 	}
418 }
419 
420 void
421 test_SplitEraWeeks(void)
422 {
423 	int32_t		ew, rw;
424 	ntpcal_split	sw;
425 	for (ew = -10000; ew < 1000000; ++ew) {
426 		sw = isocal_split_eraweeks(ew);
427 		rw = isocal_weeks_in_years(sw.hi) + sw.lo;
428 		TEST_ASSERT_EQUAL(ew, rw);
429 		TEST_ASSERT_TRUE(0 <= sw.lo && sw.lo <= 52);
430 	}
431 }
432 
433 void
434 test_RataDie1(void)
435 {
436 	int32	 testDate = 1; /* 0001-01-01 (proleptic date) */
437 	struct calendar expected = { 1, 1, 1, 1 };
438 	struct calendar actual;
439 
440 	ntpcal_rd_to_date(&actual, testDate);
441 	TEST_ASSERT_TRUE(IsEqualDateCal(&expected, &actual));
442 
443 	return;
444 }
445 
446 /* check last day of february for first 10000 years */
447 void
448 test_LeapYears1(void)
449 {
450 	struct calendar dateIn, dateOut;
451 
452 	for (dateIn.year = 1; dateIn.year < 10000; ++dateIn.year) {
453 		dateIn.month	= 2;
454 		dateIn.monthday = 28 + leapdays(dateIn.year);
455 		dateIn.yearday	= 31 + dateIn.monthday;
456 
457 		ntpcal_rd_to_date(&dateOut, ntpcal_date_to_rd(&dateIn));
458 
459 		TEST_ASSERT_TRUE(IsEqualDateCal(&dateIn, &dateOut));
460 	}
461 
462 	return;
463 }
464 
465 /* check first day of march for first 10000 years */
466 void
467 test_LeapYears2(void)
468 {
469 	struct calendar dateIn, dateOut;
470 
471 	for (dateIn.year = 1; dateIn.year < 10000; ++dateIn.year) {
472 		dateIn.month	= 3;
473 		dateIn.monthday = 1;
474 		dateIn.yearday	= 60 + leapdays(dateIn.year);
475 
476 		ntpcal_rd_to_date(&dateOut, ntpcal_date_to_rd(&dateIn));
477 		TEST_ASSERT_TRUE(IsEqualDateCal(&dateIn, &dateOut));
478 	}
479 
480 	return;
481 }
482 
483 /* check the 'is_leapyear()' implementation for 4400 years */
484 void
485 test_LeapYears3(void)
486 {
487 	int32_t year;
488 	int     l1, l2;
489 
490 	for (year = -399; year < 4000; ++year) {
491 		l1 = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
492 		l2 = is_leapyear(year);
493 		snprintf(mbuf, sizeof(mbuf), "y=%d", year);
494 		TEST_ASSERT_EQUAL_MESSAGE(l1, l2, mbuf);
495 	}
496 }
497 
498 /* Full roundtrip from 1601-01-01 to 2400-12-31
499  * checks sequence of rata die numbers and validates date output
500  * (since the input is all nominal days of the calendar in that range
501  * and the result of the inverse calculation must match the input no
502  * invalid output can occur.)
503  */
504 void
505 test_RoundTripDate(void)
506 {
507 	struct calendar truDate, expDate = { 1600, 0, 12, 31 };;
508 	int	 leaps;
509 	int32	 truRdn, expRdn	= ntpcal_date_to_rd(&expDate);
510 
511 	while (expDate.year < 2400) {
512 		expDate.year++;
513 		expDate.month	= 0;
514 		expDate.yearday = 0;
515 		leaps = leapdays(expDate.year);
516 		while (expDate.month < 12) {
517 			expDate.month++;
518 			expDate.monthday = 0;
519 			while (expDate.monthday < real_month_days[leaps][expDate.month]) {
520 				expDate.monthday++;
521 				expDate.yearday++;
522 				expRdn++;
523 
524 				truRdn = ntpcal_date_to_rd(&expDate);
525 				TEST_ASSERT_EQUAL(expRdn, truRdn);
526 
527 				ntpcal_rd_to_date(&truDate, truRdn);
528 				TEST_ASSERT_TRUE(IsEqualDateCal(&expDate, &truDate));
529 			}
530 		}
531 	}
532 
533 	return;
534 }
535 
536 /* Roundtrip testing on calyearstart */
537 void
538 test_RoundTripYearStart(void)
539 {
540 	static const time_t pivot = 0;
541 	u_int32 ntp, expys, truys;
542 	struct calendar date;
543 
544 	for (ntp = 0; ntp < 0xFFFFFFFFu - 30000000u; ntp += 30000000u) {
545 		truys = calyearstart(ntp, &pivot);
546 		ntpcal_ntp_to_date(&date, ntp, &pivot);
547 		date.month = date.monthday = 1;
548 		date.hour = date.minute = date.second = 0;
549 		expys = ntpcal_date_to_ntp(&date);
550 		TEST_ASSERT_EQUAL(expys, truys);
551 	}
552 
553 	return;
554 }
555 
556 /* Roundtrip testing on calmonthstart */
557 void
558 test_RoundTripMonthStart(void)
559 {
560 	static const time_t pivot = 0;
561 	u_int32 ntp, expms, trums;
562 	struct calendar date;
563 
564 	for (ntp = 0; ntp < 0xFFFFFFFFu - 2000000u; ntp += 2000000u) {
565 		trums = calmonthstart(ntp, &pivot);
566 		ntpcal_ntp_to_date(&date, ntp, &pivot);
567 		date.monthday = 1;
568 		date.hour = date.minute = date.second = 0;
569 		expms = ntpcal_date_to_ntp(&date);
570 		TEST_ASSERT_EQUAL(expms, trums);
571 	}
572 
573 	return;
574 }
575 
576 /* Roundtrip testing on calweekstart */
577 void
578 test_RoundTripWeekStart(void)
579 {
580 	static const time_t pivot = 0;
581 	u_int32 ntp, expws, truws;
582 	struct isodate date;
583 
584 	for (ntp = 0; ntp < 0xFFFFFFFFu - 600000u; ntp += 600000u) {
585 		truws = calweekstart(ntp, &pivot);
586 		isocal_ntp_to_date(&date, ntp, &pivot);
587 		date.hour = date.minute = date.second = 0;
588 		date.weekday = 1;
589 		expws = isocal_date_to_ntp(&date);
590 		TEST_ASSERT_EQUAL(expws, truws);
591 	}
592 
593 	return;
594 }
595 
596 /* Roundtrip testing on caldaystart */
597 void
598 test_RoundTripDayStart(void)
599 {
600 	static const time_t pivot = 0;
601 	u_int32 ntp, expds, truds;
602 	struct calendar date;
603 
604 	for (ntp = 0; ntp < 0xFFFFFFFFu - 80000u; ntp += 80000u) {
605 		truds = caldaystart(ntp, &pivot);
606 		ntpcal_ntp_to_date(&date, ntp, &pivot);
607 		date.hour = date.minute = date.second = 0;
608 		expds = ntpcal_date_to_ntp(&date);
609 		TEST_ASSERT_EQUAL(expds, truds);
610 	}
611 
612 	return;
613 }
614 
615 /* ---------------------------------------------------------------------
616  * ISO8601 week calendar internals
617  *
618  * The ISO8601 week calendar implementation is simple in the terms of
619  * the math involved, but the implementation of the calculations must
620  * take care of a few things like overflow, floor division, and sign
621  * corrections.
622  *
623  * Most of the functions are straight forward, but converting from years
624  * to weeks and from weeks to years warrants some extra tests. These use
625  * an independent reference implementation of the conversion from years
626  * to weeks.
627  * ---------------------------------------------------------------------
628  */
629 
630 /* helper / reference implementation for the first week of year in the
631  * ISO8601 week calendar. This is based on the reference definition of
632  * the ISO week calendar start: The Monday closest to January,1st of the
633  * corresponding year in the Gregorian calendar.
634  */
635 static int32_t
636 refimpl_WeeksInIsoYears(
637 	int32_t years)
638 {
639 	int32_t days, weeks;
640 
641 	days = ntpcal_weekday_close(
642 		ntpcal_days_in_years(years) + 1,
643 		CAL_MONDAY) - 1;
644 	/* the weekday functions operate on RDN, while we want elapsed
645 	 * units here -- we have to add / sub 1 in the midlle / at the
646 	 * end of the operation that gets us the first day of the ISO
647 	 * week calendar day.
648 	 */
649 	weeks = days / 7;
650 	days  = days % 7;
651 	TEST_ASSERT_EQUAL(0, days); /* paranoia check... */
652 
653 	return weeks;
654 }
655 
656 /* The next tests loop over 5000yrs, but should still be very fast. If
657  * they are not, the calendar needs a better implementation...
658  */
659 void
660 test_IsoCalYearsToWeeks(void)
661 {
662 	int32_t years;
663 	int32_t wref, wcal;
664 
665 	for (years = -1000; years < 4000; ++years) {
666 		/* get number of weeks before years (reference) */
667 		wref = refimpl_WeeksInIsoYears(years);
668 		/* get number of weeks before years (object-under-test) */
669 		wcal = isocal_weeks_in_years(years);
670 		TEST_ASSERT_EQUAL(wref, wcal);
671 	}
672 
673 	return;
674 }
675 
676 void
677 test_IsoCalWeeksToYearStart(void)
678 {
679 	int32_t years;
680 	int32_t wref;
681 	ntpcal_split ysplit;
682 
683 	for (years = -1000; years < 4000; ++years) {
684 		/* get number of weeks before years (reference) */
685 		wref = refimpl_WeeksInIsoYears(years);
686 		/* reverse split */
687 		ysplit = isocal_split_eraweeks(wref);
688 		/* check invariants: same year, week 0 */
689 		TEST_ASSERT_EQUAL(years, ysplit.hi);
690 		TEST_ASSERT_EQUAL(0, ysplit.lo);
691 	}
692 
693 	return;
694 }
695 
696 void
697 test_IsoCalWeeksToYearEnd(void)
698 {
699 	int32_t years;
700 	int32_t wref;
701 	ntpcal_split ysplit;
702 
703 	for (years = -1000; years < 4000; ++years) {
704 		/* get last week of previous year */
705 		wref = refimpl_WeeksInIsoYears(years) - 1;
706 		/* reverse split */
707 		ysplit = isocal_split_eraweeks(wref);
708 		/* check invariants: previous year, week 51 or 52 */
709 		TEST_ASSERT_EQUAL(years-1, ysplit.hi);
710 		TEST_ASSERT(ysplit.lo == 51 || ysplit.lo == 52);
711 	}
712 
713 	return;
714 }
715 
716 void
717 test_DaySecToDate(void)
718 {
719 	struct calendar cal;
720 	int32_t days;
721 
722 	days = ntpcal_daysec_to_date(&cal, -86400);
723 	TEST_ASSERT_MESSAGE((days==-1 && cal.hour==0 && cal.minute==0 && cal.second==0),
724 		"failed for -86400");
725 
726 	days = ntpcal_daysec_to_date(&cal, -86399);
727 	TEST_ASSERT_MESSAGE((days==-1 && cal.hour==0 && cal.minute==0 && cal.second==1),
728 		"failed for -86399");
729 
730 	days = ntpcal_daysec_to_date(&cal, -1);
731 	TEST_ASSERT_MESSAGE((days==-1 && cal.hour==23 && cal.minute==59 && cal.second==59),
732 		"failed for -1");
733 
734 	days = ntpcal_daysec_to_date(&cal, 0);
735 	TEST_ASSERT_MESSAGE((days==0 && cal.hour==0 && cal.minute==0 && cal.second==0),
736 		"failed for 0");
737 
738 	days = ntpcal_daysec_to_date(&cal, 1);
739 	TEST_ASSERT_MESSAGE((days==0 && cal.hour==0 && cal.minute==0 && cal.second==1),
740 		"failed for 1");
741 
742 	days = ntpcal_daysec_to_date(&cal, 86399);
743 	TEST_ASSERT_MESSAGE((days==0 && cal.hour==23 && cal.minute==59 && cal.second==59),
744 		"failed for 86399");
745 
746 	days = ntpcal_daysec_to_date(&cal, 86400);
747 	TEST_ASSERT_MESSAGE((days==1 && cal.hour==0 && cal.minute==0 && cal.second==0),
748 		"failed for 86400");
749 
750 	return;
751 }
752 
753 /* --------------------------------------------------------------------
754  * unfolding of (truncated) NTP time stamps to full 64bit values.
755  *
756  * Note: These tests need a 64bit time_t to be useful.
757  */
758 
759 void
760 test_NtpToNtp(void)
761 {
762 #   if SIZEOF_TIME_T <= 4
763 
764 	TEST_IGNORE_MESSAGE("test only useful for sizeof(time_t) > 4, skipped");
765 
766 #   else
767 
768 	static const uint32_t ntp_vals[6] = {
769 		UINT32_C(0x00000000),
770 		UINT32_C(0x00000001),
771 		UINT32_C(0x7FFFFFFF),
772 		UINT32_C(0x80000000),
773 		UINT32_C(0x80000001),
774 		UINT32_C(0xFFFFFFFF)
775 	};
776 
777 	static char	lbuf[128];
778 	vint64		hold;
779 	time_t		pivot, texp, diff;
780 	int		loops, iloop;
781 
782 	pivot = 0;
783 	for (loops = 0; loops < 16; ++loops) {
784 		for (iloop = 0; iloop < 6; ++iloop) {
785 			hold = ntpcal_ntp_to_ntp(
786 				ntp_vals[iloop], &pivot);
787 			texp = vint64_to_time(&hold);
788 
789 			/* constraint 1: texp must be in the
790 			 * (right-open) intervall [p-(2^31), p+(2^31)[,
791 			 * but the pivot 'p' must be taken in full NTP
792 			 * time scale!
793 			 */
794 			diff = texp - (pivot + JAN_1970);
795 			snprintf(lbuf, sizeof(lbuf),
796 				 "bounds check: piv=%lld exp=%lld dif=%lld",
797 				 (long long)pivot,
798 				 (long long)texp,
799 				 (long long)diff);
800 			TEST_ASSERT_MESSAGE((diff >= INT32_MIN) && (diff <= INT32_MAX),
801 					    lbuf);
802 
803 			/* constraint 2: low word must be equal to
804 			 * input
805 			 */
806 			snprintf(lbuf, sizeof(lbuf),
807 				 "low check: ntp(in)=$%08lu ntp(out[0:31])=$%08lu",
808 				 (unsigned long)ntp_vals[iloop],
809 				 (unsigned long)hold.D_s.lo);
810 			TEST_ASSERT_EQUAL_MESSAGE(ntp_vals[iloop], hold.D_s.lo, lbuf);
811 		}
812 		pivot += 0x20000000;
813 	}
814 #   endif
815 }
816 
817 void
818 test_NtpToTime(void)
819 {
820 #   if SIZEOF_TIME_T <= 4
821 
822 	TEST_IGNORE_MESSAGE("test only useful for sizeof(time_t) > 4, skipped");
823 
824 #   else
825 
826 	static const uint32_t ntp_vals[6] = {
827 		UINT32_C(0x00000000),
828 		UINT32_C(0x00000001),
829 		UINT32_C(0x7FFFFFFF),
830 		UINT32_C(0x80000000),
831 		UINT32_C(0x80000001),
832 		UINT32_C(0xFFFFFFFF)
833 	};
834 
835 	static char	lbuf[128];
836 	vint64		hold;
837 	time_t		pivot, texp, diff;
838 	uint32_t	back;
839 	int		loops, iloop;
840 
841 	pivot = 0;
842 	for (loops = 0; loops < 16; ++loops) {
843 		for (iloop = 0; iloop < 6; ++iloop) {
844 			hold = ntpcal_ntp_to_time(
845 				ntp_vals[iloop], &pivot);
846 			texp = vint64_to_time(&hold);
847 
848 			/* constraint 1: texp must be in the
849 			 * (right-open) intervall [p-(2^31), p+(2^31)[
850 			 */
851 			diff = texp - pivot;
852 			snprintf(lbuf, sizeof(lbuf),
853 				 "bounds check: piv=%lld exp=%lld dif=%lld",
854 				 (long long)pivot,
855 				 (long long)texp,
856 				 (long long)diff);
857 			TEST_ASSERT_MESSAGE((diff >= INT32_MIN) && (diff <= INT32_MAX),
858 					    lbuf);
859 
860 			/* constraint 2: conversion from full time back
861 			 * to truncated NTP time must yield same result
862 			 * as input.
863 			*/
864 			back = (uint32_t)texp + JAN_1970;
865 			snprintf(lbuf, sizeof(lbuf),
866 				 "modulo check: ntp(in)=$%08lu ntp(out)=$%08lu",
867 				 (unsigned long)ntp_vals[iloop],
868 				 (unsigned long)back);
869 			TEST_ASSERT_EQUAL_MESSAGE(ntp_vals[iloop], back, lbuf);
870 		}
871 		pivot += 0x20000000;
872 	}
873 #   endif
874 }
875 
876 /* --------------------------------------------------------------------
877  * GPS rollover
878  * --------------------------------------------------------------------
879  */
880 void
881 test_GpsRollOver(void)
882 {
883 	/* we test on wednesday, noon, and on the border */
884 	static const int32_t wsec1 = 3*SECSPERDAY + SECSPERDAY/2;
885 	static const int32_t wsec2 = 7 * SECSPERDAY - 1;
886 	static const int32_t week0 = GPSNTP_WSHIFT + 2047;
887 	static const int32_t week1 = GPSNTP_WSHIFT + 2048;
888 	TCivilDate jd;
889 	TGpsDatum  gps;
890 	l_fp       fpz;
891 
892 	ZERO(fpz);
893 
894 	/* test on 2nd rollover, April 2019
895 	 * we set the base date properly one week *before the rollover, to
896 	 * check if the expansion merrily hops over the warp.
897 	 */
898 	basedate_set_day(2047 * 7 + NTP_TO_GPS_DAYS);
899 
900 	strToCal(&jd, "19-04-03T12:00:00");
901 	gps = gpscal_from_calendar(&jd, fpz);
902 	TEST_ASSERT_EQUAL_MESSAGE(week0, gps.weeks, "(week test 1))");
903 	TEST_ASSERT_EQUAL_MESSAGE(wsec1, gps.wsecs, "(secs test 1)");
904 
905 	strToCal(&jd, "19-04-06T23:59:59");
906 	gps = gpscal_from_calendar(&jd, fpz);
907 	TEST_ASSERT_EQUAL_MESSAGE(week0, gps.weeks, "(week test 2)");
908 	TEST_ASSERT_EQUAL_MESSAGE(wsec2, gps.wsecs, "(secs test 2)");
909 
910 	strToCal(&jd, "19-04-07T00:00:00");
911 	gps = gpscal_from_calendar(&jd, fpz);
912 	TEST_ASSERT_EQUAL_MESSAGE(week1, gps.weeks, "(week test 3)");
913 	TEST_ASSERT_EQUAL_MESSAGE(  0 , gps.wsecs, "(secs test 3)");
914 
915 	strToCal(&jd, "19-04-10T12:00:00");
916 	gps = gpscal_from_calendar(&jd, fpz);
917 	TEST_ASSERT_EQUAL_MESSAGE(week1, gps.weeks, "(week test 4)");
918 	TEST_ASSERT_EQUAL_MESSAGE(wsec1, gps.wsecs, "(secs test 4)");
919 }
920 
921 void
922 test_GpsRemapFunny(void)
923 {
924 	TCivilDate di, dc, de;
925 	TGpsDatum  gd;
926 
927 	l_fp       fpz;
928 
929 	ZERO(fpz);
930 	basedate_set_day(2048 * 7 + NTP_TO_GPS_DAYS);
931 
932 	/* expand 2digit year to 2080, then fold back into 3rd GPS era: */
933 	strToCal(&di, "80-01-01T00:00:00");
934 	strToCal(&de, "2021-02-15T00:00:00");
935 	gd = gpscal_from_calendar(&di, fpz);
936 	gpscal_to_calendar(&dc, &gd);
937 	TEST_ASSERT_TRUE(IsEqualCal(&de, &dc));
938 
939 	/* expand 2digit year to 2080, then fold back into 3rd GPS era: */
940 	strToCal(&di, "80-01-05T00:00:00");
941 	strToCal(&de, "2021-02-19T00:00:00");
942 	gd = gpscal_from_calendar(&di, fpz);
943 	gpscal_to_calendar(&dc, &gd);
944 	TEST_ASSERT_TRUE(IsEqualCal(&de, &dc));
945 
946 	/* remap days before epoch into 3rd era: */
947 	strToCal(&di, "1980-01-05T00:00:00");
948 	strToCal(&de, "2038-11-20T00:00:00");
949 	gd = gpscal_from_calendar(&di, fpz);
950 	gpscal_to_calendar(&dc, &gd);
951 	TEST_ASSERT_TRUE(IsEqualCal(&de, &dc));
952 
953 	/* remap GPS epoch: */
954 	strToCal(&di, "1980-01-06T00:00:00");
955 	strToCal(&de, "2019-04-07T00:00:00");
956 	gd = gpscal_from_calendar(&di, fpz);
957 	gpscal_to_calendar(&dc, &gd);
958 	TEST_ASSERT_TRUE(IsEqualCal(&de, &dc));
959 }
960 
961 void
962 test_GpsNtpFixpoints(void)
963 {
964 	basedate_set_day(NTP_TO_GPS_DAYS);
965 	TGpsDatum e1gps;
966 	TNtpDatum e1ntp, r1ntp;
967 	l_fp      lfpe , lfpr;
968 
969 	lfpe.l_ui = 0;
970 	lfpe.l_uf = UINT32_C(0x80000000);
971 
972 	ZERO(e1gps);
973 	e1gps.weeks = 0;
974 	e1gps.wsecs = SECSPERDAY;
975 	e1gps.frac  = UINT32_C(0x80000000);
976 
977 	ZERO(e1ntp);
978 	e1ntp.frac  = UINT32_C(0x80000000);
979 
980 	r1ntp = gpsntp_from_gpscal(&e1gps);
981 	TEST_ASSERT_EQUAL_MESSAGE(e1ntp.days, r1ntp.days, "gps -> ntp / days");
982 	TEST_ASSERT_EQUAL_MESSAGE(e1ntp.secs, r1ntp.secs, "gps -> ntp / secs");
983 	TEST_ASSERT_EQUAL_MESSAGE(e1ntp.frac, r1ntp.frac, "gps -> ntp / frac");
984 
985 	lfpr = ntpfp_from_gpsdatum(&e1gps);
986 	snprintf(mbuf, sizeof(mbuf), "gps -> l_fp: %s <=> %s",
987 		 lfptoa(&lfpe, 9), lfptoa(&lfpr, 9));
988 	TEST_ASSERT_TRUE_MESSAGE(L_ISEQU(&lfpe, &lfpr), mbuf);
989 
990 	lfpr = ntpfp_from_ntpdatum(&e1ntp);
991 	snprintf(mbuf, sizeof(mbuf), "ntp -> l_fp: %s <=> %s",
992 		 lfptoa(&lfpe, 9), lfptoa(&lfpr, 9));
993 	TEST_ASSERT_TRUE_MESSAGE(L_ISEQU(&lfpe, &lfpr), mbuf);
994 }
995 
996 void
997 test_CalUMod7(void)
998 {
999 	TEST_ASSERT_EQUAL(0, u32mod7(0));
1000 	TEST_ASSERT_EQUAL(1, u32mod7(INT32_MAX));
1001 	TEST_ASSERT_EQUAL(2, u32mod7(UINT32_C(1)+INT32_MAX));
1002 	TEST_ASSERT_EQUAL(3, u32mod7(UINT32_MAX));
1003 }
1004 
1005 void
1006 test_CalIMod7(void)
1007 {
1008 	TEST_ASSERT_EQUAL(5, i32mod7(INT32_MIN));
1009 	TEST_ASSERT_EQUAL(6, i32mod7(-1));
1010 	TEST_ASSERT_EQUAL(0, i32mod7(0));
1011 	TEST_ASSERT_EQUAL(1, i32mod7(INT32_MAX));
1012 }
1013 
1014 /* Century expansion tests. Reverse application of Zeller's congruence,
1015  * sort of... hence the name "Rellez", Zeller backwards. Just in case
1016  * you didn't notice ;)
1017  */
1018 
1019 void
1020 test_RellezCentury1_1(void)
1021 {
1022 	/* 1st day of a century */
1023 	TEST_ASSERT_EQUAL(1901, ntpcal_expand_century( 1, 1, 1, CAL_TUESDAY  ));
1024 	TEST_ASSERT_EQUAL(2001, ntpcal_expand_century( 1, 1, 1, CAL_MONDAY   ));
1025 	TEST_ASSERT_EQUAL(2101, ntpcal_expand_century( 1, 1, 1, CAL_SATURDAY ));
1026 	TEST_ASSERT_EQUAL(2201, ntpcal_expand_century( 1, 1, 1, CAL_THURSDAY ));
1027 	/* bad/impossible cases: */
1028 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 1, 1, 1, CAL_WEDNESDAY));
1029 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 1, 1, 1, CAL_FRIDAY   ));
1030 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 1, 1, 1, CAL_SUNDAY   ));
1031 }
1032 
1033 void
1034 test_RellezCentury3_1(void)
1035 {
1036 	/* 1st day in March of a century (the tricky point) */
1037 	TEST_ASSERT_EQUAL(1901, ntpcal_expand_century( 1, 3, 1, CAL_FRIDAY   ));
1038 	TEST_ASSERT_EQUAL(2001, ntpcal_expand_century( 1, 3, 1, CAL_THURSDAY ));
1039 	TEST_ASSERT_EQUAL(2101, ntpcal_expand_century( 1, 3, 1, CAL_TUESDAY  ));
1040 	TEST_ASSERT_EQUAL(2201, ntpcal_expand_century( 1, 3, 1, CAL_SUNDAY   ));
1041 	/* bad/impossible cases: */
1042 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 1, 3, 1, CAL_MONDAY   ));
1043 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 1, 3, 1, CAL_WEDNESDAY));
1044 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 1, 3, 1, CAL_SATURDAY ));
1045 }
1046 
1047 void
1048 test_RellezYearZero(void)
1049 {
1050 	/* the infamous year zero */
1051 	TEST_ASSERT_EQUAL(1900, ntpcal_expand_century( 0, 1, 1, CAL_MONDAY   ));
1052 	TEST_ASSERT_EQUAL(2000, ntpcal_expand_century( 0, 1, 1, CAL_SATURDAY ));
1053 	TEST_ASSERT_EQUAL(2100, ntpcal_expand_century( 0, 1, 1, CAL_FRIDAY   ));
1054 	TEST_ASSERT_EQUAL(2200, ntpcal_expand_century( 0, 1, 1, CAL_WEDNESDAY));
1055 	/* bad/impossible cases: */
1056 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 0, 1, 1, CAL_TUESDAY  ));
1057 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 0, 1, 1, CAL_THURSDAY ));
1058 	TEST_ASSERT_EQUAL(   0, ntpcal_expand_century( 0, 1, 1, CAL_SUNDAY   ));
1059 }
1060 
1061 void test_RellezEra(void);
1062 void test_RellezEra(void)
1063 {
1064 	static const unsigned int mt[13] = { 0, 31,28,31,30,31,30,31,31,30,31,30,31 };
1065 	unsigned int yi, yo, m, d, wd;
1066 
1067 	/* last day before our era -- fold forward */
1068 	yi = 1899;
1069 	m  = 12;
1070 	d  = 31;
1071 	wd = ntpcal_edate_to_eradays(yi-1, m-1, d-1) % 7 + 1;
1072 	yo = ntpcal_expand_century((yi%100), m, d, wd);
1073 	snprintf(mbuf, sizeof(mbuf), "failed, di=%04u-%02u-%02u, wd=%u",
1074 		 yi, m, d, wd);
1075 	TEST_ASSERT_EQUAL_MESSAGE(2299, yo, mbuf);
1076 
1077 	/* 1st day after our era -- fold back */
1078 	yi = 2300;
1079 	m  = 1;
1080 	d  = 1;
1081 	wd = ntpcal_edate_to_eradays(yi-1, m-1, d-1) % 7 + 1;
1082 	yo = ntpcal_expand_century((yi%100), m, d, wd);
1083 	snprintf(mbuf, sizeof(mbuf), "failed, di=%04u-%02u-%02u, wd=%u",
1084 		 yi, m, d, wd);
1085 	TEST_ASSERT_EQUAL_MESSAGE(1900, yo, mbuf);
1086 
1087 	/* test every month in our 400y era */
1088 	for (yi = 1900; yi < 2300; ++yi) {
1089 		for (m = 1; m < 12; ++m) {
1090 			/* test first day of month */
1091 			d = 1;
1092 			wd = ntpcal_edate_to_eradays(yi-1, m-1, d-1) % 7 + 1;
1093 			yo = ntpcal_expand_century((yi%100), m, d, wd);
1094 			snprintf(mbuf, sizeof(mbuf), "failed, di=%04u-%02u-%02u, wd=%u",
1095 				 yi, m, d, wd);
1096 			TEST_ASSERT_EQUAL_MESSAGE(yi, yo, mbuf);
1097 
1098 			/* test last day of month */
1099 			d = mt[m] + (m == 2 && is_leapyear(yi));
1100 			wd = ntpcal_edate_to_eradays(yi-1, m-1, d-1) % 7 + 1;
1101 			yo = ntpcal_expand_century((yi%100), m, d, wd);
1102 			snprintf(mbuf, sizeof(mbuf), "failed, di=%04u-%02u-%02u, wd=%u",
1103 				 yi, m, d, wd);
1104 			TEST_ASSERT_EQUAL_MESSAGE(yi, yo, mbuf);
1105 		}
1106 	}
1107 }
1108 
1109 /* This is nearly a verbatim copy of the in-situ implementation of
1110  * Zeller's congruence in libparse/clk_rawdcf.c, so the algorithm
1111  * can be tested.
1112  */
1113 static int
1114 zeller_expand(
1115         unsigned int  y,
1116         unsigned int  m,
1117         unsigned int  d,
1118 	unsigned int  wd
1119 	)
1120 {
1121 	unsigned int  c;
1122 
1123         if ((y >= 100u) || (--m >= 12u) || (--d >= 31u) || (--wd >= 7u))
1124 		return 0;
1125 
1126 	if ((m += 10u) >= 12u)
1127 		m -= 12u;
1128 	else if (--y >= 100u)
1129 		y += 100u;
1130 	d += y + (y >> 2) + 2u;
1131 	d += (m * 83u + 16u) >> 5;
1132 
1133 	c = (((252u + wd - d) * 0x6db6db6eU) >> 29) & 7u;
1134 	if (c > 3u)
1135 		return 0;
1136 
1137 	if ((m > 9u) && (++y >= 100u)) {
1138 		y -= 100u;
1139 		c = (c + 1) & 3u;
1140 	}
1141 	y += (c * 100u);
1142 	y += (y < 370u) ? 2000 : 1600;
1143 	return (int)y;
1144 }
1145 
1146 void test_zellerDirect(void);
1147 void test_zellerDirect(void)
1148 {
1149 	static const unsigned int mt[13] = { 0, 31,28,31,30,31,30,31,31,30,31,30,31 };
1150 	unsigned int yi, yo, m, d, wd;
1151 
1152 	/* last day before our era -- fold forward */
1153 	yi = 1969;
1154 	m  = 12;
1155 	d  = 31;
1156 	wd = ntpcal_edate_to_eradays(yi-1, m-1, d-1) % 7 + 1;
1157 	yo = zeller_expand((yi%100), m, d, wd);
1158 	snprintf(mbuf, sizeof(mbuf), "failed, di=%04u-%02u-%02u, wd=%u",
1159 		 yi, m, d, wd);
1160 	TEST_ASSERT_EQUAL_MESSAGE(2369, yo, mbuf);
1161 
1162 	/* 1st day after our era -- fold back */
1163 	yi = 2370;
1164 	m  = 1;
1165 	d  = 1;
1166 	wd = ntpcal_edate_to_eradays(yi-1, m-1, d-1) % 7 + 1;
1167 	yo = zeller_expand((yi%100), m, d, wd);
1168 	snprintf(mbuf, sizeof(mbuf), "failed, di=%04u-%02u-%02u, wd=%u",
1169 		 yi, m, d, wd);
1170 	TEST_ASSERT_EQUAL_MESSAGE(1970, yo, mbuf);
1171 
1172 	/* test every month in our 400y era */
1173 	for (yi = 1970; yi < 2370; ++yi) {
1174 		for (m = 1; m < 12; ++m) {
1175 			/* test first day of month */
1176 			d = 1;
1177 			wd = ntpcal_edate_to_eradays(yi-1, m-1, d-1) % 7 + 1;
1178 			yo = zeller_expand((yi%100), m, d, wd);
1179 			snprintf(mbuf, sizeof(mbuf), "failed, di=%04u-%02u-%02u, wd=%u",
1180 				 yi, m, d, wd);
1181 			TEST_ASSERT_EQUAL_MESSAGE(yi, yo, mbuf);
1182 
1183 			/* test last day of month */
1184 			d = mt[m] + (m == 2 && is_leapyear(yi));
1185 			wd = ntpcal_edate_to_eradays(yi-1, m-1, d-1) % 7 + 1;
1186 			yo = zeller_expand((yi%100), m, d, wd);
1187 			snprintf(mbuf, sizeof(mbuf), "failed, di=%04u-%02u-%02u, wd=%u",
1188 				 yi, m, d, wd);
1189 			TEST_ASSERT_EQUAL_MESSAGE(yi, yo, mbuf);
1190 		}
1191 	}
1192 }
1193 
1194 void test_ZellerDirectBad(void);
1195 void test_ZellerDirectBad(void)
1196 {
1197 	unsigned int y, n, wd;
1198 	for (y = 2001; y < 2101; ++y) {
1199 		wd = ntpcal_edate_to_eradays(y-1, 0, 0) % 7 + 1;
1200 		/* move 4 centuries ahead */
1201 		wd = (wd + 5) % 7 + 1;
1202 		for (n = 0; n < 3; ++n) {
1203 			TEST_ASSERT_EQUAL(0, zeller_expand((y%100), 1, 1, wd));
1204 			wd = (wd + 4) % 7 + 1;
1205 		}
1206 	}
1207 }
1208 
1209 void test_zellerModInv(void);
1210 void test_zellerModInv(void)
1211 {
1212 	unsigned int i, r1, r2;
1213 
1214 	for (i = 0; i < 2048; ++i) {
1215 		r1 = (3 * i) % 7;
1216 		r2 = ((i * 0x6db6db6eU) >> 29) & 7u;
1217 		snprintf(mbuf, sizeof(mbuf), "i=%u", i);
1218 		TEST_ASSERT_EQUAL_MESSAGE(r1, r2, mbuf);
1219 	}
1220 }
1221 
1222 
1223