1 module dshould; 2 3 import dshould.ShouldType; 4 5 public import dshould.ShouldType : because, should; 6 public import dshould.basic; 7 public import dshould.contain; 8 public import dshould.empty; 9 public import dshould.stringcmp; 10 public import dshould.thrown; 11 12 // dispatch based on type 13 /** 14 * The word `.equal` tests its parameter for equality with the left-hand side. 15 * If the parameters are strings, a colored diff is used. 16 */ 17 public void equal(Should, T)(Should should, T value, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__) 18 if (isInstanceOf!(ShouldType, Should)) 19 { 20 static if (is(typeof(should.got()) == string) && is(T == string) && !Should.hasWord!"not") 21 { 22 dshould.stringcmp.equal(should, value, Fence(), file, line); 23 } 24 else 25 { 26 dshould.basic.equal(should, value, Fence(), file, line); 27 } 28 } 29 30 public auto equal(Should)(Should should) 31 if (isInstanceOf!(ShouldType, Should)) 32 { 33 return should.basic.equal(should); 34 } 35 36 /** 37 * The word `.throwA` (or `.throwAn`) expects its left-hand side expression to throw an exception. 38 * Instead of the cumbersome `.where.msg.should.equal("msg")`, the `msg` of the Exception to expect 39 * can be passed directly. 40 */ 41 public template throwA(T : Throwable) 42 { 43 void throwA(Should)(Should should, string msgTest, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__) 44 if (isInstanceOf!(ShouldType, Should)) 45 { 46 dshould.thrown.throwA!T(should, Fence(), file, line).where.msg.should.equal(msgTest, Fence(), file, line); 47 } 48 49 auto throwA(Should)(Should should, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__) 50 if (isInstanceOf!(ShouldType, Should)) 51 { 52 return dshould.thrown.throwA!T(should, Fence(), file, line); 53 } 54 } 55 56 /// ditto 57 public alias throwAn = throwA; 58 59 @("because defines reason for assertion") 60 unittest 61 { 62 2.should.be(5).because("string A") 63 .should.throwA!FluentException.where.reason.should.equal("string A"); 64 } 65 66 @("compares messages in throwA string overload") 67 unittest 68 { 69 2.should.be(5).because("string A") 70 .should.throwA!FluentException("string B") 71 .should.throwA!FluentException; 72 } 73 74 @("prints informative errors for int comparison") 75 unittest 76 { 77 2.should.be(3).should.throwA!FluentException("Test failed: expected 3, but got 2"); 78 } 79 80 @("prints informative errors for object comparison") 81 unittest 82 { 83 Object obj; 84 85 obj.should.not.be(null) 86 .should.throwA!FluentException("Test failed: expected non-null, but got null"); 87 88 obj = new Object; 89 90 obj.should.be(null) 91 .should.throwA!FluentException("Test failed: expected null, but got object.Object"); 92 93 obj.should.not.be(obj) 94 .should.throwA!FluentException( 95 "Test failed: expected different reference than object.Object, but got same reference"); 96 97 obj.should.be(new Object) 98 .should.throwA!FluentException( 99 "Test failed: expected same reference as object.Object, but got object.Object"); 100 } 101 102 @("prints informative errors for inequalities") 103 unittest 104 { 105 2.should.be.greater.equal(5) 106 .should.throwA!FluentException("Test failed: expected value >= 5, but got 2"); 107 108 2.should.not.be.less.equal(5) 109 .should.throwA!FluentException("Test failed: expected value not <= 5, but got 2"); 110 } 111 112 @("prints informative errors for range emptiness") 113 unittest 114 { 115 [].should.not.be.empty 116 .should.throwA!FluentException("Test failed: expected nonempty range, but got []"); 117 118 [5].should.be.empty 119 .should.throwA!FluentException("Test failed: expected empty range, but got [5]"); 120 } 121 122 @("prints informative errors for approximate checks") 123 unittest 124 { 125 2.should.approximately.be(4, error=0.5) 126 .should.throwA!FluentException("Test failed: expected 4 ± 0.5, but got 2"); 127 128 (2.4).should.not.approximately.be(2, error=0.5) 129 .should.throwA!FluentException("Test failed: expected value outside 2 ± 0.5, but got 2.4"); 130 } 131 132 @("asserts when forgetting to terminate should expression") 133 unittest 134 { 135 import core.exception : AssertError; 136 137 void test() 138 { 139 2.should; 140 } 141 142 test.should.throwAn!AssertError("unterminated should-chain!"); 143 }