fluentasserts.core.array 389/389(100%) line coverage

      
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
183
190
2029
210
22175
230
240
250
260
270
280
290
300
310
320
3390
3490
3590
3690
370
380
390
4086
410
4286
430
44930
450
46515
470
4814
490
500
51224
5268
530
54156
550
560
570
5886
590
600
610
6286
630
6486
650
66891
670
6849
690
70188
710
720
73211
7455
750
76156
770
780
790
8086
810
820
830
8486
850
8686
870
88908
89226
9014
910
920
930
9447
950
96191
970
980
99212
100159
101159
1020
1030
1040
10586
1060
1070
1080
1090
1100
1111
1120
1131
1140
1151
1161
1171
1181
1190
1200
1210
1220
1231
1240
1251
1260
1271
1281
1290
1300
1310
1320
1331
1340
1351
1360
1371
1381
1391
1401
1410
1420
1430
1440
1451
1460
1471
1480
1491
1501
1510
1520
1530
1540
1551
1560
1571
1580
1591
1601
1611
1620
1630
1640
1650
1661
1670
1681
1690
1701
1711
1721
1730
1740
1750
1760
1770
1780
1790
1800
1810
1820
18333
1840
18533
18633
18733
18833
18933
1900
19133
1920
1930
1940
1950
1960
19741
1980
19941
20041
20141
20241
20341
2040
20541
2060
20741
20841
20941
2100
21141
21241
2130
2140
21532
2160
21732
21824
2190
22030
2210
2220
2239
2240
2250
2260
22732
2280
22940
23058
2310
2328
2330
2340
23518
2360
2370
23841
2390
240420
2410
242136
2430
24424
2450
2460
2470
24841
24927
2500
25127
2520
2530
25414
2550
25614
2570
2580
2590
2600
2610
26222
2630
26422
26522
26622
2670
26822
2690
27022
27122
27222
27322
27422
2750
27622
27722
2780
27922
28036
2810
28214
2831
2840
2850
28614
2873
2880
2890
2900
29112
2928
2930
2948
2956
2960
2970
2980
29922
3000
3010
3020
3030
3040
3050
3060
30721
3080
30921
31021
31121
3120
31321
3140
31521
31621
31721
3180
31921
3200
321237
32262
3230
32462
32530
3260
3270
3280
32951
33095
3310
33221
3330
33421
33526
3360
33713
3380
3390
3400
3410
3420
3430
3440
3450
3460
3470
34816
3490
3508
3510
3520
3530
3540
3550
3560
3570
3580
3590
3600
3610
3620
3630
3640
3658
3668
3678
3680
3698
3700
3718
3728
3730
3748
3750
3760
3770
3780
3798
3807
3810
3820
3830
3840
3851
3860
3870
3880
3890
3900
3910
3920
3930
3940
3952
3962
3972
3980
3990
4002
4012
4020
4030
4043
4052
4060
4070
4082
4092
4102
4110
4123
4132
4140
4150
4162
4172
4182
4190
4203
4212
4220
4230
4242
4252
4262
4270
4280
4290
4300
4311
4322
4332
4342
4350
4362
4372
4380
4390
4400
4410
4420
4431
4442
4452
4462
4470
4482
4492
4500
4510
4520
4530
4540
4552
4562
4572
4580
4592
4602
4610
4622
4632
4640
4650
4663
4672
4680
4690
4702
4712
4722
4730
4743
4752
4760
4770
4782
4792
4800
4813
4822
4830
4840
4852
4862
4872
4880
4893
4902
4910
4920
4932
4942
4952
4962
4970
4983
4992
5000
5010
5022
5032
5042
5050
5060
5070
5080
5091
5102
5110
5120
5130
5140
5150
5161
5172
5182
5192
5200
5212
5222
5230
5240
5250
5260
5270
5281
5292
5302
5312
5320
5332
5342
5350
5360
5370
5380
5390
5402
5412
5422
5430
5442
5450
5460
5473
5482
5490
5500
5512
5522
5532
5542
5550
5563
5572
5580
5590
5602
5612
5622
5632
5640
5653
5662
5670
5680
5692
5702
5712
5722
5730
5743
5752
5760
5770
5782
5792
5802
5812
5820
5833
5842
5850
5860
5872
5882
5892
5902
5910
5920
5930
5940
5952
5962
5970
5980
5992
6002
6012
6022
6030
6040
6053
6062
6070
6080
6092
6102
6112
6120
6133
6142
6150
6160
6172
6182
6192
6202
6212
6220
6233
6242
6250
6260
6272
6282
6292
6300
6313
6322
6330
6340
6352
6362
6372
6380
6390
6400
6410
6421
6430
6440
6450
6460
6470
6482
6492
6500
6510
6523
6532
6540
6550
6560
6570
6580
6591
6601
6610
6622
6632
6640
6652
6662
6670
6680
6690
6700
6710
6720
6736
6740
6750
6760
6770
6780
6790
6800
6812
6821
6832
6840
6850
6863
6872
6880
6890
6900
6910
6920
6932
6942
6950
6960
6972
6982
6992
7002
7010
7020
7033
7042
7050
7060
7072
7082
7092
7100
7113
7122
7130
7140
7152
7162
7172
7180
7193
7202
7210
7220
7232
7242
7252
7260
7273
7282
7290
7300
7312
7322
7332
7340
7350
7360
7370
7381
7390
7400
74152
7420
7430
74451
7450
7460
74771
7480
7490
7500
7512
7522
7532
7540
7553
7562
7570
7580
7592
7602
7612
7620
7633
7642
7650
7660
7672
7682
7692
7700
7713
7722
7730
7740
7752
7762
7772
7780
7790
7800
7810
7821
7830
7840
78512
7860
7870
7880
78912
7900
7910
7920
79316
7940
7950
7960
7972
7982
7990
8000
8010
8020
8031
8040
8050
80612
8070
8080
8090
81012
8110
8120
8130
81416
8150
8160
8170
8182
8192
8200
8210
8220
8230
8242
8250
8262
8272
8282
8292
8302
8310
8320
8333
8342
8350
8360
8372
8382
8390
8400
8410
8420
8431
8441
8450
8460
8470
8480
8491
8500
8512
8520
module fluentasserts.core.array; import fluentasserts.core.results; public import fluentasserts.core.base; import std.algorithm; import std.conv; import std.traits; import std.range; import std.array; import std.string; import std.math; U[] toValueList(U, V)(V expectedValueList) { static if(is(V == void[])) { return []; } else static if(is(U == immutable) || is(U == const)) { return expectedValueList.array.idup; } else { return expectedValueList.array.dup; } } struct ListComparison(T) { private { T[] referenceList; T[] list; double maxRelDiff; } this(U, V)(U reference, V list, double maxRelDiff = 0) { this.referenceList = toValueList!T(reference); this.list = list; this.maxRelDiff = maxRelDiff; } T[] missing() { T[] result; auto tmpList = list.dup; foreach(element; referenceList) { static if(std.traits.isNumeric!(T)) { auto index = tmpList.countUntil!(a => approxEqual(element, a, maxRelDiff)); } else { auto index = tmpList.countUntil(element); } if(index == -1) { result ~= element; } else { tmpList = remove(tmpList, index); } } return result; } T[] extra() { T[] result; auto tmpReferenceList = referenceList.dup; foreach(element; list) { static if(isFloatingPoint!(T)) { auto index = tmpReferenceList.countUntil!(a => approxEqual(element, a, maxRelDiff)); } else { auto index = tmpReferenceList.countUntil(element); } if(index == -1) { result ~= element; } else { tmpReferenceList = remove(tmpReferenceList, index); } } return result; } T[] common() { T[] result; auto tmpList = list.dup; foreach(element; referenceList) { if(tmpList.length == 0) { break; } static if(isFloatingPoint!(T)) { auto index = tmpList.countUntil!(a => approxEqual(element, a, maxRelDiff)); } else { auto index = tmpList.countUntil(element); } if(index >= 0) { result ~= element; tmpList = std.algorithm.remove(tmpList, index); } } return result; } } /// ListComparison should be able to get the missing elements unittest { auto comparison = ListComparison!int([1, 2, 3], [4]); auto missing = comparison.missing; assert(missing.length == 3); assert(missing[0] == 1); assert(missing[1] == 2); assert(missing[2] == 3); } /// ListComparison should be able to get the missing elements with duplicates unittest { auto comparison = ListComparison!int([2, 2], [2]); auto missing = comparison.missing; assert(missing.length == 1); assert(missing[0] == 2); } /// ListComparison should be able to get the extra elements unittest { auto comparison = ListComparison!int([4], [1, 2, 3]); auto extra = comparison.extra; assert(extra.length == 3); assert(extra[0] == 1); assert(extra[1] == 2); assert(extra[2] == 3); } /// ListComparison should be able to get the extra elements with duplicates unittest { auto comparison = ListComparison!int([2], [2, 2]); auto extra = comparison.extra; assert(extra.length == 1); assert(extra[0] == 2); } /// ListComparison should be able to get the common elements unittest { auto comparison = ListComparison!int([1, 2, 3, 4], [2, 3]); auto common = comparison.common; assert(common.length == 2); assert(common[0] == 2); assert(common[1] == 3); } /// ListComparison should be able to get the common elements with duplicates unittest { auto comparison = ListComparison!int([2, 2, 2, 2], [2, 2]); auto common = comparison.common; assert(common.length == 2); assert(common[0] == 2); assert(common[1] == 2); } struct ShouldList(T) if(isInputRange!(T)) { private T testData; alias U = ElementType!T; mixin ShouldCommons; mixin DisabledShouldThrowableCommons; auto equal(V)(V expectedValueList, const string file = __FILE__, const size_t line = __LINE__) { U[] valueList = toValueList!U(expectedValueList); addMessage(" equal"); addMessage(" `"); addValue(valueList.to!string); addMessage("`"); beginCheck; return approximately(expectedValueList, 0, file, line); } auto approximately(V)(V expectedValueList, double maxRelDiff = 1e-05, const string file = __FILE__, const size_t line = __LINE__) { import fluentasserts.core.basetype; U[] valueList = toValueList!U(expectedValueList); addMessage(" approximately"); addMessage(" `"); addValue(valueList.to!string); addMessage("`"); beginCheck; auto comparison = ListComparison!U(valueList, testData.array, maxRelDiff); auto missing = comparison.missing; auto extra = comparison.extra; auto common = comparison.common; auto arrayTestData = testData.array; auto strArrayTestData = arrayTestData.to!string; static if(std.traits.isNumeric!(U)) { string strValueList; if(maxRelDiff == 0) { strValueList = valueList.to!string; } else { strValueList = "[" ~ valueList.map!(a => a.to!string ~ "±" ~ maxRelDiff.to!string).join(", ") ~ "]"; } } else { auto strValueList = valueList.to!string; } static if(std.traits.isNumeric!(U)) { string strMissing; if(maxRelDiff == 0 || missing.length == 0) { strMissing = missing.length == 0 ? "" : missing.to!string; } else { strMissing = "[" ~ missing.map!(a => a.to!string ~ "±" ~ maxRelDiff.to!string).join(", ") ~ "]"; } } else { string strMissing = missing.length == 0 ? "" : missing.to!string; } bool allEqual = valueList.length == arrayTestData.length; foreach(i; 0..valueList.length) { static if(std.traits.isNumeric!(U)) { allEqual = allEqual && approxEqual(valueList[i], arrayTestData[i], maxRelDiff); } else { allEqual = allEqual && (valueList[i] == arrayTestData[i]); } } if(expectedValue) { return result(allEqual, [], [ cast(IResult) new ExpectedActualResult(strValueList, strArrayTestData), cast(IResult) new ExtraMissingResult(extra.length == 0 ? "" : extra.to!string, strMissing) ], file, line); } else { return result(allEqual, [], [ cast(IResult) new ExpectedActualResult("not " ~ strValueList, strArrayTestData), cast(IResult) new ExtraMissingResult(extra.length == 0 ? "" : extra.to!string, strMissing) ], file, line); } } auto containOnly(V)(V expectedValueList, const string file = __FILE__, const size_t line = __LINE__) { U[] valueList = toValueList!U(expectedValueList); addMessage(" contain only "); addValue(valueList.to!string); beginCheck; auto comparison = ListComparison!U(testData.array, valueList); auto missing = comparison.missing; auto extra = comparison.extra; auto common = comparison.common; string missingString; string extraString; bool isSuccess; string expected; if(expectedValue) { isSuccess = missing.length == 0 && extra.length == 0 && common.length == valueList.length; if(extra.length > 0) { missingString = extra.to!string; } if(missing.length > 0) { extraString = missing.to!string; } } else { isSuccess = (missing.length != 0 || extra.length != 0) || common.length != valueList.length; isSuccess = !isSuccess; if(common.length > 0) { extraString = common.to!string; } } return result(isSuccess, [], [ cast(IResult) new ExpectedActualResult("", testData.to!string), cast(IResult) new ExtraMissingResult(extraString, missingString) ], file, line); } auto contain(V)(V expectedValueList, const string file = __FILE__, const size_t line = __LINE__) { U[] valueList = toValueList!U(expectedValueList); addMessage(" contain "); addValue(valueList.to!string); beginCheck; auto comparison = ListComparison!U(testData.array, valueList); auto missing = comparison.missing; auto extra = comparison.extra; auto common = comparison.common; ulong[size_t] indexes; foreach(value; testData) { auto index = valueList.countUntil(value); if(index != -1) { indexes[index]++; } } auto found = indexes.keys.map!(a => valueList[a]).array; auto notFound = iota(0, valueList.length).filter!(a => !indexes.keys.canFind(a)).map!(a => valueList[a]).array; auto arePresent = indexes.keys.length == valueList.length; if(expectedValue) { string isString = notFound.length == 1 ? "is" : "are"; return result(arePresent, [ Message(true, notFound.to!string), Message(false, " " ~ isString ~ " missing from "), Message(true, testData.to!string), Message(false, ".") ], [ cast(IResult) new ExpectedActualResult("all of " ~ valueList.to!string, testData.to!string), cast(IResult) new ExtraMissingResult("", notFound.to!string) ], file, line); } else { string isString = found.length == 1 ? "is" : "are"; return result(common.length != 0, [ Message(true, common.to!string), Message(false, " " ~ isString ~ " present in "), Message(true, testData.to!string), Message(false, ".") ], [ cast(IResult) new ExpectedActualResult("none of " ~ valueList.to!string, testData.to!string), cast(IResult) new ExtraMissingResult(common.to!string, "") ], file, line); } } auto contain(U value, const string file = __FILE__, const size_t line = __LINE__) { addMessage(" contain `"); addValue(value.to!string); addMessage("`"); beginCheck; auto isPresent = testData.canFind(value); auto msg = [ Message(true, value.to!string), Message(false, isPresent ? " is present in " : " is missing from "), Message(true, testData.to!string), Message(false, ".") ]; if(expectedValue) { return result(isPresent, msg, [ cast(IResult) new ExpectedActualResult("to contain `" ~ value.to!string ~ "`", testData.to!string), cast(IResult) new ExtraMissingResult("", value.to!string) ], file, line); } else { return result(isPresent, msg, [ cast(IResult) new ExpectedActualResult("to not contain `" ~ value.to!string ~ "`", testData.to!string), cast(IResult) new ExtraMissingResult(value.to!string, "") ], file, line); } } } @("range contain") unittest { ({ [1, 2, 3].map!"a".should.contain([2, 1]); [1, 2, 3].map!"a".should.not.contain([4, 5, 6, 7]); }).should.not.throwException!TestException; ({ [1, 2, 3].map!"a".should.contain(1); }).should.not.throwException!TestException; auto msg = ({ [1, 2, 3].map!"a".should.contain([4, 5]); }).should.throwException!TestException.msg; msg.split('\n')[0].should.equal("[1, 2, 3].map!\"a\" should contain [4, 5]. [4, 5] are missing from [1, 2, 3]."); msg.split('\n')[2].strip.should.equal("Expected:all of [4, 5]"); msg.split('\n')[3].strip.should.equal("Actual:[1, 2, 3]"); msg = ({ [1, 2, 3].map!"a".should.not.contain([1, 2]); }).should.throwException!TestException.msg; msg.split('\n')[0].should.equal("[1, 2, 3].map!\"a\" should not contain [1, 2]. [1, 2] are present in [1, 2, 3]."); msg.split('\n')[2].strip.should.equal("Expected:none of [1, 2]"); msg.split('\n')[3].strip.should.equal("Actual:[1, 2, 3]"); msg = ({ [1, 2, 3].map!"a".should.contain(4); }).should.throwException!TestException.msg; msg.split('\n')[0].should.contain("4 is missing from [1, 2, 3]"); msg.split('\n')[2].strip.should.equal("Expected:to contain `4`"); msg.split('\n')[3].strip.should.equal("Actual:[1, 2, 3]"); } /// const range contain unittest { const(int)[] data = [1, 2, 3]; data.map!"a".should.contain([2, 1]); data.map!"a".should.contain(data); [1, 2, 3].should.contain(data); ({ data.map!"a * 4".should.not.contain(data); }).should.not.throwAnyException; } /// immutable range contain unittest { immutable(int)[] data = [1, 2, 3]; data.map!"a".should.contain([2, 1]); data.map!"a".should.contain(data); [1, 2, 3].should.contain(data); ({ data.map!"a * 4".should.not.contain(data); }).should.not.throwAnyException; } /// contain only unittest { ({ [1, 2, 3].should.containOnly([3, 2, 1]); [1, 2, 3].should.not.containOnly([2, 1]); [1, 2, 2].should.not.containOnly([2, 1]); [1, 2, 2].should.containOnly([2, 1, 2]); [2, 2].should.containOnly([2, 2]); [2, 2, 2].should.not.containOnly([2, 2]); }).should.not.throwException!TestException; auto msg = ({ [1, 2, 3].should.containOnly([2, 1]); }).should.throwException!TestException.msg; msg.split('\n')[0].should.equal("[1, 2, 3] should contain only [2, 1]."); msg.split('\n')[2].strip.should.equal("Actual:[1, 2, 3]"); msg.split('\n')[4].strip.should.equal("Extra:[3]"); msg = ({ [1, 2].should.not.containOnly([2, 1]); }).should.throwException!TestException.msg; msg.split('\n')[0].strip.should.equal("[1, 2] should not contain only [2, 1]."); msg.split('\n')[2].strip.should.equal("Actual:[1, 2]"); msg = ({ [2, 2].should.containOnly([2]); }).should.throwException!TestException.msg; msg.split('\n')[0].should.equal("[2, 2] should contain only [2]."); msg.split('\n')[2].strip.should.equal("Actual:[2, 2]"); msg.split('\n')[4].strip.should.equal("Extra:[2]"); msg = ({ [3, 3].should.containOnly([2]); }).should.throwException!TestException.msg; msg.split('\n')[0].should.equal("[3, 3] should contain only [2]."); msg.split('\n')[2].strip.should.equal("Actual:[3, 3]"); msg.split('\n')[4].strip.should.equal("Extra:[3, 3]"); msg.split('\n')[5].strip.should.equal("Missing:[2]"); msg = ({ [2, 2].should.not.containOnly([2, 2]); }).should.throwException!TestException.msg; msg.split('\n')[0].should.equal("[2, 2] should not contain only [2, 2]."); msg.split('\n')[2].strip.should.equal("Actual:[2, 2]"); msg.split('\n')[4].strip.should.equal("Extra:[2, 2]"); } /// contain only with void array unittest { int[] list; list.should.containOnly([]); } /// const range containOnly unittest { const(int)[] data = [1, 2, 3]; data.map!"a".should.containOnly([3, 2, 1]); data.map!"a".should.containOnly(data); [1, 2, 3].should.containOnly(data); ({ data.map!"a * 4".should.not.containOnly(data); }).should.not.throwAnyException; } /// immutable range containOnly unittest { immutable(int)[] data = [1, 2, 3]; data.map!"a".should.containOnly([2, 1, 3]); data.map!"a".should.containOnly(data); [1, 2, 3].should.containOnly(data); ({ data.map!"a * 4".should.not.containOnly(data); }).should.not.throwAnyException; } /// array contain unittest { ({ [1, 2, 3].should.contain([2, 1]); [1, 2, 3].should.not.contain([4, 5, 6, 7]); [1, 2, 3].should.contain(1); }).should.not.throwException!TestException; auto msg = ({ [1, 2, 3].should.contain([4, 5]); }).should.throwException!TestException.msg.split('\n'); msg[0].should.equal("[1, 2, 3] should contain [4, 5]. [4, 5] are missing from [1, 2, 3]."); msg[2].strip.should.equal("Expected:all of [4, 5]"); msg[3].strip.should.equal("Actual:[1, 2, 3]"); msg[5].strip.should.equal("Missing:[4, 5]"); msg = ({ [1, 2, 3].should.not.contain([2, 3]); }).should.throwException!TestException.msg.split('\n'); msg[0].should.equal("[1, 2, 3] should not contain [2, 3]. [2, 3] are present in [1, 2, 3]."); msg[2].strip.should.equal("Expected:none of [2, 3]"); msg[3].strip.should.equal("Actual:[1, 2, 3]"); msg[5].strip.should.equal("Extra:[2, 3]"); msg = ({ [1, 2, 3].should.not.contain([4, 3]); }).should.throwException!TestException.msg.split('\n'); msg[0].should.equal("[1, 2, 3] should not contain [4, 3]. [3] is present in [1, 2, 3]."); msg[2].strip.should.equal("Expected:none of [4, 3]"); msg[3].strip.should.equal("Actual:[1, 2, 3]"); msg[5].strip.should.equal("Extra:[3]"); msg = ({ [1, 2, 3].should.contain(4); }).should.throwException!TestException.msg.split('\n'); msg[0].should.equal("[1, 2, 3] should contain `4`. 4 is missing from [1, 2, 3]."); msg[2].strip.should.equal("Expected:to contain `4`"); msg[3].strip.should.equal("Actual:[1, 2, 3]"); msg[5].strip.should.equal("Missing:4"); msg = ({ [1, 2, 3].should.not.contain(2); }).should.throwException!TestException.msg.split('\n'); msg[0].should.equal("[1, 2, 3] should not contain `2`. 2 is present in [1, 2, 3]."); msg[2].strip.should.equal("Expected:to not contain `2`"); msg[3].strip.should.equal("Actual:[1, 2, 3]"); msg[5].strip.should.equal("Extra:2"); } /// array equals unittest { ({ [1, 2, 3].should.equal([1, 2, 3]); }).should.not.throwAnyException; ({ [1, 2, 3].should.not.equal([2, 1, 3]); [1, 2, 3].should.not.equal([2, 3]); [2, 3].should.not.equal([1, 2, 3]); }).should.not.throwAnyException; auto msg = ({ [1, 2, 3].should.equal([4, 5]); }).should.throwException!TestException.msg.split("\n"); msg[0].strip.should.equal("[1, 2, 3] should equal `[4, 5]`."); msg[2].strip.should.equal("Expected:[4, 5]"); msg[3].strip.should.equal("Actual:[1, 2, 3]"); msg = ({ [1, 2].should.equal([4, 5]); }).should.throwException!TestException.msg.split("\n"); msg[0].strip.should.equal("[1, 2] should equal `[4, 5]`."); msg[2].strip.should.equal("Expected:[4, 5]"); msg[3].strip.should.equal("Actual:[1, 2]"); msg[5].strip.should.equal("Extra:[1, 2]"); msg[6].strip.should.equal("Missing:[4, 5]"); msg = ({ [1, 2, 3].should.equal([2, 3, 1]); }).should.throwException!TestException.msg.split("\n"); msg[0].strip.should.equal("[1, 2, 3] should equal `[2, 3, 1]`."); msg[2].strip.should.equal("Expected:[2, 3, 1]"); msg[3].strip.should.equal("Actual:[1, 2, 3]"); msg = ({ [1, 2, 3].should.not.equal([1, 2, 3]); }).should.throwException!TestException.msg.split("\n"); msg[0].strip.should.startWith("[1, 2, 3] should not equal `[1, 2, 3]`"); msg[2].strip.should.equal("Expected:not [1, 2, 3]"); msg[3].strip.should.equal("Actual:[1, 2, 3]"); } ///array equals with structs unittest { struct TestStruct { int value; void f() {} } ({ [TestStruct(1)].should.equal([TestStruct(1)]); }).should.not.throwAnyException; ({ [TestStruct(2)].should.equal([TestStruct(1)]); }).should.throwException!TestException.withMessage.startWith("[TestStruct(2)] should equal `[TestStruct(1, null)]`"); } /// const array equal unittest { const(string)[] constValue = ["test", "string"]; immutable(string)[] immutableValue = ["test", "string"]; constValue.should.equal(["test", "string"]); immutableValue.should.equal(["test", "string"]); ["test", "string"].should.equal(constValue); ["test", "string"].should.equal(immutableValue); } version(unittest) { class TestEqualsClass { int value; this(int value) { this.value = value; } void f() {} } } ///array equals with classes unittest { ({ auto instance = new TestEqualsClass(1); [instance].should.equal([instance]); }).should.not.throwAnyException; ({ [new TestEqualsClass(2)].should.equal([new TestEqualsClass(1)]); }).should.throwException!TestException.withMessage.startWith("[new TestEqualsClass(2)] should equal `[fluentasserts.core.array.TestEqualsClass]`."); } /// range equals unittest { ({ [1, 2, 3].map!"a".should.equal([1, 2, 3]); }).should.not.throwAnyException; ({ [1, 2, 3].map!"a".should.not.equal([2, 1, 3]); [1, 2, 3].map!"a".should.not.equal([2, 3]); [2, 3].map!"a".should.not.equal([1, 2, 3]); }).should.not.throwAnyException; auto msg = ({ [1, 2, 3].map!"a".should.equal([4, 5]); }).should.throwException!TestException.msg; msg.split("\n")[0].strip.should.equal("[1, 2, 3].map!\"a\" should equal `[4, 5]`."); msg.split("\n")[2].strip.should.equal("Expected:[4, 5]"); msg.split("\n")[3].strip.should.equal("Actual:[1, 2, 3]"); msg = ({ [1, 2].map!"a".should.equal([4, 5]); }).should.throwException!TestException.msg; msg.split("\n")[0].strip.should.equal("[1, 2].map!\"a\" should equal `[4, 5]`."); msg.split("\n")[2].strip.should.equal("Expected:[4, 5]"); msg.split("\n")[3].strip.should.equal("Actual:[1, 2]"); msg = ({ [1, 2, 3].map!"a".should.equal([2, 3, 1]); }).should.throwException!TestException.msg; msg.split("\n")[0].strip.should.equal("[1, 2, 3].map!\"a\" should equal `[2, 3, 1]`."); msg.split("\n")[2].strip.should.equal("Expected:[2, 3, 1]"); msg.split("\n")[3].strip.should.equal("Actual:[1, 2, 3]"); msg = ({ [1, 2, 3].map!"a".should.not.equal([1, 2, 3]); }).should.throwException!TestException.msg; msg.split("\n")[0].strip.should.startWith("[1, 2, 3].map!\"a\" should not equal `[1, 2, 3]`"); msg.split("\n")[2].strip.should.equal("Expected:not [1, 2, 3]"); msg.split("\n")[3].strip.should.equal("Actual:[1, 2, 3]"); } /// custom range asserts unittest { struct Range { int n; int front() { return n; } void popFront() { ++n; } bool empty() { return n == 3; } } Range().should.equal([0,1,2]); Range().should.contain([0,1]); Range().should.contain(0); auto msg = ({ Range().should.equal([0,1]); }).should.throwException!TestException.msg; msg.split("\n")[0].strip.should.startWith("Range() should equal `[0, 1]`"); msg.split("\n")[2].strip.should.equal("Expected:[0, 1]"); msg.split("\n")[3].strip.should.equal("Actual:[0, 1, 2]"); msg = ({ Range().should.contain([2, 3]); }).should.throwException!TestException.msg; msg.split("\n")[0].strip.should.startWith("Range() should contain [2, 3]. [3] is missing from [0, 1, 2]."); msg.split("\n")[2].strip.should.equal("Expected:all of [2, 3]"); msg.split("\n")[3].strip.should.equal("Actual:[0, 1, 2]"); msg = ({ Range().should.contain(3); }).should.throwException!TestException.msg; msg.split("\n")[0].strip.should.startWith("Range() should contain `3`. 3 is missing from [0, 1, 2]."); msg.split("\n")[2].strip.should.equal("Expected:to contain `3`"); msg.split("\n")[3].strip.should.equal("Actual:[0, 1, 2]"); } /// custom const range equals unittest { struct ConstRange { int n; const(int) front() { return n; } void popFront() { ++n; } bool empty() { return n == 3; } } [0,1,2].should.equal(ConstRange()); ConstRange().should.equal([0,1,2]); } /// custom immutable range equals unittest { struct ImmutableRange { int n; immutable(int) front() { return n; } void popFront() { ++n; } bool empty() { return n == 3; } } [0,1,2].should.equal(ImmutableRange()); ImmutableRange().should.equal([0,1,2]); } /// approximately equals unittest { [0.350, 0.501, 0.341].should.be.approximately([0.35, 0.50, 0.34], 0.01); ({ [0.350, 0.501, 0.341].should.not.be.approximately([0.35, 0.50, 0.34], 0.00001); [0.350, 0.501, 0.341].should.not.be.approximately([0.501, 0.350, 0.341], 0.001); [0.350, 0.501, 0.341].should.not.be.approximately([0.350, 0.501], 0.001); [0.350, 0.501].should.not.be.approximately([0.350, 0.501, 0.341], 0.001); }).should.not.throwAnyException; auto msg = ({ [0.350, 0.501, 0.341].should.be.approximately([0.35, 0.50, 0.34], 0.0001); }).should.throwException!TestException.msg; msg.should.contain("Expected:[0.35±0.0001, 0.5±0.0001, 0.34±0.0001]"); msg.should.contain("Missing:[0.5±0.0001, 0.34±0.0001]"); } /// approximately equals with Assert unittest { Assert.approximately([0.350, 0.501, 0.341], [0.35, 0.50, 0.34], 0.01); Assert.notApproximately([0.350, 0.501, 0.341], [0.350, 0.501], 0.0001); } /// immutable string unittest { immutable string[] someList; someList.should.equal([]); }