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