xref: /netbsd-src/external/bsd/ntp/dist/tests/libntp/timespecops.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: timespecops.c,v 1.1.1.5 2016/01/08 21:21:33 christos Exp $	*/
2 
3 #include "config.h"
4 
5 #include "ntp_types.h"
6 #include "ntp_fp.h"
7 #include "timespecops.h"
8 
9 #include "unity.h"
10 
11 #include <math.h>
12 #include <string.h>
13 
14 
15 #define TEST_ASSERT_EQUAL_timespec(a, b) {				\
16     TEST_ASSERT_EQUAL_MESSAGE(a.tv_sec, b.tv_sec, "Field tv_sec");	\
17     TEST_ASSERT_EQUAL_MESSAGE(a.tv_nsec, b.tv_nsec, "Field tv_nsec");	\
18 }
19 
20 
21 #define TEST_ASSERT_EQUAL_l_fp(a, b) {					\
22     TEST_ASSERT_EQUAL_MESSAGE(a.l_i, b.l_i, "Field l_i");		\
23     TEST_ASSERT_EQUAL_UINT_MESSAGE(a.l_uf, b.l_uf, "Field l_uf");	\
24 }
25 
26 
27 static u_int32 my_tick_to_tsf(u_int32 ticks);
28 static u_int32 my_tsf_to_tick(u_int32 tsf);
29 
30 
31 // that's it...
32 struct lfpfracdata {
33 	long	nsec;
34 	u_int32 frac;
35 };
36 
37 
38 void setUp(void);
39 void test_Helpers1(void);
40 void test_Normalise(void);
41 void test_SignNoFrac(void);
42 void test_SignWithFrac(void);
43 void test_CmpFracEQ(void);
44 void test_CmpFracGT(void);
45 void test_CmpFracLT(void);
46 void test_AddFullNorm(void);
47 void test_AddFullOflow1(void);
48 void test_AddNsecNorm(void);
49 void test_AddNsecOflow1(void);
50 void test_SubFullNorm(void);
51 void test_SubFullOflow(void);
52 void test_SubNsecNorm(void);
53 void test_SubNsecOflow(void);
54 void test_Neg(void);
55 void test_AbsNoFrac(void);
56 void test_AbsWithFrac(void);
57 void test_Helpers2(void);
58 void test_ToLFPbittest(void);
59 void test_ToLFPrelPos(void);
60 void test_ToLFPrelNeg(void);
61 void test_ToLFPabs(void);
62 void test_FromLFPbittest(void);
63 void test_FromLFPrelPos(void);
64 void test_FromLFPrelNeg(void);
65 void test_LFProundtrip(void);
66 void test_ToString(void);
67 
68 typedef int bool;
69 
70 const bool	timespec_isValid(struct timespec V);
71 struct timespec timespec_init(time_t hi, long lo);
72 l_fp		l_fp_init(int32 i, u_int32 f);
73 bool		AssertFpClose(const l_fp m, const l_fp n, const l_fp limit);
74 bool		AssertTimespecClose(const struct timespec m,
75 				    const struct timespec n,
76 				    const struct timespec limit);
77 
78 
79 //***************************MY CUSTOM FUNCTIONS***************************
80 
81 
82 void
83 setUp(void)
84 {
85 	init_lib();
86 
87 	return;
88 }
89 
90 
91 const bool
92 timespec_isValid(struct timespec V)
93 {
94 
95 	return V.tv_nsec >= 0 && V.tv_nsec < 1000000000;
96 }
97 
98 
99 struct timespec
100 timespec_init(time_t hi, long lo)
101 {
102 	struct timespec V;
103 
104 	V.tv_sec = hi;
105 	V.tv_nsec = lo;
106 
107 	return V;
108 }
109 
110 
111 l_fp
112 l_fp_init(int32 i, u_int32 f)
113 {
114 	l_fp temp;
115 
116 	temp.l_i  = i;
117 	temp.l_uf = f;
118 
119 	return temp;
120 }
121 
122 
123 bool
124 AssertFpClose(const l_fp m, const l_fp n, const l_fp limit)
125 {
126 	l_fp diff;
127 
128 	if (L_ISGEQ(&m, &n)) {
129 		diff = m;
130 		L_SUB(&diff, &n);
131 	} else {
132 		diff = n;
133 		L_SUB(&diff, &m);
134 	}
135 	if (L_ISGEQ(&limit, &diff)) {
136 		return TRUE;
137 	}
138 	else {
139 		printf("m_expr which is %s \nand\nn_expr which is %s\nare not close; diff=%susec\n", lfptoa(&m, 10), lfptoa(&n, 10), lfptoa(&diff, 10));
140 		return FALSE;
141 	}
142 }
143 
144 
145 bool
146 AssertTimespecClose(const struct timespec m, const struct timespec n,
147 	const struct timespec limit)
148 {
149 	struct timespec diff;
150 
151 	diff = abs_tspec(sub_tspec(m, n));
152 	if (cmp_tspec(limit, diff) >= 0)
153 		return TRUE;
154 	else
155 	{
156 		printf("m_expr which is %ld.%lu \nand\nn_expr which is %ld.%lu\nare not close; diff=%ld.%lunsec\n", m.tv_sec, m.tv_nsec, n.tv_sec, n.tv_nsec, diff.tv_sec, diff.tv_nsec);
157 		return FALSE;
158 	}
159 }
160 
161 //-----------------------------------------------
162 
163 static const struct lfpfracdata fdata[] = {
164 	{	  0, 0x00000000 }, {   2218896, 0x00916ae6 },
165 	{  16408100, 0x0433523d }, { 125000000, 0x20000000 },
166 	{ 250000000, 0x40000000 }, { 287455871, 0x4996b53d },
167 	{ 375000000, 0x60000000 }, { 500000000, 0x80000000 },
168 	{ 518978897, 0x84dbcd0e }, { 563730222, 0x90509fb3 },
169 	{ 563788007, 0x9054692c }, { 583289882, 0x95527c57 },
170 	{ 607074509, 0x9b693c2a }, { 625000000, 0xa0000000 },
171 	{ 645184059, 0xa52ac851 }, { 676497788, 0xad2ef583 },
172 	{ 678910895, 0xadcd1abb }, { 679569625, 0xadf84663 },
173 	{ 690926741, 0xb0e0932d }, { 705656483, 0xb4a5e73d },
174 	{ 723553854, 0xb93ad34c }, { 750000000, 0xc0000000 },
175 	{ 763550253, 0xc3780785 }, { 775284917, 0xc6791284 },
176 	{ 826190764, 0xd3813ce8 }, { 875000000, 0xe0000000 },
177 	{ 956805507, 0xf4f134a9 }, { 982570733, 0xfb89c16c }
178 	};
179 
180 
181 u_int32
182 my_tick_to_tsf(u_int32 ticks)
183 {
184 	// convert nanoseconds to l_fp fractional units, using double
185 	// precision float calculations or, if available, 64bit integer
186 	// arithmetic. This should give the precise fraction, rounded to
187 	// the nearest representation.
188 
189 #ifdef HAVE_U_INT64
190 	return (u_int32)((( ((u_int64)(ticks)) << 32) + 500000000) / 1000000000);
191 #else
192 	return (u_int32)((double(ticks)) * 4.294967296 + 0.5);
193 #endif
194 	// And before you ask: if ticks >= 1000000000, the result is
195 	// truncated nonsense, so don't use it out-of-bounds.
196 }
197 
198 
199 u_int32
200 my_tsf_to_tick(u_int32 tsf)
201 {
202 
203 	// Inverse operation: converts fraction to microseconds.
204 #ifdef HAVE_U_INT64
205 	return (u_int32)(( ((u_int64)(tsf)) * 1000000000 + 0x80000000) >> 32);
206 #else
207 	return (u_int32)(double(tsf) / 4.294967296 + 0.5);
208 #endif
209 	// Beware: The result might be 10^9 due to rounding!
210 }
211 
212 
213 
214 // ---------------------------------------------------------------------
215 // test support stuff -- part 1
216 // ---------------------------------------------------------------------
217 
218 void
219 test_Helpers1(void)
220 {
221 	struct timespec x;
222 
223 	for (x.tv_sec = -2; x.tv_sec < 3; x.tv_sec++) {
224 		x.tv_nsec = -1;
225 		TEST_ASSERT_FALSE(timespec_isValid(x));
226 		x.tv_nsec = 0;
227 		TEST_ASSERT_TRUE(timespec_isValid(x));
228 		x.tv_nsec = 999999999;
229 		TEST_ASSERT_TRUE(timespec_isValid(x));
230 		x.tv_nsec = 1000000000;
231 		TEST_ASSERT_FALSE(timespec_isValid(x));
232 	}
233 
234 	return;
235 }
236 
237 
238 //----------------------------------------------------------------------
239 // test normalisation
240 //----------------------------------------------------------------------
241 
242 void
243 test_Normalise(void)
244 {
245 	long ns;
246 
247 	for ( ns = -2000000000; ns <= 2000000000; ns += 10000000) {
248 		struct timespec x = timespec_init(0, ns);
249 
250 		x = normalize_tspec(x);
251 		TEST_ASSERT_TRUE(timespec_isValid(x));
252 	}
253 
254 	return;
255 }
256 
257 //----------------------------------------------------------------------
258 // test classification
259 //----------------------------------------------------------------------
260 
261 void
262 test_SignNoFrac(void)
263 {
264 	// sign test, no fraction
265 	int i;
266 
267 	for (i = -4; i <= 4; ++i) {
268 		struct timespec a = timespec_init(i, 0);
269 		int E = (i > 0) - (i < 0);
270 		int r = test_tspec(a);
271 
272 		TEST_ASSERT_EQUAL(E, r);
273 	}
274 
275 	return;
276 }
277 
278 
279 void
280 test_SignWithFrac(void)
281 {
282 	// sign test, with fraction
283 	int i;
284 
285 	for (i = -4; i <= 4; ++i) {
286 		struct timespec a = timespec_init(i, 10);
287 		int E = (i >= 0) - (i < 0);
288 		int r = test_tspec(a);
289 
290 		TEST_ASSERT_EQUAL(E, r);
291 	}
292 
293 	return;
294 }
295 
296 //----------------------------------------------------------------------
297 // test compare
298 //----------------------------------------------------------------------
299 void
300 test_CmpFracEQ(void)
301 {
302 	// fractions are equal
303 	int i, j;
304 	for (i = -4; i <= 4; ++i)
305 		for (j = -4; j <= 4; ++j) {
306 			struct timespec a = timespec_init( i , 200);
307 			struct timespec b = timespec_init( j , 200);
308 			int   E = (i > j) - (i < j);
309 			int   r = cmp_tspec_denorm(a, b);
310 
311 			TEST_ASSERT_EQUAL(E, r);
312 		}
313 
314 	return;
315 }
316 
317 
318 void
319 test_CmpFracGT(void)
320 {
321 	// fraction a bigger fraction b
322 	int i, j;
323 
324 	for (i = -4; i <= 4; ++i)
325 		for (j = -4; j <= 4; ++j) {
326 			struct timespec a = timespec_init(i, 999999800);
327 			struct timespec b = timespec_init(j, 200);
328 			int   E = (i >= j) - (i < j);
329 			int   r = cmp_tspec_denorm(a, b);
330 
331 			TEST_ASSERT_EQUAL(E, r);
332 		}
333 
334 	return;
335 }
336 
337 
338 void
339 test_CmpFracLT(void)
340 {
341 	// fraction a less fraction b
342 	int i, j;
343 
344 	for (i = -4; i <= 4; ++i)
345 		for (j = -4; j <= 4; ++j) {
346 			struct timespec a = timespec_init(i, 200);
347 			struct timespec b = timespec_init(j, 999999800);
348 			int   E = (i > j) - (i <= j);
349 			int   r = cmp_tspec_denorm(a, b);
350 
351 			TEST_ASSERT_EQUAL(E, r);
352 		}
353 
354 	return;
355 }
356 
357 //----------------------------------------------------------------------
358 // Test addition (sum)
359 //----------------------------------------------------------------------
360 
361 void
362 test_AddFullNorm(void)
363 {
364 	int i, j;
365 
366 	for (i = -4; i <= 4; ++i)
367 		for (j = -4; j <= 4; ++j) {
368 			struct timespec a = timespec_init(i, 200);
369 			struct timespec b = timespec_init(j, 400);
370 			struct timespec E = timespec_init(i + j, 200 + 400);
371 			struct timespec c;
372 
373 			c = add_tspec(a, b);
374 			TEST_ASSERT_EQUAL_timespec(E, c);
375 		}
376 
377 	return;
378 }
379 
380 
381 void
382 test_AddFullOflow1(void)
383 {
384 	int i, j;
385 
386 	for (i = -4; i <= 4; ++i)
387 		for (j = -4; j <= 4; ++j) {
388 			struct timespec a = timespec_init(i, 200);
389 			struct timespec b = timespec_init(j, 999999900);
390 			struct timespec E = timespec_init(i + j + 1, 100);
391 			struct timespec c;
392 
393 			c = add_tspec(a, b);
394 			TEST_ASSERT_EQUAL_timespec(E, c);
395 		}
396 
397 	return;
398 }
399 
400 
401 void
402 test_AddNsecNorm(void) {
403 	int i;
404 
405 	for (i = -4; i <= 4; ++i) {
406 		struct timespec a = timespec_init(i, 200);
407 		struct timespec E = timespec_init(i, 600);
408 		struct timespec c;
409 
410 		c = add_tspec_ns(a, 600 - 200);
411 		TEST_ASSERT_EQUAL_timespec(E, c);
412 	}
413 
414 	return;
415 }
416 
417 
418 void
419 test_AddNsecOflow1(void)
420 {
421 	int i;
422 
423 	for (i = -4; i <= 4; ++i) {
424 		struct timespec a = timespec_init(i, 200);
425 		struct timespec E = timespec_init(i + 1, 100);
426 		struct timespec c;
427 
428 		c = add_tspec_ns(a, NANOSECONDS - 100);
429 		TEST_ASSERT_EQUAL_timespec(E, c);
430 	}
431 
432 	return;
433 }
434 
435 //----------------------------------------------------------------------
436 // test subtraction (difference)
437 //----------------------------------------------------------------------
438 
439 void
440 test_SubFullNorm(void)
441 {
442 	int i, j;
443 
444 	for (i = -4; i <= 4; ++i)
445 		for (j = -4; j <= 4; ++j) {
446 			struct timespec a = timespec_init( i , 600);
447 			struct timespec b = timespec_init( j , 400);
448 			struct timespec E = timespec_init(i-j, 200);
449 			struct timespec c;
450 
451 			c = sub_tspec(a, b);
452 			TEST_ASSERT_EQUAL_timespec(E, c);
453 		}
454 
455 	return;
456 }
457 
458 
459 void
460 test_SubFullOflow(void)
461 {
462 	int i, j;
463 
464 	for (i = -4; i <= 4; ++i)
465 		for (j = -4; j <= 4; ++j) {
466 			struct timespec a = timespec_init(i, 100);
467 			struct timespec b = timespec_init(j, 999999900);
468 			struct timespec E = timespec_init(i - j - 1, 200);
469 			struct timespec c;
470 
471 			c = sub_tspec(a, b);
472 			TEST_ASSERT_EQUAL_timespec(E, c);
473 		}
474 
475 	return;
476 }
477 
478 
479 void
480 test_SubNsecNorm(void)
481 {
482 	int i;
483 
484 	for (i = -4; i <= 4; ++i) {
485 		struct timespec a = timespec_init(i, 600);
486 		struct timespec E = timespec_init(i, 200);
487 		struct timespec c;
488 
489 		c = sub_tspec_ns(a, 600 - 200);
490 		TEST_ASSERT_EQUAL_timespec(E, c);
491 	}
492 
493 	return;
494 }
495 
496 
497 void
498 test_SubNsecOflow(void)
499 {
500 	int i;
501 
502 	for (i = -4; i <= 4; ++i) {
503 		struct timespec a = timespec_init( i , 100);
504 		struct timespec E = timespec_init(i-1, 200);
505 		struct timespec c;
506 
507 		c = sub_tspec_ns(a, NANOSECONDS - 100);
508 		TEST_ASSERT_EQUAL_timespec(E, c);
509 	}
510 
511 	return;
512 }
513 
514 //----------------------------------------------------------------------
515 // test negation
516 //----------------------------------------------------------------------
517 
518 
519 void
520 test_Neg(void)
521 {
522 	int i;
523 
524 	for (i = -4; i <= 4; ++i) {
525 		struct timespec a = timespec_init(i, 100);
526 		struct timespec b;
527 		struct timespec c;
528 
529 		b = neg_tspec(a);
530 		c = add_tspec(a, b);
531 		TEST_ASSERT_EQUAL(0, test_tspec(c));
532 	}
533 
534 	return;
535 }
536 
537 //----------------------------------------------------------------------
538 // test abs value
539 //----------------------------------------------------------------------
540 
541 void
542 test_AbsNoFrac(void)
543 {
544 	int i;
545 
546 	for (i = -4; i <= 4; ++i) {
547 		struct timespec a = timespec_init(i , 0);
548 		struct timespec b;
549 
550 		b = abs_tspec(a);
551 		TEST_ASSERT_EQUAL((i != 0), test_tspec(b));
552 	}
553 
554 	return;
555 }
556 
557 
558 void
559 test_AbsWithFrac(void)
560 {
561 	int i;
562 
563 	for (i = -4; i <= 4; ++i) {
564 		struct timespec a = timespec_init(i, 100);
565 		struct timespec b;
566 
567 		b = abs_tspec(a);
568 		TEST_ASSERT_EQUAL(1, test_tspec(b));
569 	}
570 
571 	return;
572 }
573 
574 // ---------------------------------------------------------------------
575 // test support stuff -- part 2
576 // ---------------------------------------------------------------------
577 
578 void
579 test_Helpers2(void)
580 {
581 	struct timespec limit = timespec_init(0, 2);
582 	struct timespec x, y;
583 	long i;
584 
585 	for (x.tv_sec = -2; x.tv_sec < 3; x.tv_sec++)
586 		for (x.tv_nsec = 1;
587 		     x.tv_nsec < 1000000000;
588 		     x.tv_nsec += 499999999) {
589 			for (i = -4; i < 5; ++i) {
590 				y = x;
591 				y.tv_nsec += i;
592 				if (i >= -2 && i <= 2) {
593 					TEST_ASSERT_TRUE(AssertTimespecClose(x, y, limit));
594 				}
595 				else
596 				{
597 					TEST_ASSERT_FALSE(AssertTimespecClose(x, y, limit));
598 				}
599 			}
600 		}
601 
602 	return;
603 }
604 
605 //----------------------------------------------------------------------
606 // conversion to l_fp
607 //----------------------------------------------------------------------
608 
609 void
610 test_ToLFPbittest(void)
611 {
612 	l_fp lfpClose =  l_fp_init(0, 1);
613 	u_int32 i;
614 
615 	for (i = 0; i < 1000000000; i+=1000) {
616 		struct timespec a = timespec_init(1, i);
617 		l_fp E= l_fp_init(1, my_tick_to_tsf(i));
618 		l_fp r;
619 
620 		r = tspec_intv_to_lfp(a);
621 		TEST_ASSERT_TRUE(AssertFpClose(E, r, lfpClose));
622 	}
623 
624 	return;
625 }
626 
627 
628 void
629 test_ToLFPrelPos(void)
630 {
631 	int i;
632 
633 	for (i = 0; i < COUNTOF(fdata); ++i) {
634 		struct timespec a = timespec_init(1, fdata[i].nsec);
635 		l_fp E = l_fp_init(1, fdata[i].frac);
636 		l_fp r;
637 
638 		r = tspec_intv_to_lfp(a);
639 		TEST_ASSERT_EQUAL_l_fp(E, r);
640 	}
641 
642 	return;
643 }
644 
645 
646 void
647 test_ToLFPrelNeg(void)
648 {
649 	int i;
650 
651 	for (i = 0; i < COUNTOF(fdata); ++i) {
652 		struct timespec a = timespec_init(-1, fdata[i].nsec);
653 		l_fp E = l_fp_init(~0, fdata[i].frac);
654 		l_fp r;
655 
656 		r = tspec_intv_to_lfp(a);
657 		TEST_ASSERT_EQUAL_l_fp(E, r);
658 	}
659 
660 	return;
661 }
662 
663 
664 void
665 test_ToLFPabs(void)
666 {
667 	int i;
668 
669 	for (i = 0; i < COUNTOF(fdata); ++i) {
670 		struct timespec a = timespec_init(1, fdata[i].nsec);
671 		l_fp E = l_fp_init(1 + JAN_1970, fdata[i].frac);
672 		l_fp r;
673 
674 		r = tspec_stamp_to_lfp(a);
675 		TEST_ASSERT_EQUAL_l_fp(E, r);
676 	}
677 
678 	return;
679 }
680 
681 //----------------------------------------------------------------------
682 // conversion from l_fp
683 //----------------------------------------------------------------------
684 
685 void
686 test_FromLFPbittest(void)
687 {
688 	struct timespec limit = timespec_init(0, 2);
689 
690 	// Not *exactly* a bittest, because 2**32 tests would take a
691 	// really long time even on very fast machines! So we do test
692 	// every 1000 fractional units.
693 	u_int32 tsf;
694 	for (tsf = 0; tsf < ~((u_int32)(1000)); tsf += 1000) {
695 		struct timespec E = timespec_init(1, my_tsf_to_tick(tsf));
696 		l_fp a = l_fp_init(1, tsf);
697 		struct timespec r;
698 
699 		r = lfp_intv_to_tspec(a);
700 		// The conversion might be off by one nanosecond when
701 		// comparing to calculated value.
702 		TEST_ASSERT_TRUE(AssertTimespecClose(E, r, limit));
703 	}
704 
705 	return;
706 }
707 
708 
709 void
710 test_FromLFPrelPos(void)
711 {
712 	struct timespec limit = timespec_init(0, 2);
713 	int i;
714 
715 	for (i = 0; i < COUNTOF(fdata); ++i) {
716 		l_fp a = l_fp_init(1, fdata[i].frac);
717 		struct timespec E = timespec_init(1, fdata[i].nsec);
718 		struct timespec r;
719 
720 		r = lfp_intv_to_tspec(a);
721 		TEST_ASSERT_TRUE(AssertTimespecClose(E, r, limit));
722 	}
723 
724 	return;
725 }
726 
727 
728 void
729 test_FromLFPrelNeg(void)
730 {
731 	struct timespec limit = timespec_init(0, 2);
732 	int i;
733 
734 	for (i = 0; i < COUNTOF(fdata); ++i) {
735 		l_fp a = l_fp_init(~0, fdata[i].frac);
736 		struct timespec E = timespec_init(-1, fdata[i].nsec);
737 		struct timespec r;
738 
739 		r = lfp_intv_to_tspec(a);
740 		TEST_ASSERT_TRUE(AssertTimespecClose(E, r, limit));
741 	}
742 
743 	return;
744 }
745 
746 
747 // nsec -> frac -> nsec roundtrip, using a prime start and increment
748 void
749 test_LFProundtrip(void)
750 {
751 	int32_t t;
752 	u_int32 i;
753 
754 	for (t = -1; t < 2; ++t)
755 		for (i = 4999; i < 1000000000; i += 10007) {
756 			struct timespec E = timespec_init(t, i);
757 			l_fp a;
758 			struct timespec r;
759 
760 			a = tspec_intv_to_lfp(E);
761 			r = lfp_intv_to_tspec(a);
762 			TEST_ASSERT_EQUAL_timespec(E, r);
763 		}
764 
765 	return;
766 }
767 
768 //----------------------------------------------------------------------
769 // string formatting
770 //----------------------------------------------------------------------
771 
772 void
773 test_ToString(void)
774 {
775 	static const struct {
776 		time_t		sec;
777 		long		nsec;
778 		const char *	repr;
779 	} data [] = {
780 		{ 0, 0,	 "0.000000000" },
781 		{ 2, 0,	 "2.000000000" },
782 		{-2, 0, "-2.000000000" },
783 		{ 0, 1,	 "0.000000001" },
784 		{ 0,-1,	"-0.000000001" },
785 		{ 1,-1,	 "0.999999999" },
786 		{-1, 1, "-0.999999999" },
787 		{-1,-1, "-1.000000001" },
788 	};
789 	int i;
790 
791 	for (i = 0; i < COUNTOF(data); ++i) {
792 		struct timespec a = timespec_init(data[i].sec, data[i].nsec);
793 		const char * E = data[i].repr;
794 		const char * r = tspectoa(a);
795 		TEST_ASSERT_EQUAL_STRING(E, r);
796 	}
797 
798 	return;
799 }
800 
801 // -*- EOF -*-
802