From a05928fb9b02b20695c941913b3e5d7c25207c16 Mon Sep 17 00:00:00 2001 From: Szabo Bogdan Date: Sat, 24 Mar 2018 15:40:40 +0200 Subject: [PATCH] handle exceptions from lazy evaluations --- source/fluentasserts/core/array.d | 24 +++++++++++++++ source/fluentasserts/core/base.d | 9 +++++- source/fluentasserts/core/basetype.d | 38 +++++++++++++++++++++++- source/fluentasserts/core/callable.d | 5 +++- source/fluentasserts/core/objects.d | 28 ++++++++++++++++-- source/fluentasserts/core/string.d | 44 +++++++++++++++++++++++++++- 6 files changed, 142 insertions(+), 6 deletions(-) diff --git a/source/fluentasserts/core/array.d b/source/fluentasserts/core/array.d index 4602aa4..73d1443 100644 --- a/source/fluentasserts/core/array.d +++ b/source/fluentasserts/core/array.d @@ -391,6 +391,30 @@ struct ShouldList(T) if(isInputRange!(T)) { } } + +/// When there is a lazy array that throws an it should throw that exception +unittest { + int[] someLazyArray() { + throw new Exception("This is it."); + } + + ({ + someLazyArray.should.equal([]); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyArray.should.approximately([], 3); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyArray.should.contain([]); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyArray.should.contain(3); + }).should.throwAnyException.withMessage("This is it."); +} + @("range contain") unittest { ({ diff --git a/source/fluentasserts/core/base.d b/source/fluentasserts/core/base.d index bd81f42..ebe7290 100644 --- a/source/fluentasserts/core/base.d +++ b/source/fluentasserts/core/base.d @@ -129,6 +129,14 @@ mixin template ShouldCommons() import std.string; import fluentasserts.core.results; + private ValueEvaluation valueEvaluation; + + private void validateException() { + if(valueEvaluation.throwable !is null) { + throw valueEvaluation.throwable; + } + } + auto be() { addMessage(" be"); return this; @@ -455,7 +463,6 @@ auto evaluate(T)(lazy T testData) @trusted { auto begin = Clock.currTime; alias Result = Tuple!(T, "value", ValueEvaluation, "evaluation"); - try { auto value = testData; diff --git a/source/fluentasserts/core/basetype.d b/source/fluentasserts/core/basetype.d index a11b824..450f9c2 100644 --- a/source/fluentasserts/core/basetype.d +++ b/source/fluentasserts/core/basetype.d @@ -11,7 +11,6 @@ import std.algorithm; struct ShouldBaseType(T) { private const T testData; - private ValueEvaluation valueEvaluation; this(U)(U value) { valueEvaluation = value.evaluation; @@ -26,6 +25,8 @@ struct ShouldBaseType(T) { alias within = this.between; auto equal(const T someValue, const string file = __FILE__, const size_t line = __LINE__) { + validateException; + addMessage(" equal `"); addValue(someValue.to!string); addMessage("`"); @@ -45,6 +46,8 @@ struct ShouldBaseType(T) { auto greaterThan()(const T someValue, const string file = __FILE__, const size_t line = __LINE__) if(!is(T == bool)) { + validateException; + addMessage(" greater than `"); addValue(someValue.to!string); addMessage("`"); @@ -68,6 +71,8 @@ struct ShouldBaseType(T) { auto lessThan()(const T someValue, const string file = __FILE__, const size_t line = __LINE__) if(!is(T == bool)) { + validateException; + addMessage(" less than `"); addValue(someValue.to!string); addMessage("`"); @@ -91,6 +96,8 @@ struct ShouldBaseType(T) { auto between()(const T limit1, const T limit2, const string file = __FILE__, const size_t line = __LINE__) if(!is(T == bool)) { + validateException; + T min = limit1 < limit2 ? limit1 : limit2; T max = limit1 > limit2 ? limit1 : limit2; @@ -128,6 +135,8 @@ struct ShouldBaseType(T) { auto approximately()(const T someValue, const T delta, const string file = __FILE__, const size_t line = __LINE__) if(!is(T == bool)) { + validateException; + addMessage(" equal `"); addValue(someValue.to!string ~ "±" ~ delta.to!string); addMessage("`"); @@ -137,6 +146,33 @@ struct ShouldBaseType(T) { } } +/// When there is a lazy number that throws an it should throw that exception +unittest { + int someLazyInt() { + throw new Exception("This is it."); + } + + ({ + someLazyInt.should.equal(3); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyInt.should.be.greaterThan(3); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyInt.should.be.lessThan(3); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyInt.should.be.between(3, 4); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyInt.should.be.approximately(3, 4); + }).should.throwAnyException.withMessage("This is it."); +} + @("numbers equal") unittest { ({ diff --git a/source/fluentasserts/core/callable.d b/source/fluentasserts/core/callable.d index 07a9807..0c0ed4b 100644 --- a/source/fluentasserts/core/callable.d +++ b/source/fluentasserts/core/callable.d @@ -13,7 +13,6 @@ import fluentasserts.core.results; struct ShouldCallable(T) { private { T callable; - ValueEvaluation valueEvaluation; } mixin ShouldCommons; @@ -27,12 +26,16 @@ struct ShouldCallable(T) { } auto haveExecutionTime(string file = __FILE__, size_t line = __LINE__) { + validateException; + auto tmpShould = ShouldBaseType!Duration(evaluate(valueEvaluation.duration)).forceMessage(" have execution time"); return tmpShould; } auto beNull(string file = __FILE__, size_t line = __LINE__) { + validateException; + addMessage(" be "); addValue("null"); beginCheck; diff --git a/source/fluentasserts/core/objects.d b/source/fluentasserts/core/objects.d index f9d4a3e..509ab7e 100644 --- a/source/fluentasserts/core/objects.d +++ b/source/fluentasserts/core/objects.d @@ -13,7 +13,6 @@ import std.conv; struct ShouldObject(T) { private { T testData; - ValueEvaluation valueEvaluation; } mixin ShouldCommons; @@ -25,6 +24,8 @@ struct ShouldObject(T) { } auto beNull(const string file = __FILE__, const size_t line = __LINE__) @trusted { + validateException; + addMessage(" be "); addValue("null"); beginCheck; @@ -37,6 +38,8 @@ struct ShouldObject(T) { } auto instanceOf(U)(const string file = __FILE__, const size_t line = __LINE__) @trusted { + validateException; + addValue(" instance of `" ~ U.stringof ~ "`"); beginCheck; @@ -49,6 +52,8 @@ struct ShouldObject(T) { } auto equal(U)(U instance, const string file = __FILE__, const size_t line = __LINE__) @trusted { + validateException; + addMessage(" equal "); addValue("`" ~ U.stringof ~ "`"); beginCheck; @@ -58,6 +63,26 @@ struct ShouldObject(T) { } } + +/// When there is a lazy object that throws an it should throw that exception +unittest { + Object someLazyObject() { + throw new Exception("This is it."); + } + + ({ + someLazyObject.should.not.beNull; + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyObject.should.be.instanceOf!Object; + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyObject.should.equal(new Object); + }).should.throwAnyException.withMessage("This is it."); +} + /// object beNull unittest { Object o = null; @@ -118,7 +143,6 @@ unittest { msg.split("\n")[3].strip.should.equal("Actual:a `OtherClass` instance"); } - /// object instanceOf interface unittest { interface MyInterface { } diff --git a/source/fluentasserts/core/string.d b/source/fluentasserts/core/string.d index bdf9a8e..97aa81a 100644 --- a/source/fluentasserts/core/string.d +++ b/source/fluentasserts/core/string.d @@ -13,7 +13,6 @@ import std.array; struct ShouldString { private { const string testData; - ValueEvaluation valueEvaluation; } mixin ShouldCommons; @@ -29,6 +28,8 @@ struct ShouldString { } auto equal(const string someString, const string file = __FILE__, const size_t line = __LINE__) @trusted { + validateException; + addMessage(" equal `"); addValue(someString.to!string); addMessage("`"); @@ -52,6 +53,8 @@ struct ShouldString { } auto contain(const string[] someStrings, const string file = __FILE__, const size_t line = __LINE__) { + validateException; + addMessage(" contain `"); addValue(someStrings.to!string); addMessage("`"); @@ -81,6 +84,8 @@ struct ShouldString { } auto contain(const string someString, const string file = __FILE__, const size_t line = __LINE__) { + validateException; + addMessage(" contain `"); addValue(someString); addMessage("`"); @@ -103,6 +108,8 @@ struct ShouldString { } auto contain(const char someChar, const string file = __FILE__, const size_t line = __LINE__) { + validateException; + addMessage(" contain `"); addValue(someChar.to!string); addMessage("`"); @@ -125,6 +132,8 @@ struct ShouldString { } auto startWith(T)(const T someString, const string file = __FILE__, const size_t line = __LINE__) { + validateException; + addMessage(" start with `"); addValue(someString.to!string); addMessage("`"); @@ -147,6 +156,8 @@ struct ShouldString { } auto endWith(T)(const T someString, const string file = __FILE__, const size_t line = __LINE__) { + validateException; + addMessage(" end with `"); addValue(someString.to!string); addMessage("`"); @@ -174,6 +185,37 @@ struct ShouldString { } } +/// When there is a lazy string that throws an it should throw that exception +unittest { + string someLazyString() { + throw new Exception("This is it."); + } + + ({ + someLazyString.should.equal(""); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyString.should.contain(""); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyString.should.contain([""]); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyString.should.contain(' '); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyString.should.startWith(" "); + }).should.throwAnyException.withMessage("This is it."); + + ({ + someLazyString.should.endWith(" "); + }).should.throwAnyException.withMessage("This is it."); +} + @("string startWith") unittest { ({