fluentasserts.core.expect 101/105(96%) line coverage

      
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
202937
212937
220
232937
242937
252937
262937
270
280
292937
300
312937
321257
330
341680
350
360
370
380
390
402937
410
422937
432
440
450
460
474756
484756
494756
500
510
520
537693
540
557693
562935
572935
580
592935
602886
612886
6249
630
640
650
660
672935
680
690
700
710
72435
730
740
750
76435
770
780
790
8010
8110
820
830
840
8521
8621
870
880
890
90871
91871
920
930
940
950
96882
970
980
990
1000
101335
102335
1030
1040
1050
1060
107559
108559
1090
110559
1110
1120
1130
1140
11562
1160
1170
1180
1190
120452
121452
1220
123452
1240
1250
1260
1274
1284
1290
1300
1310
1320
1331542
1340
1350
1360
1370
138298
1390
1400
1410
1420
14362
1440
1450
1460
1470
14826
1490
1500
1510
15257
1530
1540
1550
1560
15728
1580
1590
1600
1610
16285
1630
1640
1650
1660
16737
1680
1690
1700
171142
1720
1730
1740
17549
1760
1770
1780
17988
1800
1810
1820
18328
1840
1850
1860
1872
1880
1890
1900
1912
1920
1934
1940
1952
1960
1970
1980
1990
2002997
20162
2020
2030
2042997
2050
2060
2070
2080
20972
2100
21172
2120
2130
2140
2150
2162894
2170
2180
2195788
2200
2214750
222928
2230
2240
2252894
2260
2270
2280
2290
2306118
2310
2320
2330
2342894
2350
2360
2370
2380
2390
240417
241417
2420
2430
244417
245413
2460
2474
2480
2490
250400
251400
2520
2531
2541
2550
2560
257417
2580
2590
2600
2610
2625113
2630
2640
2650
2660
2672938
2680
269101122
27023077
2712937
2722937
2730
2740
27520140
27663
27763
2780
2790
28021078
2811001
2821001
2831001
2840
2850
28619076
2870
2880
2892938
2900
2910
2920
2930
2942
2952
2962
2970
module fluentasserts.core.expect; import fluentasserts.core.lifecycle; import fluentasserts.core.evaluation; import fluentasserts.core.results; import std.traits; import std.string; import std.uni; import std.conv; /// @safe struct Expect { private { Evaluation evaluation; int refCount; } this(ValueEvaluation value, const string fileName, const size_t line, string prependText = null) @trusted { this.evaluation = new Evaluation(); evaluation.id = Lifecycle.instance.beginEvaluation(value); evaluation.currentValue = value; evaluation.message = new MessageResult(); evaluation.source = new SourceResult(fileName, line); try { auto sourceValue = evaluation.source.getValue; if(sourceValue == "") { evaluation.message.startWith(evaluation.currentValue.niceValue); } else { evaluation.message.startWith(sourceValue); } } catch(Exception) { evaluation.message.startWith(evaluation.currentValue.strValue); } evaluation.message.addText(" should"); if(prependText) { evaluation.message.addText(prependText); } } this(ref return scope Expect another) { this.evaluation = another.evaluation; this.refCount = another.refCount + 1; } ~this() { refCount--; if(refCount < 0) { evaluation.message.addText(" "); evaluation.message.addText(evaluation.operationName.toNiceOperation); if(evaluation.expectedValue.niceValue) { evaluation.message.addText(" "); evaluation.message.addValue(evaluation.expectedValue.niceValue); } else if(evaluation.expectedValue.strValue) { evaluation.message.addText(" "); evaluation.message.addValue(evaluation.expectedValue.strValue); } Lifecycle.instance.endEvaluation(evaluation); } } string msg(const size_t line = __LINE__, const string file = __FILE__) @trusted { if(this.thrown is null) { throw new Exception("There were no thrown exceptions", file, line); } return this.thrown.message.to!string; } Expect withMessage(const size_t line = __LINE__, const string file = __FILE__) { addOperationName("withMessage"); return this; } Expect withMessage(string message, const size_t line = __LINE__, const string file = __FILE__) { addOperationName("withMessage"); return this.equal(message); } Throwable thrown() { Lifecycle.instance.endEvaluation(evaluation); return evaluation.throwable; } /// Expect to() { return this; } /// Expect be () { evaluation.message.addText(" be"); return this; } /// Expect not() { evaluation.isNegated = !evaluation.isNegated; evaluation.message.addText(" not"); return this; } /// auto throwAnyException() { return opDispatch!"throwAnyException"; } /// Expect throwException(Type)() { this.evaluation.expectedValue.meta["exceptionType"] = fullyQualifiedName!Type; this.evaluation.expectedValue.meta["throwableType"] = fullyQualifiedName!Type; return opDispatch!"throwException"(fullyQualifiedName!Type); } auto because(string reason) { evaluation.message.prependText("Because " ~ reason ~ ", "); return this; } /// auto equal(T)(T value) { return opDispatch!"equal"(value); } /// auto contain(T)(T value) { return opDispatch!"contain"(value); } /// auto greaterThan(T)(T value) { return opDispatch!"greaterThan"(value); } /// auto above(T)(T value) { return opDispatch!"above"(value); } /// auto lessThan(T)(T value) { return opDispatch!"lessThan"(value); } /// auto below(T)(T value) { return opDispatch!"below"(value); } /// auto startWith(T)(T value) { return opDispatch!"startWith"(value); } /// auto endWith(T)(T value) { return opDispatch!"endWith"(value); } auto containOnly(T)(T value) { return opDispatch!"containOnly"(value); } auto approximately(T, U)(T value, U range) { return opDispatch!"approximately"(value, range); } auto between(T, U)(T value, U range) { return opDispatch!"between"(value, range); } auto within(T, U)(T value, U range) { return opDispatch!"within"(value, range); } void inhibit() { this.refCount = int.max; } auto haveExecutionTime() { this.inhibit; auto result = expect(evaluation.currentValue.duration, evaluation.source.file, evaluation.source.line, " have execution time"); return result; } void addOperationName(string value) { if(this.evaluation.operationName) { this.evaluation.operationName ~= "."; } this.evaluation.operationName ~= value; } /// Expect opDispatch(string methodName)() { addOperationName(methodName); return this; } /// Expect opDispatch(string methodName, Params...)(Params params) if(Params.length > 0) { addOperationName(methodName); static if(Params.length > 0) { auto expectedValue = params[0].evaluate.evaluation; foreach(key, value; evaluation.expectedValue.meta) { expectedValue.meta[key] = value; } evaluation.expectedValue = expectedValue; } static if(Params.length >= 1) { static foreach (i, Param; Params) { () @trusted { evaluation.expectedValue.meta[i.to!string] = params[i].to!string; } (); } } return this; } } /// Expect expect(void delegate() callable, const string file = __FILE__, const size_t line = __LINE__, string prependText = null) @trusted { ValueEvaluation value; value.typeName = "callable"; try { if(callable !is null) { callable(); } else { value.typeName = "null"; } } catch(Exception e) { value.throwable = e; value.meta["Exception"] = "yes"; } catch(Throwable t) { value.throwable = t; value.meta["Throwable"] = "yes"; } return Expect(value, file, line, prependText); } /// Expect expect(T)(lazy T testedValue, const string file = __FILE__, const size_t line = __LINE__, string prependText = null) @trusted { return Expect(testedValue.evaluate.evaluation, file, line, prependText); } /// string toNiceOperation(string value) @safe nothrow { string newValue; foreach(index, ch; value) { if(index == 0) { newValue ~= ch.toLower; continue; } if(ch == '.') { newValue ~= ' '; continue; } if(ch.isUpper && value[index - 1].isLower) { newValue ~= ' '; newValue ~= ch.toLower; continue; } newValue ~= ch; } return newValue; } /// toNiceOperation converts to a nice and readable string unittest { expect("".toNiceOperation).to.equal(""); expect("a.b".toNiceOperation).to.equal("a b"); expect("aB".toNiceOperation).to.equal("a b"); }