1 module fluentasserts.core.operations.throwable; 2 3 public import fluentasserts.core.base; 4 import fluentasserts.core.results; 5 import fluentasserts.core.lifecycle; 6 import fluentasserts.core.expect; 7 import fluentasserts.core.serializers; 8 9 import std..string; 10 import std.conv; 11 import std.algorithm; 12 import std.array; 13 14 version(unittest) { 15 class CustomException : Exception { 16 this(string msg, string fileName = "", size_t line = 0, Throwable next = null) { 17 super(msg, fileName, line, next); 18 } 19 } 20 } 21 22 /// 23 IResult[] throwAnyException(ref Evaluation evaluation) @trusted nothrow { 24 IResult[] results; 25 26 evaluation.message.addText(". "); 27 auto thrown = evaluation.currentValue.throwable; 28 29 if(evaluation.currentValue.throwable && evaluation.isNegated) { 30 string message; 31 try message = thrown.message.to!string; catch(Exception) {} 32 33 evaluation.message.addText("`"); 34 evaluation.message.addValue(thrown.classinfo.name); 35 evaluation.message.addText("` saying `"); 36 evaluation.message.addValue(message); 37 evaluation.message.addText("` was thrown."); 38 39 try results ~= new ExpectedActualResult("No exception to be thrown", "`" ~ thrown.classinfo.name ~ "` saying `" ~ message ~ "`"); catch(Exception) {} 40 } 41 42 if(!thrown && !evaluation.isNegated) { 43 evaluation.message.addText("No exception was thrown."); 44 45 try results ~= new ExpectedActualResult("Any exception to be thrown", "Nothing was thrown"); catch(Exception) {} 46 } 47 48 if(thrown && !evaluation.isNegated && "Throwable" in evaluation.currentValue.meta) { 49 string message; 50 try message = thrown.message.to!string; catch(Exception) {} 51 52 evaluation.message.addText("A `Throwable` saying `" ~ message ~ "` was thrown."); 53 54 try results ~= new ExpectedActualResult("Any exception to be thrown", "A `Throwable` with message `" ~ message ~ "` was thrown"); catch(Exception) {} 55 } 56 57 evaluation.throwable = thrown; 58 evaluation.currentValue.throwable = null; 59 60 return results; 61 } 62 63 /// It should be successfull when the function does not throw 64 unittest { 65 void test() {} 66 expect({ test(); }).to.not.throwAnyException(); 67 } 68 69 /// It should fail when an exception is thrown and none is expected 70 unittest { 71 void test() { throw new Exception("Test exception"); } 72 73 bool thrown; 74 75 try { 76 expect({ test(); }).to.not.throwAnyException(); 77 } catch(TestException e) { 78 thrown = true; 79 80 assert(e.message.indexOf("should not throw any exception. `object.Exception` saying `Test exception` was thrown.") != -1); 81 assert(e.message.indexOf("\n Expected:No exception to be thrown\n") != -1); 82 assert(e.message.indexOf("\n Actual:`object.Exception` saying `Test exception`\n") != -1); 83 } 84 85 assert(thrown, "The exception was not thrown"); 86 } 87 88 /// It should be successfull when the function throws an expected exception 89 unittest { 90 void test() { throw new Exception("test"); } 91 expect({ test(); }).to.throwAnyException; 92 } 93 94 /// It should not be successfull when the function throws a throwable and an exception is expected 95 unittest { 96 void test() { assert(false); } 97 98 bool thrown; 99 100 try { 101 expect({ test(); }).to.throwAnyException; 102 } catch(TestException e) { 103 thrown = true; 104 105 assert(e.message.indexOf("should throw any exception. A `Throwable` saying `Assertion failure` was thrown.") != -1); 106 assert(e.message.indexOf("\n Expected:Any exception to be thrown\n") != -1); 107 assert(e.message.indexOf("\n Actual:A `Throwable` with message `Assertion failure` was thrown\n") != -1); 108 assert(e.file == "source/fluentasserts/core/operations/throwable.d"); 109 } 110 111 assert(thrown, "The exception was not thrown"); 112 } 113 114 /// It should be successfull when the function throws an expected exception 115 unittest { 116 void test() { throw new Exception("test"); } 117 expect({ test(); }).to.throwAnyException; 118 } 119 120 IResult[] throwAnyExceptionWithMessage(ref Evaluation evaluation) @trusted nothrow { 121 IResult[] results; 122 123 auto thrown = evaluation.currentValue.throwable; 124 125 126 if(thrown !is null && evaluation.isNegated) { 127 string message; 128 try message = thrown.message.to!string; catch(Exception) {} 129 130 evaluation.message.addText("`"); 131 evaluation.message.addValue(thrown.classinfo.name); 132 evaluation.message.addText("` saying `"); 133 evaluation.message.addValue(message); 134 evaluation.message.addText("` was thrown."); 135 136 try results ~= new ExpectedActualResult("No exception to be thrown", "`" ~ thrown.classinfo.name ~ "` saying `" ~ message ~ "`"); catch(Exception) {} 137 } 138 139 if(thrown is null && !evaluation.isNegated) { 140 evaluation.message.addText("Nothing was thrown."); 141 142 try results ~= new ExpectedActualResult("Any exception to be thrown", "Nothing was thrown"); catch(Exception) {} 143 } 144 145 if(thrown && !evaluation.isNegated && "Throwable" in evaluation.currentValue.meta) { 146 string message; 147 try message = thrown.message.to!string; catch(Exception) {} 148 149 evaluation.message.addText(". A `Throwable` saying `" ~ message ~ "` was thrown."); 150 151 try results ~= new ExpectedActualResult("Any throwable with the message `" ~ message ~ "` to be thrown", "A `" ~ thrown.classinfo.name ~ "` with message `" ~ message ~ "` was thrown"); catch(Exception) {} 152 } 153 154 evaluation.throwable = thrown; 155 evaluation.currentValue.throwable = null; 156 157 return results; 158 } 159 160 /// 161 IResult[] throwException(ref Evaluation evaluation) @trusted nothrow { 162 evaluation.message.addText("."); 163 164 string exceptionType; 165 166 if("exceptionType" in evaluation.expectedValue.meta) { 167 exceptionType = evaluation.expectedValue.meta["exceptionType"].cleanString; 168 } 169 170 IResult[] results; 171 auto thrown = evaluation.currentValue.throwable; 172 173 if(thrown && evaluation.isNegated && thrown.classinfo.name == exceptionType) { 174 string message; 175 try message = thrown.message.to!string; catch(Exception) {} 176 177 evaluation.message.addText("`"); 178 evaluation.message.addValue(thrown.classinfo.name); 179 evaluation.message.addText("` saying `"); 180 evaluation.message.addValue(message); 181 evaluation.message.addText("` was thrown."); 182 183 try results ~= new ExpectedActualResult("no `" ~ exceptionType ~ "` to be thrown", "`" ~ thrown.classinfo.name ~ "` saying `" ~ message ~ "`"); catch(Exception) {} 184 } 185 186 if(thrown && !evaluation.isNegated && thrown.classinfo.name != exceptionType) { 187 string message; 188 try message = thrown.message.to!string; catch(Exception) {} 189 190 evaluation.message.addText("`"); 191 evaluation.message.addValue(thrown.classinfo.name); 192 evaluation.message.addText("` saying `"); 193 evaluation.message.addValue(message); 194 evaluation.message.addText("` was thrown."); 195 196 try results ~= new ExpectedActualResult(exceptionType, "`" ~ thrown.classinfo.name ~ "` saying `" ~ message ~ "`"); catch(Exception) {} 197 } 198 199 evaluation.throwable = thrown; 200 evaluation.currentValue.throwable = null; 201 202 return results; 203 } 204 205 /// Should be able to catch a certain exception type 206 unittest { 207 expect({ 208 throw new CustomException("test"); 209 }).to.throwException!CustomException; 210 } 211 212 /// It should fail when an unexpected exception is thrown 213 unittest { 214 bool thrown; 215 216 try { 217 expect({ 218 throw new Exception("test"); 219 }).to.throwException!CustomException; 220 } catch(TestException e) { 221 thrown = true; 222 223 assert(e.message.indexOf("should throw exception \"fluentasserts.core.operations.throwable.CustomException\".`object.Exception` saying `test` was thrown.") != -1); 224 assert(e.message.indexOf("\n Expected:fluentasserts.core.operations.throwable.CustomException\n") != -1); 225 assert(e.message.indexOf("\n Actual:`object.Exception` saying `test`\n") != -1); 226 assert(e.file == "source/fluentasserts/core/operations/throwable.d"); 227 } 228 229 assert(thrown, "The exception was not thrown"); 230 } 231 232 /// It should not fail when an exception is thrown and it is not expected 233 unittest { 234 expect({ 235 throw new Exception("test"); 236 }).to.not.throwException!CustomException; 237 } 238 239 /// It should fail when an different exception than the one checked is thrown 240 unittest { 241 bool thrown; 242 243 try { 244 expect({ 245 throw new CustomException("test"); 246 }).to.not.throwException!CustomException; 247 } catch(TestException e) { 248 thrown = true; 249 assert(e.message.indexOf("should not throw exception \"fluentasserts.core.operations.throwable.CustomException\".`fluentasserts.core.operations.throwable.CustomException` saying `test` was thrown.") != -1); 250 assert(e.message.indexOf("\n Expected:no `fluentasserts.core.operations.throwable.CustomException` to be thrown\n") != -1); 251 assert(e.message.indexOf("\n Actual:`fluentasserts.core.operations.throwable.CustomException` saying `test`\n") != -1); 252 assert(e.file == "source/fluentasserts/core/operations/throwable.d"); 253 } 254 255 assert(thrown, "The exception was not thrown"); 256 } 257 258 /// 259 IResult[] throwExceptionWithMessage(ref Evaluation evaluation) @trusted nothrow { 260 import std.stdio; 261 262 263 evaluation.message.addText(". "); 264 265 string exceptionType; 266 string message; 267 string expectedMessage = evaluation.expectedValue.strValue; 268 269 if(expectedMessage.startsWith(`"`)) { 270 expectedMessage = expectedMessage[1..$-1]; 271 } 272 273 if("exceptionType" in evaluation.expectedValue.meta) { 274 exceptionType = evaluation.expectedValue.meta["exceptionType"].cleanString; 275 } 276 277 IResult[] results; 278 auto thrown = evaluation.currentValue.throwable; 279 evaluation.throwable = thrown; 280 evaluation.currentValue.throwable = null; 281 282 if(thrown) { 283 try message = thrown.message.to!string; catch(Exception) {} 284 } 285 286 if(!thrown && !evaluation.isNegated) { 287 evaluation.message.addText("No exception was thrown."); 288 289 try results ~= new ExpectedActualResult("`" ~ exceptionType ~ "` with message `" ~ expectedMessage ~ "` to be thrown", "nothing was thrown"); catch(Exception) {} 290 } 291 292 if(thrown && !evaluation.isNegated && thrown.classinfo.name != exceptionType) { 293 evaluation.message.addText("`"); 294 evaluation.message.addValue(thrown.classinfo.name); 295 evaluation.message.addText("` saying `"); 296 evaluation.message.addValue(message); 297 evaluation.message.addText("` was thrown."); 298 299 try results ~= new ExpectedActualResult("`" ~ exceptionType ~ "` to be thrown", "`" ~ thrown.classinfo.name ~ "` saying `" ~ message ~ "`"); catch(Exception) {} 300 } 301 302 if(thrown && !evaluation.isNegated && thrown.classinfo.name == exceptionType && message != expectedMessage) { 303 evaluation.message.addText("`"); 304 evaluation.message.addValue(thrown.classinfo.name); 305 evaluation.message.addText("` saying `"); 306 evaluation.message.addValue(message); 307 evaluation.message.addText("` was thrown."); 308 309 try results ~= new ExpectedActualResult("`" ~ exceptionType ~ "` saying `" ~ message ~ "` to be thrown", "`" ~ thrown.classinfo.name ~ "` saying `" ~ message ~ "`"); catch(Exception) {} 310 } 311 312 return results; 313 } 314 315 /// It fails when an exception is not catched 316 unittest { 317 Exception exception; 318 319 try { 320 expect({}).to.throwException!Exception.withMessage.equal("test"); 321 } catch(Exception e) { 322 exception = e; 323 } 324 325 assert(exception !is null); 326 expect(exception.message).to.contain(`should throw exception with message equal "test". No exception was thrown.`); 327 } 328 329 /// It does not fail when an exception is not expected and none is not catched 330 unittest { 331 Exception exception; 332 333 try { 334 expect({}).not.to.throwException!Exception.withMessage.equal("test"); 335 } catch(Exception e) { 336 exception = e; 337 } 338 339 assert(exception is null); 340 } 341 342 /// It fails when the caught exception has a different type 343 unittest { 344 Exception exception; 345 346 try { 347 expect({ 348 throw new CustomException("hello"); 349 }).to.throwException!Exception.withMessage.equal("test"); 350 } catch(Exception e) { 351 exception = e; 352 } 353 354 assert(exception !is null); 355 expect(exception.message).to.contain("should throw exception with message equal \"test\". `fluentasserts.core.operations.throwable.CustomException` saying `hello` was thrown."); 356 } 357 358 /// It does not fail when a certain exception type is not catched 359 unittest { 360 Exception exception; 361 362 try { 363 expect({ 364 throw new CustomException("hello"); 365 }).not.to.throwException!Exception.withMessage.equal("test"); 366 } catch(Exception e) { 367 exception = e; 368 } 369 370 assert(exception is null); 371 } 372 373 /// It fails when the caught exception has a different message 374 unittest { 375 Exception exception; 376 377 try { 378 expect({ 379 throw new CustomException("hello"); 380 }).to.throwException!CustomException.withMessage.equal("test"); 381 } catch(Exception e) { 382 exception = e; 383 } 384 385 assert(exception !is null); 386 expect(exception.message).to.contain("should throw exception with message equal \"test\". `fluentasserts.core.operations.throwable.CustomException` saying `hello` was thrown."); 387 } 388 389 /// It does not fails when the caught exception is expected to have a different message 390 unittest { 391 Exception exception; 392 393 try { 394 expect({ 395 throw new CustomException("hello"); 396 }).not.to.throwException!CustomException.withMessage.equal("test"); 397 } catch(Exception e) { 398 exception = e; 399 } 400 401 assert(exception is null); 402 }