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