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