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