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
25 static u_int32 my_tick_to_tsf(u_int32 ticks);
26 static u_int32 my_tsf_to_tick(u_int32 tsf);
27
28
29 // that's it...
30 struct lfpfracdata {
31 long nsec;
32 u_int32 frac;
33 };
34
35
36 void setUp(void);
37 void test_Helpers1(void);
38 void test_Normalise(void);
39 void test_SignNoFrac(void);
40 void test_SignWithFrac(void);
41 void test_CmpFracEQ(void);
42 void test_CmpFracGT(void);
43 void test_CmpFracLT(void);
44 void test_AddFullNorm(void);
45 void test_AddFullOflow1(void);
46 void test_AddNsecNorm(void);
47 void test_AddNsecOflow1(void);
48 void test_SubFullNorm(void);
49 void test_SubFullOflow(void);
50 void test_SubNsecNorm(void);
51 void test_SubNsecOflow(void);
52 void test_Neg(void);
53 void test_AbsNoFrac(void);
54 void test_AbsWithFrac(void);
55 void test_Helpers2(void);
56 void test_ToLFPbittest(void);
57 void test_ToLFPrelPos(void);
58 void test_ToLFPrelNeg(void);
59 void test_ToLFPabs(void);
60 void test_FromLFPbittest(void);
61 void test_FromLFPrelPos(void);
62 void test_FromLFPrelNeg(void);
63 void test_LFProundtrip(void);
64 void test_ToString(void);
65
66 const bool timespec_isValid(struct timespec V);
67 struct timespec timespec_init(time_t hi, long lo);
68 l_fp l_fp_init(int32 i, u_int32 f);
69 bool AssertFpClose(const l_fp m, const l_fp n, const l_fp limit);
70 bool AssertTimespecClose(const struct timespec m,
71 const struct timespec n,
72 const struct timespec limit);
73
74
75 //***************************MY CUSTOM FUNCTIONS***************************
76
77
78 void
setUp(void)79 setUp(void)
80 {
81 init_lib();
82
83 return;
84 }
85
86
87 const bool
timespec_isValid(struct timespec V)88 timespec_isValid(struct timespec V)
89 {
90
91 return V.tv_nsec >= 0 && V.tv_nsec < 1000000000;
92 }
93
94
95 struct timespec
timespec_init(time_t hi,long lo)96 timespec_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
107 l_fp
l_fp_init(int32 i,u_int32 f)108 l_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
119 bool
AssertFpClose(const l_fp m,const l_fp n,const l_fp limit)120 AssertFpClose(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
141 bool
AssertTimespecClose(const struct timespec m,const struct timespec n,const struct timespec limit)142 AssertTimespecClose(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
159 static 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
177 u_int32
my_tick_to_tsf(u_int32 ticks)178 my_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
195 u_int32
my_tsf_to_tick(u_int32 tsf)196 my_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
214 void
test_Helpers1(void)215 test_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
238 void
test_Normalise(void)239 test_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
257 void
test_SignNoFrac(void)258 test_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
275 void
test_SignWithFrac(void)276 test_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 //----------------------------------------------------------------------
295 void
test_CmpFracEQ(void)296 test_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
314 void
test_CmpFracGT(void)315 test_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
334 void
test_CmpFracLT(void)335 test_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
357 void
test_AddFullNorm(void)358 test_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
377 void
test_AddFullOflow1(void)378 test_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
397 void
test_AddNsecNorm(void)398 test_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
414 void
test_AddNsecOflow1(void)415 test_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
435 void
test_SubFullNorm(void)436 test_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
455 void
test_SubFullOflow(void)456 test_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
475 void
test_SubNsecNorm(void)476 test_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
493 void
test_SubNsecOflow(void)494 test_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
515 void
test_Neg(void)516 test_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
537 void
test_AbsNoFrac(void)538 test_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
554 void
test_AbsWithFrac(void)555 test_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
574 void
test_Helpers2(void)575 test_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
605 void
test_ToLFPbittest(void)606 test_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
624 void
test_ToLFPrelPos(void)625 test_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
642 void
test_ToLFPrelNeg(void)643 test_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
660 void
test_ToLFPabs(void)661 test_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
681 void
test_FromLFPbittest(void)682 test_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
705 void
test_FromLFPrelPos(void)706 test_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
724 void
test_FromLFPrelNeg(void)725 test_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
744 void
test_LFProundtrip(void)745 test_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
768 void
test_ToString(void)769 test_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