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