1 module dshould.thrown; 2 3 import std.format : format; 4 import std.traits : CommonType; 5 import std.typecons; 6 import dshould.ShouldType; 7 8 unittest 9 { 10 import dshould.basic : be, equal, not, should; 11 12 auto error = new Exception(""); 13 14 /** 15 * Throws: Exception 16 */ 17 void throwsException() { throw error; } 18 19 throwsException.should.throwAn!Exception.where.it.should.be(error); 20 throwsException.should.throwAn!Exception.where.it.should.not.be(null); 21 22 2.should.be(5).because("it just should, okay") 23 .should.throwA!FluentException.where.its.reason.should.equal("it just should, okay"); 24 25 2.should.be(5).should.throwA!FluentException; 26 2.should.be(5).should.throwAn!Error.should.throwA!FluentException; 27 28 2.should.be(2).should.not.throwA!FluentException; 29 30 2.should.be(5).should.throwA!FluentException("test"); 31 } 32 33 template throwA(T : Throwable) 34 { 35 auto throwA(Should)(Should should, string file = __FILE__, size_t line = __LINE__) 36 if (isInstanceOf!(ShouldType, Should)) 37 { 38 should.allowOnlyWordsBefore!(["not"], "throwA"); 39 40 should.terminateChain; 41 42 FluentException innerError = null; 43 44 auto inner() 45 { 46 try 47 { 48 should.data.lhs(); 49 } 50 catch (T throwable) 51 { 52 static if (should.hasWord!"not") 53 { 54 innerError = new FluentException( 55 format!`expected no %s`(T.stringof), 56 format!`, but expression threw %s`(throwable), 57 file, line 58 ); 59 } 60 else 61 { 62 return throwable; 63 } 64 } 65 66 static if (!should.hasWord!"not") 67 { 68 return null; 69 } 70 } 71 72 try 73 { 74 static if (is(typeof(inner()) == void)) 75 { 76 inner; 77 } 78 else 79 { 80 if (auto throwable = inner()) 81 { 82 return tuple!"where"(tuple!("it", "its")(throwable, throwable)); 83 } 84 } 85 } 86 // don't go up beyond Exception unless we're not from beneath it: 87 // keeps us from needlessly breaking purity. 88 catch (CommonType!(Exception, T) otherThrowable) 89 { 90 static if (should.hasWord!"not") 91 { 92 return; 93 } 94 else 95 { 96 throw new FluentException( 97 format!`expected %s`(T.stringof), 98 format!`, but expression threw %s`(otherThrowable), 99 file, line 100 ); 101 } 102 } 103 104 static if (should.hasWord!"not") 105 { 106 if (innerError !is null) 107 { 108 throw innerError; 109 } 110 } 111 else 112 { 113 throw new FluentException( 114 format!`expected %s`(T.stringof), 115 `, but expression did not throw.`, 116 file, line 117 ); 118 } 119 } 120 } 121 122 alias throwAn = throwA; 123 124 T because(T)(lazy T value, string reason) 125 { 126 try 127 { 128 return value; 129 } 130 catch (FluentException fluentException) 131 { 132 throw fluentException.because(reason); 133 } 134 }