1 /** 2 * Assert toolkit for more expressive unit testing. 3 * 4 * Many methods implement compile-time parameters (file, line) that are set at the call site. 5 * It is preferred that these parameters are ignored when using these methods. 6 * 7 * License: 8 * MIT. See LICENSE for full details. 9 */ 10 module dunit.toolkit; 11 12 /** 13 * Imports. 14 */ 15 import dunit.error; 16 import dunit.moduleunittester; 17 import std.algorithm; 18 import std.array; 19 import std.math; 20 import std.regex; 21 import std.stdio; 22 import std..string; 23 import std.traits; 24 import std.range; 25 26 /** 27 * Assert that two floating point values are approximately equal. 28 * 29 * See_Also: 30 * $(LINK http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm) 31 * 32 * Params: 33 * value = The value used during the assertion. 34 * target = The target value. 35 * ulps = The maximum space between two approximately equal floating point numbers measured in $(LINK2 http://en.wikipedia.org/wiki/Unit_in_the_last_place, units of least precision). A higher number means more approximation. 36 * message = The error message to display. 37 * file = The file name where the error occurred. The value is added automatically at the call site. 38 * line = The line where the error occurred. The value is added automatically at the call site. 39 * 40 * Throws: 41 * DUnitAssertError if the assertation fails. 42 */ 43 public void assertApprox(A, B)(A value, B target, long ulps = 10, string message = "Failed asserting approximately equal", string file = __FILE__, size_t line = __LINE__) if (isFloatingPoint!(CommonType!(A, B))) 44 { 45 static if (is(CommonType!(A, B) == double)) 46 { 47 long maximumUlps = 0x8000000000000; 48 long negativeZeroFloat = 0x8000000000000000; 49 long intValue = *(cast(ulong*)&value); 50 long intTarget = *(cast(ulong*)&target); 51 long difference; 52 } 53 else 54 { 55 int maximumUlps = 0x400000; 56 int negativeZeroFloat = 0x80000000; 57 int intValue = *(cast(int*)&value); 58 int intTarget = *(cast(int*)&target); 59 int difference; 60 } 61 62 ulps.assertGreaterThan(0, "Unit of least precision should be above 0", file, line); 63 ulps.assertLessThan(maximumUlps, format("Unit of least precision should be below %s", maximumUlps), file, line); 64 65 if (intValue < 0) 66 { 67 intValue = negativeZeroFloat - intValue; 68 } 69 70 if (intTarget < 0) 71 { 72 intTarget = negativeZeroFloat - intTarget; 73 } 74 75 difference = abs(intValue - intTarget); 76 77 if (difference > ulps) 78 { 79 auto error = new DUnitAssertError(message, file, line); 80 81 error.addTypedExpectation("Expected value", target); 82 error.addTypedError("Actual value", value); 83 84 throw error; 85 } 86 } 87 88 /// 89 unittest 90 { 91 float smallestFloatSubnormal = float.min_normal * float.epsilon; 92 smallestFloatSubnormal.assertApprox(-smallestFloatSubnormal); 93 94 double smallestDoubleSubnormal = double.min_normal * double.epsilon; 95 smallestDoubleSubnormal.assertApprox(-smallestDoubleSubnormal); 96 97 0.0f.assertApprox(-0.0f); 98 (-0.0f).assertApprox(0.0f); 99 0.0.assertApprox(-0.0); 100 (-0.0).assertApprox(0.0); 101 2.0f.assertApprox(1.999999f); 102 1.999999f.assertApprox(2.0f); 103 2.0.assertApprox(1.999999999999999); 104 1.999999999999999.assertApprox(2.0); 105 106 // The following tests pass but are open for debate whether or not they should. 107 float.max.assertApprox(float.infinity); 108 float.infinity.assertApprox(float.max); 109 double.infinity.assertApprox(double.max); 110 double.max.assertApprox(double.infinity); 111 float.nan.assertApprox(float.nan); 112 double.nan.assertApprox(double.nan); 113 114 // Assert a DUnitAssertError is thrown if assertApprox fails. 115 10f.assertApprox(0f).assertThrow!(DUnitAssertError)("Failed asserting approximately equal"); 116 } 117 118 /** 119 * Assert that two floating point values are approximately equal using an epsilon value. 120 * 121 * See_Also: 122 * $(LINK http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm) 123 * 124 * Params: 125 * value = The value used during the assertion. 126 * target = The target value. 127 * epsilon = An epsilon value to be used as the maximum absolute and relative error in the comparison. 128 * message = The error message to display. 129 * file = The file name where the error occurred. The value is added automatically at the call site. 130 * line = The line where the error occurred. The value is added automatically at the call site. 131 * 132 * Throws: 133 * DUnitAssertError if the assertation fails. 134 */ 135 public void assertApprox(A, B)(A value, B target, double epsilon, string message = "Failed asserting approximately equal", string file = __FILE__, size_t line = __LINE__) if (isFloatingPoint!(CommonType!(A, B))) 136 { 137 auto divisor = (fabs(value) > fabs(target)) ? value : target; 138 auto absoluteError = fabs(value - target); 139 auto relativeError = fabs((value - target) / divisor); 140 141 if (absoluteError > epsilon && relativeError > epsilon) 142 { 143 auto error = new DUnitAssertError(message, file, line); 144 145 error.addTypedExpectation("Expected value", target); 146 error.addTypedError("Actual value", value); 147 148 throw error; 149 } 150 } 151 152 /// 153 unittest 154 { 155 float smallestFloatSubnormal = float.min_normal * float.epsilon; 156 smallestFloatSubnormal.assertApprox(-smallestFloatSubnormal, 0.00001); 157 158 double smallestDoubleSubnormal = double.min_normal * double.epsilon; 159 smallestDoubleSubnormal.assertApprox(-smallestDoubleSubnormal, 0.00001); 160 161 0.0f.assertApprox(-0.0f, 0.00001); 162 (-0.0f).assertApprox(0.0f, 0.00001); 163 0.0.assertApprox(-0.0, 0.00001); 164 (-0.0).assertApprox(0.0, 0.00001); 165 2.0f.assertApprox(1.99f, 0.01); 166 1.99f.assertApprox(2.0f, 0.01); 167 2.0.assertApprox(1.99, 0.01); 168 1.99.assertApprox(2.0, 0.01); 169 170 // The following tests pass but are open for debate whether or not they should. 171 float.max.assertApprox(float.infinity, 0.00001); 172 float.infinity.assertApprox(float.max, 0.00001); 173 double.infinity.assertApprox(double.max, 0.00001); 174 double.max.assertApprox(double.infinity, 0.00001); 175 float.nan.assertApprox(float.nan, 0.00001); 176 double.nan.assertApprox(double.nan, 0.00001); 177 178 // Assert a DUnitAssertError is thrown if assertApprox fails. 179 10f.assertApprox(0f, 0.00001).assertThrow!(DUnitAssertError)("Failed asserting approximately equal"); 180 } 181 182 /** 183 * Assert that an array contains a particular value count. 184 * 185 * Params: 186 * array = The array to interogate. 187 * count = The amount of values the array should hold. 188 * message = The error message to display. 189 * file = The file name where the error occurred. The value is added automatically at the call site. 190 * line = The line where the error occurred. The value is added automatically at the call site. 191 * 192 * Throws: 193 * DUnitAssertError if the assertation fails. 194 */ 195 public void assertCount(A)(A array, ulong count, string message = "Failed asserting array count", string file = __FILE__, size_t line = __LINE__) if (isArray!(A) || isAssociativeArray!(A)) 196 { 197 if (array.length != count) 198 { 199 auto error = new DUnitAssertError(message, file, line); 200 201 error.addInfo("Elements", array); 202 error.addExpectation("Expected count", count); 203 error.addError("Actual count", array.length); 204 205 throw error; 206 } 207 } 208 209 /// 210 unittest 211 { 212 int[string] associativeArray; 213 int[] dynamicArray; 214 string string_; 215 216 associativeArray.assertCount(0); 217 dynamicArray.assertCount(0); 218 string_.assertCount(0); 219 [].assertCount(0); 220 221 "Hello".assertCount(5); 222 [1, 2, 3, 4].assertCount(4); 223 ["foo", "bar", "baz", "qux"].assertCount(4); 224 [["foo", "bar"], ["baz", "qux"]].assertCount(2); 225 ["foo":1, "bar":2, "baz":3, "qux":4].assertCount(4); 226 227 // Assert a DUnitAssertError is thrown if assertCount fails. 228 associativeArray.assertCount(1).assertThrow!(DUnitAssertError)("Failed asserting array count"); 229 } 230 231 /** 232 * Assert that an array is empty. 233 * 234 * Params: 235 * array = The array to interogate. 236 * message = The error message to display. 237 * file = The file name where the error occurred. The value is added automatically at the call site. 238 * line = The line where the error occurred. The value is added automatically at the call site. 239 * 240 * Throws: 241 * DUnitAssertError if the assertation fails. 242 */ 243 public void assertEmpty(A)(A array, string message = "Failed asserting empty array", string file = __FILE__, size_t line = __LINE__) if (isArray!(A) || isAssociativeArray!(A)) 244 { 245 if (array.length > 0) 246 { 247 auto error = new DUnitAssertError(message, file, line); 248 249 error.addInfo("Elements", array); 250 error.addExpectation("Expected count", 0); 251 error.addError("Actual count", array.length); 252 253 throw error; 254 } 255 } 256 257 /// 258 unittest 259 { 260 int[string] associativeArray; 261 int[] dynamicArray; 262 string string_; 263 264 associativeArray.assertEmpty(); 265 dynamicArray.assertEmpty(); 266 string_.assertEmpty(); 267 [].assertEmpty(); 268 269 // Assert a DUnitAssertError is thrown if assertEmpty fails. 270 [1].assertEmpty().assertThrow!(DUnitAssertError)("Failed asserting empty array"); 271 } 272 273 /** 274 * Assert that a range is empty. 275 * 276 * Params: 277 * range = The range to interogate. 278 * message = The error message to display. 279 * file = The file name where the error occurred. The value is added automatically at the call site. 280 * line = The line where the error occurred. The value is added automatically at the call site. 281 * 282 * Throws: 283 * DUnitAssertError if the assertation fails. 284 */ 285 public void assertEmpty(R)(R range, string message = "Failed asserting empty range", string file = __FILE__, size_t line = __LINE__) if ((is(R == class) || is (R == struct)) && isInputRange!(R)) 286 { 287 if (!range.empty) 288 { 289 auto error = new DUnitAssertError(message, file, line); 290 291 error.addExpectation("Expected count", 0); 292 error.addInfo("Front elements", range.take(10)); 293 294 static if (isInfinite!(R)) 295 { 296 error.addError("Actual count", "∞"); 297 } 298 else 299 { 300 error.addError("Actual count", range.walkLength()); 301 } 302 303 throw error; 304 } 305 } 306 307 /// 308 unittest 309 { 310 class A 311 { 312 void popFront() {}; 313 @property bool empty() { return true; }; 314 @property int front() { return 0; }; 315 } 316 317 struct B 318 { 319 void popFront() {}; 320 enum bool empty = false; 321 @property int front() { return 1; }; 322 } 323 324 static assert(isInputRange!(A)); 325 static assert(isInputRange!(B)); 326 327 auto emptyRange = new A(); 328 emptyRange.assertEmpty(); 329 330 B infiniteRange = B.init; 331 infiniteRange.takeNone.assertEmpty(); 332 333 // Assert a DUnitAssertError is thrown if assertEmpty fails. 334 infiniteRange.assertEmpty().assertThrow!(DUnitAssertError)("Failed asserting empty range"); 335 infiniteRange.take(10).assertEmpty().assertThrow!(DUnitAssertError)("Failed asserting empty range"); 336 } 337 338 /** 339 * Assert that a string ends with a particular string. 340 * 341 * Params: 342 * value = The value used during the assertion. 343 * suffix = The suffix to match. 344 * message = The error message to display. 345 * file = The file name where the error occurred. The value is added automatically at the call site. 346 * line = The line where the error occurred. The value is added automatically at the call site. 347 * 348 * Throws: 349 * DUnitAssertError if the assertation fails. 350 */ 351 public void assertEndsWith(string value, string suffix, string message = "Failed asserting ends with", string file = __FILE__, size_t line = __LINE__) 352 { 353 if (!endsWith(value, suffix)) 354 { 355 auto error = new DUnitAssertError(message, file, line); 356 357 error.addExpectation("Expected end", "..." ~ suffix); 358 error.addError("Actual value", value); 359 360 throw error; 361 } 362 } 363 364 /// 365 unittest 366 { 367 "foo bar".assertEndsWith("bar"); 368 "baz qux".assertEndsWith("qux"); 369 370 // Assert a DUnitAssertError is thrown if assertEndsWith fails. 371 "foo".assertEndsWith("bar").assertThrow!(DUnitAssertError)("Failed asserting ends with"); 372 } 373 374 /** 375 * Assert that two values are equal. 376 * 377 * Params: 378 * value = The value used during the assertion. 379 * target = The target value. 380 * message = The error message to display. 381 * file = The file name where the error occurred. The value is added automatically at the call site. 382 * line = The line where the error occurred. The value is added automatically at the call site. 383 * 384 * Throws: 385 * DUnitAssertError if the assertation fails. 386 */ 387 public void assertEqual(A, B)(A value, B target, string message = "Failed asserting equal", string file = __FILE__, size_t line = __LINE__) 388 { 389 if (target != value) 390 { 391 auto error = new DUnitAssertError(message, file, line); 392 393 error.addTypedExpectation("Expected value", target); 394 error.addTypedError("Actual value", value); 395 396 throw error; 397 } 398 } 399 400 /// 401 unittest 402 { 403 123.assertEqual(123); 404 "hello".assertEqual("hello"); 405 406 // Assert a DUnitAssertError is thrown if assertEqual fails. 407 1.assertEqual(2).assertThrow!(DUnitAssertError)("Failed asserting equal"); 408 } 409 410 /** 411 * Assert that a boolean value is false. 412 * 413 * Params: 414 * value = The value used during the assertion. 415 * message = The error message to display. 416 * file = The file name where the error occurred. The value is added automatically at the call site. 417 * line = The line where the error occurred. The value is added automatically at the call site. 418 * 419 * Throws: 420 * DUnitAssertError if the assertation fails. 421 */ 422 public void assertFalse(T)(T value, string message = "Failed asserting false", string file = __FILE__, size_t line = __LINE__) 423 { 424 value.assertType!(bool)("Wrong type for asserting false", file, line); 425 426 if (value) 427 { 428 auto error = new DUnitAssertError(message, file, line); 429 430 error.addError("Value", value); 431 432 throw error; 433 } 434 } 435 436 /// 437 unittest 438 { 439 false.assertFalse(); 440 441 // Assert a DUnitAssertError is thrown if assertFalse fails. 442 true.assertFalse().assertThrow!(DUnitAssertError)("Failed asserting false"); 443 } 444 445 /** 446 * Assert that a value evaluates as false. 447 * 448 * Params: 449 * value = The value used during the assertion. 450 * message = The error message to display. 451 * file = The file name where the error occurred. The value is added automatically at the call site. 452 * line = The line where the error occurred. The value is added automatically at the call site. 453 * 454 * Throws: 455 * DUnitAssertError if the assertation fails. 456 */ 457 public void assertFalsey(T)(T value, string message = "Failed asserting falsey", string file = __FILE__, size_t line = __LINE__) 458 { 459 if (value) 460 { 461 auto error = new DUnitAssertError(message, file, line); 462 463 error.addTypedInfo("Value", value); 464 error.addError("Evaluates to", !!value); 465 466 throw error; 467 } 468 } 469 470 /// 471 unittest 472 { 473 false.assertFalsey(); 474 [].assertFalsey(); 475 null.assertFalsey(); 476 0.assertFalsey(); 477 478 // Assert a DUnitAssertError is thrown if assertFalsey fails. 479 true.assertFalsey().assertThrow!(DUnitAssertError)("Failed asserting falsey"); 480 } 481 482 /** 483 * Assert that a value is greater than a threshold value. 484 * 485 * Params: 486 * value = The value used during the assertion. 487 * threshold = The threshold value. 488 * message = The error message to display. 489 * file = The file name where the error occurred. The value is added automatically at the call site. 490 * line = The line where the error occurred. The value is added automatically at the call site. 491 * 492 * Throws: 493 * DUnitAssertError if the assertation fails. 494 */ 495 public void assertGreaterThan(A, B)(A value, B threshold, string message = "Failed asserting greater than", string file = __FILE__, size_t line = __LINE__) 496 { 497 if (value <= threshold) 498 { 499 auto error = new DUnitAssertError(message, file, line); 500 501 error.addExpectation("Minimum value", threshold + 1); 502 error.addError("Actual value", value); 503 504 throw error; 505 } 506 } 507 508 /// 509 unittest 510 { 511 11.assertGreaterThan(10); 512 513 // Assert a DUnitAssertError is thrown if assertGreaterThan fails. 514 11.assertGreaterThan(12).assertThrow!(DUnitAssertError)("Failed asserting greater than"); 515 } 516 517 /** 518 * Assert that a value is greater than or equal to a threshold value. 519 * 520 * Params: 521 * value = The value used during the assertion. 522 * threshold = The threshold value. 523 * message = The error message to display. 524 * file = The file name where the error occurred. The value is added automatically at the call site. 525 * line = The line where the error occurred. The value is added automatically at the call site. 526 * 527 * Throws: 528 * DUnitAssertError if the assertation fails. 529 */ 530 public void assertGreaterThanOrEqual(A, B)(A value, B threshold, string message = "Failed asserting greater than or equal", string file = __FILE__, size_t line = __LINE__) 531 { 532 if (value < threshold) 533 { 534 auto error = new DUnitAssertError(message, file, line); 535 536 error.addExpectation("Minimum value", threshold); 537 error.addError("Actual value", value); 538 539 throw error; 540 } 541 } 542 543 /// 544 unittest 545 { 546 10.assertGreaterThanOrEqual(10); 547 11.assertGreaterThanOrEqual(10); 548 549 // Assert a DUnitAssertError is thrown if assertGreaterThanOrEqual fails. 550 11.assertGreaterThanOrEqual(12).assertThrow!(DUnitAssertError)("Failed asserting greater than or equal"); 551 } 552 553 /** 554 * Assert that an associative array contains a particular key. 555 * 556 * Params: 557 * haystack = The associative array to interogate. 558 * needle = The key the array should contain. 559 * message = The error message to display. 560 * file = The file name where the error occurred. The value is added automatically at the call site. 561 * line = The line where the error occurred. The value is added automatically at the call site. 562 * 563 * Throws: 564 * DUnitAssertError if the assertation fails. 565 */ 566 public void assertHasKey(A, B)(A haystack, B needle, string message = "Failed asserting array has key", string file = __FILE__, size_t line = __LINE__) if (isAssociativeArray!(A)) 567 { 568 if (needle !in haystack) 569 { 570 auto error = new DUnitAssertError(message, file, line); 571 572 error.addInfo("Array type", typeof(haystack).stringof); 573 error.addInfo("Elements", haystack); 574 error.addTypedError("Missing key", needle); 575 576 throw error; 577 } 578 } 579 580 /// 581 unittest 582 { 583 ["foo":1, "bar":2, "baz":3, "qux":4].assertHasKey("foo"); 584 [1:"foo", 2:"bar", 3:"baz", 4:"qux"].assertHasKey(1); 585 586 // Assert a DUnitAssertError is thrown if assertHasKey fails. 587 ["foo":"bar"].assertHasKey("baz").assertThrow!(DUnitAssertError)("Failed asserting array has key"); 588 } 589 590 /** 591 * Assert that an array contains a particular value. 592 * 593 * Params: 594 * haystack = The array to interogate. 595 * needle = The value the array should contain. 596 * message = The error message to display. 597 * file = The file name where the error occurred. The value is added automatically at the call site. 598 * line = The line where the error occurred. The value is added automatically at the call site. 599 * 600 * Throws: 601 * DUnitAssertError if the assertation fails. 602 */ 603 public void assertHasValue(A, B)(A haystack, B needle, string message = "Failed asserting array has value", string file = __FILE__, size_t line = __LINE__) if (isArray!(A) || isAssociativeArray!(A)) 604 { 605 static if (isArray!(A)) 606 { 607 bool foundValue = canFind(haystack, needle); 608 } 609 else static if (isAssociativeArray!(A)) 610 { 611 bool foundValue = canFind(haystack.values, needle); 612 } 613 614 if (!foundValue) 615 { 616 auto error = new DUnitAssertError(message, file, line); 617 618 error.addInfo("Array type", typeof(haystack).stringof); 619 error.addInfo("Elements", haystack); 620 error.addTypedError("Missing value", needle); 621 622 throw error; 623 } 624 } 625 626 /// 627 unittest 628 { 629 "Hello".assertHasValue("H"); 630 [1, 2, 3, 4].assertHasValue(2); 631 ["foo", "bar", "baz", "qux"].assertHasValue("foo"); 632 [["foo", "bar"], ["baz", "qux"]].assertHasValue(["foo", "bar"]); 633 ["foo":1, "bar":2, "baz":3, "qux":4].assertHasValue(4); 634 635 // Assert a DUnitAssertError is thrown if assertHasValue fails. 636 ["foo":"bar"].assertHasValue("baz").assertThrow!(DUnitAssertError)("Failed asserting array has value"); 637 } 638 639 /** 640 * Assert that a value is an instance of a type. 641 * 642 * Params: 643 * value = The value used during the assertion. 644 * message = The error message to display. 645 * file = The file name where the error occurred. The value is added automatically at the call site. 646 * line = The line where the error occurred. The value is added automatically at the call site. 647 * 648 * Throws: 649 * DUnitAssertError if the assertation fails. 650 */ 651 public void assertInstanceOf(A, B)(B value, string message = "Failed asserting instance of", string file = __FILE__, size_t line = __LINE__) 652 { 653 if (!cast(A)value) 654 { 655 auto error = new DUnitAssertError(message, file, line); 656 657 error.addExpectation("Expected instance", A.stringof); 658 error.addError("Non derived type", B.stringof); 659 660 throw error; 661 } 662 } 663 664 /// 665 unittest 666 { 667 interface A {} 668 class B : A {} 669 class C : B {} 670 671 auto b = new B(); 672 auto c = new C(); 673 674 b.assertInstanceOf!(Object)(); 675 b.assertInstanceOf!(A)(); 676 b.assertInstanceOf!(B)(); 677 678 c.assertInstanceOf!(Object)(); 679 c.assertInstanceOf!(A)(); 680 c.assertInstanceOf!(B)(); 681 c.assertInstanceOf!(C)(); 682 683 // Assert a DUnitAssertError is thrown if assertInstanceOf fails. 684 b.assertInstanceOf!(C)().assertThrow!(DUnitAssertError)("Failed asserting instance of"); 685 } 686 687 /** 688 * Assert that a value is less than a threshold value. 689 * 690 * Params: 691 * value = The value used during the assertion. 692 * threshold = The threshold value. 693 * message = The error message to display. 694 * file = The file name where the error occurred. The value is added automatically at the call site. 695 * line = The line where the error occurred. The value is added automatically at the call site. 696 * 697 * Throws: 698 * DUnitAssertError if the assertation fails. 699 */ 700 public void assertLessThan(A, B)(A value, B threshold, string message = "Failed asserting less than", string file = __FILE__, size_t line = __LINE__) 701 { 702 if (value >= threshold) 703 { 704 auto error = new DUnitAssertError(message, file, line); 705 706 error.addExpectation("Maximum value", threshold - 1); 707 error.addError("Actual value", value); 708 709 throw error; 710 } 711 } 712 713 /// 714 unittest 715 { 716 9.assertLessThan(10); 717 718 // Assert a DUnitAssertError is thrown if assertLessThan fails. 719 9.assertLessThan(8).assertThrow!(DUnitAssertError)("Failed asserting less than"); 720 } 721 722 /** 723 * Assert that a value is less than or equal to a threshold value. 724 * 725 * Params: 726 * value = The value used during the assertion. 727 * threshold = The threshold value. 728 * message = The error message to display. 729 * file = The file name where the error occurred. The value is added automatically at the call site. 730 * line = The line where the error occurred. The value is added automatically at the call site. 731 * 732 * Throws: 733 * DUnitAssertError if the assertation fails. 734 */ 735 public void assertLessThanOrEqual(A, B)(A value, B threshold, string message = "Failed asserting less than or equal", string file = __FILE__, size_t line = __LINE__) 736 { 737 if (value > threshold) 738 { 739 auto error = new DUnitAssertError(message, file, line); 740 741 error.addExpectation("Maximum value", threshold); 742 error.addError("Actual value", value); 743 744 throw error; 745 } 746 } 747 748 /// 749 unittest 750 { 751 10.assertLessThanOrEqual(10); 752 9.assertLessThanOrEqual(10); 753 754 // Assert a DUnitAssertError is thrown if assertLessThanOrEqual fails. 755 9.assertLessThanOrEqual(8).assertThrow!(DUnitAssertError)("Failed asserting less than or equal"); 756 } 757 758 /** 759 * Assert that a string matches a regular expression. 760 * 761 * Params: 762 * value = The value used during the assertion. 763 * pattern = The regular expression pattern. 764 * message = The error message to display. 765 * file = The file name where the error occurred. The value is added automatically at the call site. 766 * line = The line where the error occurred. The value is added automatically at the call site. 767 * 768 * Throws: 769 * DUnitAssertError if the assertation fails. 770 */ 771 public void assertMatchRegex(string value, string pattern, string message = "Failed asserting match to regex", string file = __FILE__, size_t line = __LINE__) 772 { 773 if (match(value, pattern).empty()) 774 { 775 auto error = new DUnitAssertError(message, file, line); 776 777 error.addInfo("Regex", pattern); 778 error.addError("Value", value); 779 780 throw error; 781 } 782 } 783 784 /// 785 unittest 786 { 787 "foo".assertMatchRegex(r"^foo$"); 788 "192.168.0.1".assertMatchRegex(r"((?:[\d]{1,3}\.){3}[\d]{1,3})"); 789 790 // Assert a DUnitAssertError is thrown if assertMatchRegex fails. 791 "foo".assertMatchRegex(r"^bar$").assertThrow!(DUnitAssertError)("Failed asserting match to regex"); 792 } 793 794 /** 795 * Assert that a value is null. 796 * 797 * Params: 798 * value = The value to assert as null. 799 * message = The error message to display. 800 * file = The file name where the error occurred. The value is added automatically at the call site. 801 * line = The line where the error occurred. The value is added automatically at the call site. 802 * 803 * Throws: 804 * DUnitAssertError if the assertation fails. 805 */ 806 public void assertNull(A)(A value, string message = "Failed asserting null", string file = __FILE__, size_t line = __LINE__) if (A.init is null) 807 { 808 if (value !is null) 809 { 810 auto error = new DUnitAssertError(message, file, line); 811 812 error.addTypedError("Actual value", value); 813 814 throw error; 815 816 } 817 } 818 819 /// 820 unittest 821 { 822 class T {} 823 824 string foo; 825 int[] bar; 826 T t; 827 828 foo.assertNull(); 829 bar.assertNull(); 830 t.assertNull(); 831 null.assertNull(); 832 833 // Assert a DUnitAssertError is thrown if assertNull fails. 834 "foo".assertNull().assertThrow!(DUnitAssertError)("Failed asserting null"); 835 } 836 837 /** 838 * Assert that a string starts with a particular string. 839 * 840 * Params: 841 * value = The value used during the assertion. 842 * prefix = The prefix to match. 843 * message = The error message to display. 844 * file = The file name where the error occurred. The value is added automatically at the call site. 845 * line = The line where the error occurred. The value is added automatically at the call site. 846 * 847 * Throws: 848 * DUnitAssertError if the assertation fails. 849 */ 850 public void assertStartsWith(string value, string prefix, string message = "Failed asserting starts with", string file = __FILE__, size_t line = __LINE__) 851 { 852 if (!startsWith(value, prefix)) 853 { 854 auto error = new DUnitAssertError(message, file, line); 855 856 error.addExpectation("Expected start", prefix ~ "..."); 857 error.addError("Actual value", value); 858 859 throw error; 860 } 861 } 862 863 /// 864 unittest 865 { 866 "foo bar".assertStartsWith("foo"); 867 "baz qux".assertStartsWith("baz"); 868 869 // Assert a DUnitAssertError is thrown if assertStartsWith fails. 870 "foo bar".assertStartsWith("baz").assertThrow!(DUnitAssertError)("Failed asserting starts with"); 871 } 872 873 /** 874 * Assert that an expression throws an exception. 875 * 876 * Params: 877 * expression = The expression to evaluate in order to assert the exception is thrown. 878 * expressionMsg = An optional expected message of the thrown exception. 879 * message = The error message to display. 880 * file = The file name where the error occurred. The value is added automatically at the call site. 881 * line = The line where the error occurred. The value is added automatically at the call site. 882 * 883 * Throws: 884 * DUnitAssertError if the assertation fails. 885 */ 886 public void assertThrow(A : Throwable = Exception, B)(lazy B expression, string expressionMsg = null, string message = "Failed asserting throw", string file = __FILE__, size_t line = __LINE__) 887 { 888 try 889 { 890 try 891 { 892 expression; 893 } 894 catch (A ex) 895 { 896 if (expressionMsg !is null && expressionMsg != ex.msg) 897 { 898 auto error = new DUnitAssertError(message, file, line); 899 900 error.addExpectation("Expected message", expressionMsg); 901 error.addError("Thrown message", ex.msg); 902 903 throw error; 904 } 905 return; 906 } 907 } 908 catch (Exception ex) 909 { 910 // If the expression throws an exception other than the one specified just let it pass. 911 // We can't get any meaningful information about what was thrown anyway. 912 } 913 914 auto error = new DUnitAssertError(message, file, line); 915 916 error.addError("Expected exception", A.stringof); 917 918 throw error; 919 } 920 921 /// 922 unittest 923 { 924 import core.exception : AssertError, RangeError; 925 926 class Foo : Exception 927 { 928 this(string message) 929 { 930 super(message); 931 } 932 } 933 934 class Bar 935 { 936 public void baz() 937 { 938 throw new Foo("Thrown from baz."); 939 } 940 } 941 942 auto bar = new Bar(); 943 bar.baz().assertThrow(); 944 bar.baz().assertThrow!(Foo)("Thrown from baz."); 945 946 delegate(){throw new Foo("Thrown from delegate.");}().assertThrow!(Exception)("Thrown from delegate."); 947 948 auto baz = [0, 1, 2]; 949 baz[3].assertThrow!(RangeError)(); 950 951 assert(false).assertThrow!(AssertError)("Assertion failure"); 952 953 // Assert a DUnitAssertError is thrown if assertThrow fails. 954 null.assertThrow().assertThrow!(DUnitAssertError)("Failed asserting throw"); 955 956 // Assert a DUnitAssertError is thrown if assertThrow fails due to mismatched error message. 957 baz[3].assertThrow!(RangeError)("Foo").assertThrow!(DUnitAssertError)("Failed asserting throw"); 958 } 959 960 /** 961 * Assert that a boolean value is true. 962 * 963 * Params: 964 * value = The value used during the assertion. 965 * message = The error message to display. 966 * file = The file name where the error occurred. The value is added automatically at the call site. 967 * line = The line where the error occurred. The value is added automatically at the call site. 968 * 969 * Throws: 970 * DUnitAssertError if the assertation fails. 971 */ 972 public void assertTrue(T)(T value, string message = "Failed asserting true", string file = __FILE__, size_t line = __LINE__) 973 { 974 value.assertType!(bool)("Wrong type for asserting true", file, line); 975 976 if (!value) 977 { 978 auto error = new DUnitAssertError(message, file, line); 979 980 error.addError("Value", value); 981 982 throw error; 983 } 984 } 985 986 /// 987 unittest 988 { 989 true.assertTrue(); 990 991 // Assert a DUnitAssertError is thrown if assertTrue fails. 992 false.assertTrue().assertThrow!(DUnitAssertError)("Failed asserting true"); 993 } 994 995 /** 996 * Assert that a value evaluates as true. 997 * 998 * Params: 999 * value = The value used during the assertion. 1000 * message = The error message to display. 1001 * file = The file name where the error occurred. The value is added automatically at the call site. 1002 * line = The line where the error occurred. The value is added automatically at the call site. 1003 * 1004 * Throws: 1005 * DUnitAssertError if the assertation fails. 1006 */ 1007 public void assertTruthy(T)(T value, string message = "Failed asserting truthy", string file = __FILE__, size_t line = __LINE__) 1008 { 1009 if (!value) 1010 { 1011 auto error = new DUnitAssertError(message, file, line); 1012 1013 error.addTypedInfo("Value", value); 1014 error.addError("Evaluates to", !!value); 1015 1016 throw error; 1017 } 1018 } 1019 1020 /// 1021 unittest 1022 { 1023 true.assertTruthy(); 1024 ["foo"].assertTruthy(); 1025 1.assertTruthy(); 1026 1027 // Assert a DUnitAssertError is thrown if assertTruthy fails. 1028 false.assertTruthy().assertThrow!(DUnitAssertError)("Failed asserting truthy"); 1029 } 1030 1031 /** 1032 * Assert that a value is of a particular type. 1033 * 1034 * Params: 1035 * value = The value used during the assertion. 1036 * message = The error message to display. 1037 * file = The file name where the error occurred. The value is added automatically at the call site. 1038 * line = The line where the error occurred. The value is added automatically at the call site. 1039 * 1040 * Throws: 1041 * DUnitAssertError if the assertation fails. 1042 */ 1043 public void assertType(A, B)(B value, string message = "Failed asserting type", string file = __FILE__, size_t line = __LINE__) 1044 { 1045 if (!is(A == B)) 1046 { 1047 auto error = new DUnitAssertError(message, file, line); 1048 1049 error.addExpectation("Expected type", A.stringof); 1050 error.addError("Actual type", B.stringof); 1051 1052 throw error; 1053 } 1054 } 1055 1056 /// 1057 unittest 1058 { 1059 1.assertType!(int)(); 1060 "foo".assertType!(string)(); 1061 ["bar"].assertType!(string[])(); 1062 ['a'].assertType!(char[])(); 1063 1064 // Assert a DUnitAssertError is thrown if assertType fails. 1065 false.assertType!(string)().assertThrow!(DUnitAssertError)("Failed asserting type"); 1066 }