fluentasserts.core.serializers 158/158(100%) line coverage

      
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
2810
290
303895
310
320
330
340
350
363
370
3812
390
400
410
420
4343
440
450
4632
475
480
4927
500
510
5211
530
540
5543
562
570
582
592
600
610
6243
631
641
651
660
670
6843
690
700
710
720
730
743221
750
7657
770
783411
790
800
810
820
830
840
851
861
871
880
892
902
912
920
930
940
950
961
971
981
990
1002
1012
1022
1030
1040
1050
1060
1071
1081
1091
1100
1112
1122
1132
1140
1150
1160
1170
1181
1191
1201
1210
1222
1232
1242
1250
1260
1270
1280
1291
1301
1311
1320
1332
1342
1352
1360
1370
1380
1390
1401
1411
1421
1430
1442
1452
1462
1470
1480
1490
1500
1511
1521
1531
1540
1552
1562
1572
1580
1590
1600
1610
1620
1631
1641
1651
1660
1672
1682
1692
1700
1710
1720
1731012
1740
1750
1760
1770
1780
1790
1800
1815316
1820
1830
1840
1850
186861
1871
1880
1890
190860
19118
1920
1930
1941479
195205
1960
1970
198637
199637
2000
201637
202637
203637
204637
2050
20625584
2077891
20822117
2090
21016193
2111255
2121255
2131255
2140
2150
21613260
2175852
21815
21915
2200
2210
2225852
22315
2240
22515
22610
2270
2280
2290
2300
2316636
23213140
233384
2340
2350
23612380
23712
2380
2390
2400
2416636
2420
2430
244637
245629
2460
2470
248637
2490
2500
2510
2520
2531
2540
2552
2560
2570
2580
2590
2601
2610
2622
2630
2640
2650
2660
2670
2681
2690
2702
2710
2720
2730
2740
2751
2760
2772
2780
2790
2800
2810
2821
2830
2842
2850
2860
2870
2880
2891
2900
2912
2920
2930
2940
2950
2961
2970
2982
2990
3000
3010
3020
3031
3040
3052
3060
3070
3080
3090
3101
3110
3122
3130
3140
3150
3160
3171
3180
3192
3200
3210
3220
3230
3241
3250
3262
3270
3280
3290
3300
3311
3320
3332
3340
3350
3360
3370
3381
3390
3402
3410
3420
3430
3440
3451
3462
3470
3480
3490
3500
3511
3522
3530
3540
3550
3560
3570
3581
3592
3600
3610
3620
3630
3641
3652
3660
3670
3680
3690
3701
3712
3720
3730
3740
3750
3762461
377297
3780
3790
3802164
3812164
3820
3832889
384662
3850
3860
3870
3881502
3890
3900
3910
3920
3932
3940
3950
3960
3970
3982
3990
4000
4010
4020
4032
4040
4050
4060
4070
4082
4090
4100
4110
4120
4132925
4140
4150
4160
4170
4181
4190
4202
4210
4220
4230
4240
4252
4260
module fluentasserts.core.serializers; import std.array; import std.string; import std.algorithm; import std.traits; import std.conv; version(unittest) import fluent.asserts; /// Singleton used to serialize to string the tested values class SerializerRegistry { /// static SerializerRegistry instance; private { void*[] serializers; } /// void register(T)(string delegate(T) serializer) { serializers[T.stringof] = &serializer; } /// string serialize(T)(T[] value) if(!isSomeString!(T[])) { static if(is(Unqual!T == void)) { return "[]"; } else { return "[" ~ value.map!(a => serialize(a)).joiner(", ").array.to!string ~ "]"; } } /// string serialize(T: V[K], V, K)(T value) { auto keys = value.byKey.array.sort; return "[" ~ keys.map!(a => serialize(a) ~ ":" ~ serialize(value[a])).joiner(", ").array.to!string ~ "]"; } /// string serialize(T)(T value) if(isAggregateType!T) { string result; static if(is(T == class)) { if(value is null) { result = "null"; } else { result = T.stringof ~ "(" ~ (cast() value).toHash.to!string ~ ")"; } } else { result = value.to!string; } if(result.indexOf("const(") == 0) { result = result[6..$]; auto pos = result.indexOf(")"); result = result[0..pos] ~ result[pos + 1..$]; } if(result.indexOf("immutable(") == 0) { result = result[10..$]; auto pos = result.indexOf(")"); result = result[0..pos] ~ result[pos + 1..$]; } return result; } /// string serialize(T)(T value) if(isSomeString!T || (!isArray!T && !isAssociativeArray!T && !isAggregateType!T)) { static if(isSomeString!T) { return `"` ~ value.to!string ~ `"`; } else static if(isSomeChar!T) { return `'` ~ value.to!string ~ `'`; } else { return value.to!string; } } } /// It should serialize a char unittest { char ch = 'a'; const char cch = 'a'; immutable char ich = 'a'; SerializerRegistry.instance.serialize(ch).should.equal("'a'"); SerializerRegistry.instance.serialize(cch).should.equal("'a'"); SerializerRegistry.instance.serialize(ich).should.equal("'a'"); } /// It should serialize a string unittest { string str = "aaa"; const string cstr = "aaa"; immutable string istr = "aaa"; SerializerRegistry.instance.serialize(str).should.equal(`"aaa"`); SerializerRegistry.instance.serialize(cstr).should.equal(`"aaa"`); SerializerRegistry.instance.serialize(istr).should.equal(`"aaa"`); } /// It should serialize an int unittest { int value = 23; const int cvalue = 23; immutable int ivalue = 23; SerializerRegistry.instance.serialize(value).should.equal(`23`); SerializerRegistry.instance.serialize(cvalue).should.equal(`23`); SerializerRegistry.instance.serialize(ivalue).should.equal(`23`); } /// It should serialize an int list unittest { int[] value = [2,3]; const int[] cvalue = [2,3]; immutable int[] ivalue = [2,3]; SerializerRegistry.instance.serialize(value).should.equal(`[2, 3]`); SerializerRegistry.instance.serialize(cvalue).should.equal(`[2, 3]`); SerializerRegistry.instance.serialize(ivalue).should.equal(`[2, 3]`); } /// It should serialize a void list unittest { void[] value = []; const void[] cvalue = []; immutable void[] ivalue = []; SerializerRegistry.instance.serialize(value).should.equal(`[]`); SerializerRegistry.instance.serialize(cvalue).should.equal(`[]`); SerializerRegistry.instance.serialize(ivalue).should.equal(`[]`); } /// It should serialize a nested int list unittest { int[][] value = [[0,1],[2,3]]; const int[][] cvalue = [[0,1],[2,3]]; immutable int[][] ivalue = [[0,1],[2,3]]; SerializerRegistry.instance.serialize(value).should.equal(`[[0, 1], [2, 3]]`); SerializerRegistry.instance.serialize(cvalue).should.equal(`[[0, 1], [2, 3]]`); SerializerRegistry.instance.serialize(ivalue).should.equal(`[[0, 1], [2, 3]]`); } /// It should serialize an assoc array unittest { int[string] value = ["a": 2,"b": 3, "c": 4]; const int[string] cvalue = ["a": 2,"b": 3, "c": 4]; immutable int[string] ivalue = ["a": 2,"b": 3, "c": 4]; SerializerRegistry.instance.serialize(value).should.equal(`["a":2, "b":3, "c":4]`); SerializerRegistry.instance.serialize(cvalue).should.equal(`["a":2, "b":3, "c":4]`); SerializerRegistry.instance.serialize(ivalue).should.equal(`["a":2, "b":3, "c":4]`); } version(unittest) { struct TestStruct { int a; string b; }; } /// It should serialzie a struct unittest { TestStruct value = TestStruct(1, "2"); const TestStruct cvalue = TestStruct(1, "2"); immutable TestStruct ivalue = TestStruct(1, "2"); SerializerRegistry.instance.serialize(value).should.equal(`TestStruct(1, "2")`); SerializerRegistry.instance.serialize(cvalue).should.equal(`TestStruct(1, "2")`); SerializerRegistry.instance.serialize(ivalue).should.equal(`TestStruct(1, "2")`); } string unqualString(T: U[], U)() if(isArray!T && !isSomeString!T) { return unqualString!U ~ "[]"; } string unqualString(T: V[K], V, K)() if(isAssociativeArray!T) { return unqualString!V ~ "[" ~ unqualString!K ~ "]"; } string unqualString(T)() if(isSomeString!T || (!isArray!T && !isAssociativeArray!T)) { return Unqual!T.stringof; } /// string[] parseList(string value) @safe nothrow { if(value.length == 0) { return []; } if(value.length == 1) { return [ value ]; } if(value[0] != '[' || value[value.length - 1] != ']') { return [ value ]; } string[] result; string currentValue; bool isInsideString; bool isInsideChar; bool isInsideArray; long arrayIndex = 0; foreach(index; 1..value.length - 1) { auto ch = value[index]; auto canSplit = !isInsideString && !isInsideChar && !isInsideArray; if(canSplit && ch == ',' && currentValue.length > 0) { result ~= currentValue.strip.dup; currentValue = ""; continue; } if(!isInsideChar && !isInsideString) { if(ch == '[') { arrayIndex++; isInsideArray = true; } if(ch == ']') { arrayIndex--; if(arrayIndex == 0) { isInsideArray = false; } } } if(!isInsideArray) { if(!isInsideChar && ch == '"') { isInsideString = !isInsideString; } if(!isInsideString && ch == '\'') { isInsideChar = !isInsideChar; } } currentValue ~= ch; } if(currentValue.length > 0) { result ~= currentValue.strip; } return result; } /// it should parse an empty string unittest { auto pieces = "".parseList; pieces.should.equal([]); } /// it should not parse a string that does not contain [] unittest { auto pieces = "test".parseList; pieces.should.equal([ "test" ]); } /// it should not parse a char that does not contain [] unittest { auto pieces = "t".parseList; pieces.should.equal([ "t" ]); } /// it should parse an empty array unittest { auto pieces = "[]".parseList; pieces.should.equal([]); } /// it should parse a list of one number unittest { auto pieces = "[1]".parseList; pieces.should.equal(["1"]); } /// it should parse a list of two numbers unittest { auto pieces = "[1,2]".parseList; pieces.should.equal(["1","2"]); } /// it should remove the whitespaces from the parsed values unittest { auto pieces = "[ 1, 2 ]".parseList; pieces.should.equal(["1","2"]); } /// it should parse two string values that contain a `,` unittest { auto pieces = `[ "a,b", "c,d" ]`.parseList; pieces.should.equal([`"a,b"`,`"c,d"`]); } /// it should parse two string values that contain a `'` unittest { auto pieces = `[ "a'b", "c'd" ]`.parseList; pieces.should.equal([`"a'b"`,`"c'd"`]); } /// it should parse two char values that contain a `,` unittest { auto pieces = `[ ',' , ',' ]`.parseList; pieces.should.equal([`','`,`','`]); } /// it should parse two char values that contain `[` and `]` unittest { auto pieces = `[ '[' , ']' ]`.parseList; pieces.should.equal([`'['`,`']'`]); } /// it should parse two string values that contain `[` and `]` unittest { auto pieces = `[ "[" , "]" ]`.parseList; pieces.should.equal([`"["`,`"]"`]); } /// it should parse two char values that contain a `"` unittest { auto pieces = `[ '"' , '"' ]`.parseList; pieces.should.equal([`'"'`,`'"'`]); } /// it should parse two empty lists unittest { auto pieces = `[ [] , [] ]`.parseList; pieces.should.equal([`[]`,`[]`]); } /// it should parse two nested lists unittest { auto pieces = `[ [[],[]] , [[[]],[]] ]`.parseList; pieces.should.equal([`[[],[]]`,`[[[]],[]]`]); } /// it should parse two lists with items unittest { auto pieces = `[ [1,2] , [3,4] ]`.parseList; pieces.should.equal([`[1,2]`,`[3,4]`]); } /// it should parse two lists with string and char items unittest { auto pieces = `[ ["1", "2"] , ['3', '4'] ]`.parseList; pieces.should.equal([`["1", "2"]`,`['3', '4']`]); } /// it should parse two lists with string and char items unittest { auto pieces = `[ ["1", "2"] , ['3', '4'] ]`.parseList; pieces.should.equal([`["1", "2"]`,`['3', '4']`]); } /// string cleanString(string value) @safe nothrow { if(value.length <= 1) { return value; } char first = value[0]; char last = value[value.length - 1]; if(first == last && (first == '"' || first == '\'')) { return value[1..$-1]; } return value; } /// it should return an empty string when the input is an empty string unittest { "".cleanString.should.equal(""); } /// it should return the input value when it has one char unittest { "'".cleanString.should.equal("'"); } /// it should remove the " from start and end of the string unittest { `""`.cleanString.should.equal(``); } /// it should remove the ' from start and end of the string unittest { `''`.cleanString.should.equal(``); } /// string[] cleanString(string[] pieces) @safe nothrow { return pieces.map!(a => a.cleanString).array; } /// It should return an empty array when the input list is empty unittest { string[] empty; empty.cleanString.should.equal(empty); } /// It should remove the `"` from the begin and end of the string unittest { [`"1"`, `"2"`].cleanString.should.equal([`1`, `2`]); }