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