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