Line data Source code
1 : /** 2 : * @file rational.test.cpp 3 : * @author Essam A. El-Sherif <esm.elsh@gmail.com> 4 : * @version v1.0.0 5 : * 6 : * A testing module for the rational template class defined by rational.h 7 : */ 8 : 9 : #include <iostream> 10 : #include <list> 11 : #include <stdexcept> 12 : #include <sstream> 13 : #include <string> 14 : 15 : #include "../include/rational.h" 16 : 17 : /** 18 : * A namespace to enclose the unit testing code. 19 : */ 20 : namespace utest{ 21 : 22 : using namespace src; 23 : 24 : /** Define a structure variable to enclose testing options. */ 25 : struct { 26 : bool verbose; 27 : } cmdOptions = { false }; 28 : 29 : /** Define a unit test type. */ 30 : typedef struct Test{ 31 : void (*method)(void); 32 : std::string desc; 33 : bool skip; 34 : } 35 : *TestPtr; 36 : 37 : /** Define a test suite type. */ 38 : typedef struct Suite{ 39 : std::string desc; 40 : std::list<TestPtr> *testList; 41 : } 42 : *SuitePtr; 43 : 44 : /** A list of pointers to test suites. */ 45 : std::list<SuitePtr> suites; 46 : 47 : void loadTestData(); /**< Load test data into the suites list. */ 48 : void verboseExit(); /**< Count success, failures and/or skipped tests */ 49 : void testRunner(); /**< Run the tests loaded into the suites list. */ 50 : void makeTest(TestPtr); /**< Run the unit test given by the test pointer. */ 51 : 52 : /** Assert true condition otherwise throws an exception. */ 53 228 : inline void _assert(bool test, const char *msg = ""){ 54 228 : if(!test) throw std::logic_error(msg); 55 228 : } 56 : 57 : void test1(); void test2(); void test3(); void test4(); void test5(); 58 : void test6(); void test7(); void test8(); void test9(); void test10(); 59 : void test11(); void test12(); void test13(); void test14(); void test15(); 60 : void test16(); void test17(); void test18(); void test19(); void test20(); 61 : 62 : /* Prepare test environment */ 63 : int testCount = 1; 64 : int passCount = 0; 65 : int failCount = 0; 66 : int skipCount = 0; 67 : } 68 : 69 1 : int main(){ 70 : using namespace utest; 71 : 72 1 : loadTestData(); 73 : 74 1 : cmdOptions.verbose = false; 75 1 : testRunner(); 76 : 77 1 : cmdOptions.verbose = true; 78 1 : testRunner(); 79 : 80 1 : return 0; 81 : } 82 : 83 1 : void utest::loadTestData(){ 84 1 : SuitePtr suitePtr = nullptr; 85 1 : TestPtr testPtr = nullptr; 86 : 87 : // TEST SUITE #1 - Constructors 88 1 : suitePtr = new Suite(); 89 : 90 1 : suitePtr->desc = "Test Suite #1 - Constructors"; 91 1 : suitePtr->testList = new std::list<TestPtr>(); 92 : 93 1 : suites.push_back(suitePtr); 94 : 95 : // TEST #1 - Default constructor 96 1 : testPtr = new Test(); 97 : 98 1 : testPtr->desc = "Default constructor"; 99 1 : testPtr->skip = false; 100 1 : testPtr->method = test1; 101 : 102 1 : suitePtr->testList->push_back(testPtr); 103 : 104 : // TEST #2 - One argument constructor 105 1 : testPtr = new Test(); 106 : 107 1 : testPtr->desc = "One argument constructor"; 108 1 : testPtr->skip = false; 109 1 : testPtr->method = test2; 110 : 111 1 : suitePtr->testList->push_back(testPtr); 112 : 113 : // TEST #3 - Two arguments constructor 114 1 : testPtr = new Test(); 115 : 116 1 : testPtr->desc = "Two arguments constructor"; 117 1 : testPtr->skip = false; 118 1 : testPtr->method = test3; 119 : 120 1 : suitePtr->testList->push_back(testPtr); 121 : 122 : // TEST #4 - Two arguments constructor invalid 123 1 : testPtr = new Test(); 124 : 125 1 : testPtr->desc = "Two arguments constructor invalid"; 126 1 : testPtr->skip = false; 127 1 : testPtr->method = test4; 128 : 129 1 : suitePtr->testList->push_back(testPtr); 130 : 131 : // TEST #5 - Copy constructor 132 1 : testPtr = new Test(); 133 : 134 1 : testPtr->desc = "Copy constructor"; 135 1 : testPtr->skip = false; 136 1 : testPtr->method = test5; 137 : 138 1 : suitePtr->testList->push_back(testPtr); 139 : 140 : // TEST SUITE #2 - Assignment 141 1 : suitePtr = new Suite(); 142 : 143 1 : suitePtr->desc = "Test Suite #2 - Assignment"; 144 1 : suitePtr->testList = new std::list<TestPtr>(); 145 : 146 1 : suites.push_back(suitePtr); 147 : 148 : // TEST #6 - Assignment 149 1 : testPtr = new Test(); 150 : 151 1 : testPtr->desc = "Assignment"; 152 1 : testPtr->skip = false; 153 1 : testPtr->method = test6; 154 : 155 1 : suitePtr->testList->push_back(testPtr); 156 : 157 : // TEST #7 - Arithmetic assignment 158 1 : testPtr = new Test(); 159 : 160 1 : testPtr->desc = "Arithmetic assignment"; 161 1 : testPtr->skip = false; 162 1 : testPtr->method = test7; 163 : 164 1 : suitePtr->testList->push_back(testPtr); 165 : 166 : // TEST #8 - Arithmetic assignment invalid 167 1 : testPtr = new Test(); 168 : 169 1 : testPtr->desc = "Arithmetic assignment invalid"; 170 1 : testPtr->skip = false; 171 1 : testPtr->method = test8; 172 : 173 1 : suitePtr->testList->push_back(testPtr); 174 : 175 : // TEST #9 - Arithmetic assignment with int type 176 1 : testPtr = new Test(); 177 : 178 1 : testPtr->desc = "Arithmetic assignment with int type"; 179 1 : testPtr->skip = false; 180 1 : testPtr->method = test9; 181 : 182 1 : suitePtr->testList->push_back(testPtr); 183 : 184 : // TEST #10 - Arithmetic assignment with int type invalid 185 1 : testPtr = new Test(); 186 : 187 1 : testPtr->desc = "Arithmetic assignment with int type invalid"; 188 1 : testPtr->skip = false; 189 1 : testPtr->method = test10; 190 : 191 1 : suitePtr->testList->push_back(testPtr); 192 : 193 : // TEST SUITE #3 - Member operators 194 1 : suitePtr = new Suite(); 195 : 196 1 : suitePtr->desc = "Test Suite #3 - Member operators"; 197 1 : suitePtr->testList = new std::list<TestPtr>(); 198 : 199 1 : suites.push_back(suitePtr); 200 : 201 : // TEST #11 - Increment / decrement 202 1 : testPtr = new Test(); 203 : 204 1 : testPtr->desc = "Increment / decrement"; 205 1 : testPtr->skip = false; 206 1 : testPtr->method = test11; 207 : 208 1 : suitePtr->testList->push_back(testPtr); 209 : 210 : // TEST #12 - Operator not 211 1 : testPtr = new Test(); 212 : 213 1 : testPtr->desc = "Operator not"; 214 1 : testPtr->skip = false; 215 1 : testPtr->method = test12; 216 : 217 1 : suitePtr->testList->push_back(testPtr); 218 : 219 : // TEST #13 - Boolean conversion 220 1 : testPtr = new Test(); 221 : 222 1 : testPtr->desc = "Boolean conversion"; 223 1 : testPtr->skip = false; 224 1 : testPtr->method = test13; 225 : 226 1 : suitePtr->testList->push_back(testPtr); 227 : 228 : // TEST #14 - Comparison operators 229 1 : testPtr = new Test(); 230 : 231 1 : testPtr->desc = "Comparison operators"; 232 1 : testPtr->skip = false; 233 1 : testPtr->method = test14; 234 : 235 1 : suitePtr->testList->push_back(testPtr); 236 : 237 : // TEST SUITE #4 - Global operators 238 1 : suitePtr = new Suite(); 239 : 240 1 : suitePtr->desc = "Test Suite #4 - Global operators"; 241 1 : suitePtr->testList = new std::list<TestPtr>(); 242 : 243 1 : suites.push_back(suitePtr); 244 : 245 : // TEST #15 - Global unary operators 246 1 : testPtr = new Test(); 247 : 248 1 : testPtr->desc = "Global unary operators"; 249 1 : testPtr->skip = false; 250 1 : testPtr->method = test15; 251 : 252 1 : suitePtr->testList->push_back(testPtr); 253 : 254 : // TEST #16 - Global binary operators 255 1 : testPtr = new Test(); 256 : 257 1 : testPtr->desc = "Global binary operators"; 258 1 : testPtr->skip = false; 259 1 : testPtr->method = test16; 260 : 261 1 : suitePtr->testList->push_back(testPtr); 262 : 263 : // TEST SUITE #5 - Others 264 1 : suitePtr = new Suite(); 265 : 266 1 : suitePtr->desc = "Test Suite #5 - Others"; 267 1 : suitePtr->testList = new std::list<TestPtr>(); 268 : 269 1 : suites.push_back(suitePtr); 270 : 271 : // TEST #17 - Absolute member function 272 1 : testPtr = new Test(); 273 : 274 1 : testPtr->desc = "Absolute member function"; 275 1 : testPtr->skip = false; 276 1 : testPtr->method = test17; 277 : 278 1 : suitePtr->testList->push_back(testPtr); 279 : 280 : // TEST #18 - Type conversion 281 1 : testPtr = new Test(); 282 : 283 1 : testPtr->desc = "Type conversion"; 284 1 : testPtr->skip = false; 285 1 : testPtr->method = test18; 286 : 287 1 : suitePtr->testList->push_back(testPtr); 288 : 289 : // TEST #19 - Sign handling 290 1 : testPtr = new Test(); 291 : 292 1 : testPtr->desc = "Sign handling"; 293 1 : testPtr->skip = false; 294 1 : testPtr->method = test19; 295 : 296 1 : suitePtr->testList->push_back(testPtr); 297 : 298 : // TEST #20 - Overflow 299 1 : testPtr = new Test(); 300 : 301 1 : testPtr->desc = "Overflow"; 302 1 : testPtr->skip = false; 303 1 : testPtr->method = test20; 304 : 305 1 : suitePtr->testList->push_back(testPtr); 306 1 : } 307 : 308 2 : void utest::testRunner(){ 309 : 310 2 : std::atexit(verboseExit); 311 2 : if(cmdOptions.verbose) std::cerr << std::endl; 312 : 313 2 : std::list<SuitePtr>::const_iterator it1; 314 12 : for(it1 = suites.begin(); it1 != suites.end(); ++it1){ 315 : 316 10 : std::string suiteDesc = (*it1)->desc; 317 10 : if(cmdOptions.verbose) std::cerr << suiteDesc << std::endl; 318 : 319 10 : std::list<TestPtr> *testList = (*it1)->testList; 320 : 321 10 : std::list<TestPtr>::const_iterator it2; 322 50 : for(it2 = testList->begin(); it2 != testList->end(); ++it2){ 323 40 : makeTest(*it2); 324 : } 325 10 : } 326 : 327 2 : if(cmdOptions.verbose) std::cerr << std::endl; 328 2 : } 329 : 330 40 : void utest::makeTest(TestPtr ptr){ 331 : 332 40 : const int testID = testCount++; 333 : 334 40 : std::ostringstream ss; 335 40 : ss << "... Test#" << std::setw(3) << std::setfill('0') << testID << " ... "; 336 : 337 40 : std::string preMsg = ss.str(), postMsg = preMsg; 338 : 339 40 : preMsg += "Initiate ... " + ptr->desc; 340 40 : if(cmdOptions.verbose) std::cerr << preMsg << std::endl; 341 : 342 40 : if(!cmdOptions.verbose){ 343 20 : ptr->method(); 344 : } 345 : else{ 346 : try{ 347 20 : ptr->method(); 348 20 : passCount++; 349 : 350 20 : postMsg += "Success ... " + ptr->desc;; 351 20 : if(cmdOptions.verbose) std::cerr << postMsg << std::endl; 352 : } 353 0 : catch(...){ 354 0 : failCount++; 355 : 356 0 : postMsg += "Failure ... " + ptr->desc; 357 0 : if(cmdOptions.verbose) std::cerr << postMsg << std::endl; 358 0 : } 359 : } 360 40 : } 361 : 362 2 : void utest::verboseExit(){ 363 2 : if(cmdOptions.verbose){ 364 2 : std::cout << std::endl; 365 2 : std::cout << "▶ tests " << --testCount << std::endl; 366 2 : std::cout << "▶ suites " << suites.size() << std::endl; 367 2 : std::cout << "▶ pass " << passCount << std::endl; 368 2 : std::cout << "▶ fail " << failCount << std::endl; 369 2 : std::cout << "▶ skipped " << skipCount << std::endl; 370 : } 371 2 : } 372 : 373 : /** Test#1 - Default constructor. */ 374 2 : void utest::test1(){ 375 2 : _assert(rational<int>().numerator() == 0); 376 2 : _assert(rational<int>().denominator() == 1); 377 2 : } 378 : 379 : /** Test#2 - One argument constructor. */ 380 2 : void utest::test2(){ 381 2 : _assert(rational<int>(1).numerator() == 1); 382 2 : _assert(rational<int>(1).denominator() == 1); 383 : 384 2 : _assert(rational<int>(-1).numerator() == -1); 385 2 : _assert(rational<int>(-1).denominator() == 1); 386 : 387 2 : _assert(rational<int>(0).numerator() == 0); 388 2 : _assert(rational<int>(0).denominator() == 1); 389 2 : } 390 : 391 : /** Test#3 - Two arguments constructor. */ 392 2 : void utest::test3(){ 393 2 : _assert(rational<int>(1, 2).numerator() == 1); 394 2 : _assert(rational<int>(1, 2).denominator() == 2); 395 : 396 2 : _assert(rational<int>(-1, 2).numerator() == -1); 397 2 : _assert(rational<int>(-1, 2).denominator() == 2); 398 : 399 2 : _assert(rational<int>(1, -2).numerator() == -1); 400 2 : _assert(rational<int>(1, -2).denominator() == 2); 401 : 402 2 : _assert(rational<int>(-1, -2).numerator() == 1); 403 2 : _assert(rational<int>(-1, -2).denominator() == 2); 404 : 405 2 : _assert(rational<int>(0, 2).numerator() == 0); 406 2 : _assert(rational<int>(0, 2).denominator() == 1); 407 2 : } 408 : 409 : /** Test#4 - Two arguments constructor invalid. */ 410 2 : void utest::test4(){ 411 : try{ 412 2 : rational<int>(2, 0); 413 : } 414 2 : catch(bad_rational&){} 415 2 : } 416 : 417 : /** Test#5 - Copy constructor. */ 418 2 : void utest::test5(){ 419 2 : rational<long> rl(1L, 2L); 420 2 : rational<int> ri(rl); 421 : 422 2 : _assert(ri.numerator() == 1); 423 2 : _assert(ri.denominator() == 2); 424 2 : } 425 : 426 : /** Test#6 - Assignment. */ 427 2 : void utest::test6(){ 428 2 : rational<int> r = 3; 429 : 430 2 : _assert(r.numerator() == 3); 431 2 : _assert(r.denominator() == 1); 432 : 433 2 : r.assign(1, -2); 434 2 : _assert(r.numerator() == -1); 435 2 : _assert(r.denominator() == 2); 436 2 : } 437 : 438 : /** Test#7 - Arithmetic assignment. */ 439 2 : void utest::test7(){ 440 2 : const rational<int> one(1); 441 2 : const rational<int> half(1, 2); 442 2 : rational<int> r; 443 : 444 2 : r = 1; r += one; 445 2 : _assert(r.numerator() == 2); 446 2 : _assert(r.denominator() == 1); 447 : 448 2 : r = 2; r -= one; 449 2 : _assert(r.numerator() == 1); 450 2 : _assert(r.denominator() == 1); 451 : 452 2 : r = 2; r *= one; 453 2 : _assert(r.numerator() == 2); 454 2 : _assert(r.denominator() == 1); 455 : 456 2 : r = 2; r /= one; 457 2 : _assert(r.numerator() == 2); 458 2 : _assert(r.denominator() == 1); 459 : 460 2 : r = 1; r /= half; 461 2 : _assert(r.numerator() == 2); 462 2 : _assert(r.denominator() == 1); 463 : 464 2 : r = 0; r /= one; 465 2 : _assert(r.numerator() == 0); 466 2 : _assert(r.denominator() == 1); 467 : 468 2 : } 469 : 470 : /** Test#8 - Arithmetic assignment invalid. */ 471 2 : void utest::test8(){ 472 2 : const rational<int> zero; 473 2 : rational<int> r; 474 : 475 : try{ 476 2 : r = 1; 477 2 : r /= zero; 478 : } 479 2 : catch(bad_rational&){} 480 2 : } 481 : 482 : /** Test#9 - Arithmetic assignment with int type. */ 483 2 : void utest::test9(){ 484 2 : rational<int> r = 3; 485 : 486 2 : r = 1; r += 1; 487 2 : _assert(r.numerator() == 2); 488 2 : _assert(r.denominator() == 1); 489 : 490 2 : r = 2; r -= 1; 491 2 : _assert(r.numerator() == 1); 492 2 : _assert(r.denominator() == 1); 493 : 494 2 : r = 2; r *= 1; 495 2 : _assert(r.numerator() == 2); 496 2 : _assert(r.denominator() == 1); 497 : 498 2 : r = 2; r /= 1; 499 2 : _assert(r.numerator() == 2); 500 2 : _assert(r.denominator() == 1); 501 : 502 2 : r = 0; r /= 1; 503 2 : _assert(r.numerator() == 0); 504 2 : _assert(r.denominator() == 1); 505 2 : } 506 : 507 : /** Test#10 - Arithmetic assignment with int type invalid. */ 508 2 : void utest::test10(){ 509 2 : rational<int> r; 510 : 511 : try{ 512 2 : r = 1; 513 2 : r /= 0; 514 : } 515 2 : catch(bad_rational&){} 516 2 : } 517 : 518 : /** Test#11 - Increment/decrement. */ 519 2 : void utest::test11(){ 520 2 : rational<int> r, s; 521 : 522 2 : r = 1; s = ++r; 523 2 : _assert(r.numerator() == 2); 524 2 : _assert(r.denominator() == 1); 525 2 : _assert(s == r); 526 : 527 2 : r = 1; s = --r; 528 2 : _assert(r.numerator() == 0); 529 2 : _assert(r.denominator() == 1); 530 2 : _assert(s == r); 531 : 532 2 : r = 1; s = r++; 533 2 : _assert(r.numerator() == 2); 534 2 : _assert(r.denominator() == 1); 535 2 : _assert(s != r); 536 : 537 2 : r = 1; s = r--; 538 2 : _assert(r.numerator() == 0); 539 2 : _assert(r.denominator() == 1); 540 2 : _assert(s != r); 541 2 : } 542 : 543 : /** Test#12 - Operator not. */ 544 2 : void utest::test12(){ 545 2 : rational<int> r; 546 : 547 2 : r = 0; 548 2 : _assert(!r); 549 : 550 2 : r = 1; 551 2 : _assert(!!r); 552 2 : } 553 : 554 : /** Test#13 - Boolean conversion. */ 555 2 : void utest::test13(){ 556 2 : rational<int> r; 557 : 558 2 : r = 1; 559 2 : _assert(r); 560 2 : } 561 : 562 : /** Test#14 - Comparison operators. */ 563 2 : void utest::test14(){ 564 2 : _assert(rational<int>() < rational<int>(1)); 565 2 : _assert(rational<int>(-1) < rational<int>()); 566 : 567 2 : _assert(rational<int>() == rational<int>()); 568 2 : _assert(rational<int>(-1) == rational<int>(-1)); 569 : 570 2 : _assert(rational<int>() < 1); 571 2 : _assert(rational<int>(-1) < 0); 572 : 573 2 : _assert(rational<int>(1) > 0); 574 2 : _assert(rational<int>(0) > -1); 575 : 576 2 : _assert(rational<int>() == 0); 577 2 : _assert(rational<int>(-1) == -1); 578 2 : } 579 : 580 : /** Test#15 - Global unary operators. */ 581 2 : void utest::test15(){ 582 2 : _assert( (+rational<int>(1, 2)).numerator() == 1); 583 2 : _assert( (+rational<int>(1, 2)).denominator() == 2); 584 : 585 2 : _assert( (+rational<int>(1, -2)).numerator() == -1); 586 2 : _assert( (+rational<int>(1, -2)).denominator() == 2); 587 : 588 2 : _assert( (-rational<int>(1, 2)).numerator() == -1); 589 2 : _assert( (-rational<int>(1, 2)).denominator() == 2); 590 : 591 2 : _assert( (-rational<int>(-1, 2)).numerator() == 1); 592 2 : _assert( (-rational<int>(-1, 2)).denominator() == 2); 593 2 : } 594 : 595 : /** Test#16 - Global binary operators. */ 596 2 : void utest::test16(){ 597 2 : const rational<int> zero; 598 2 : const rational<int> half(1, 2); 599 2 : const rational<int> one(1); 600 2 : const rational<int> two(2); 601 2 : const rational<int> minus_half(-1, 2); 602 : 603 2 : _assert(half + half == one); 604 2 : _assert(one - half == half); 605 2 : _assert(two * half == one); 606 2 : _assert(one / half == two); 607 2 : _assert(zero / one == zero); 608 : 609 2 : _assert(half + minus_half == zero); 610 2 : _assert(half - minus_half == one); 611 2 : _assert(one * minus_half == minus_half); 612 2 : _assert(one / minus_half == -two); 613 2 : _assert(zero / minus_half == zero); 614 : 615 2 : _assert(zero + 1 == one); 616 2 : _assert(one - 0 == one); 617 2 : _assert(two * 1 == two); 618 2 : _assert(two / 1 == two); 619 2 : _assert(zero / 1 == zero); 620 : 621 2 : _assert(zero + -1 == -one); 622 2 : _assert(one - -1 == two); 623 2 : _assert(two * -1 == -two); 624 2 : _assert(two / -1 == -two); 625 2 : _assert(zero / -1 == zero); 626 : 627 2 : _assert(1 + zero == one); 628 2 : _assert(1 - zero == one); 629 2 : _assert(2 * one == two); 630 2 : _assert(2 / one == two); 631 2 : _assert(0 / one == zero); 632 : 633 2 : _assert(half + half == 1); 634 2 : _assert(2 * half == one); 635 2 : _assert(2 * half == 1); 636 2 : _assert(one / half == 2); 637 2 : _assert(1 / half == 2); 638 2 : } 639 : 640 : /** Test#17 - Absolute member function. */ 641 2 : void utest::test17(){ 642 2 : const rational<int> half(1, 2); 643 2 : const rational<int> minus_half(-1, 2); 644 : 645 2 : _assert(abs(minus_half) == half); 646 2 : } 647 : 648 : /** Test#18 - Type conversion. */ 649 2 : void utest::test18(){ 650 2 : const rational<int> pi(22,7); 651 : 652 2 : _assert((rational_cast<double>(pi) - 22.0/7.0) < 1e-6); 653 2 : } 654 : 655 : /** Test#19 - Sign handling. */ 656 2 : void utest::test19(){ 657 : 658 2 : const rational<int> half(1, 2); 659 2 : const rational<int> minus_half(-1, 2); 660 : 661 2 : _assert(-half == minus_half); 662 2 : _assert(abs(minus_half) == half); 663 2 : } 664 : 665 : /** Test#20 - Overflow. */ 666 2 : void utest::test20(){ 667 2 : int maxint = (std::numeric_limits<int>::max)(); 668 2 : rational<int> big(maxint, 2); 669 : 670 2 : _assert(2 * big == maxint); 671 2 : }