1 module tests.protocol_unit;
2 
3 
4 import cerealed;
5 import unit_threaded;
6 import core.exception;
7 
8 
9 struct Unit {
10     ushort us;
11     ubyte ub1;
12     ubyte ub2;
13 }
14 
15 struct Packet {
16     ubyte ub1;
17     ushort length;
18     ubyte ub2;
19     @ArrayLength("length") Unit[] units;
20 }
21 
22 
23 void testUnits() {
24     ubyte[] bytes = [3, 0, 4, 9, 0, 7, 1, 2, 0, 6, 2, 3, 0, 5, 4, 5, 0, 4, 9, 8];
25     auto pkt = decerealise!Packet(bytes);
26 
27     pkt.ub1.shouldEqual(3);
28     pkt.length.shouldEqual(4);
29     pkt.ub2.shouldEqual(9);
30     pkt.units.length.shouldEqual(pkt.length);
31 
32     pkt.units[1].us.shouldEqual(6);
33     pkt.units[1].ub1.shouldEqual(2);
34     pkt.units[1].ub2.shouldEqual(3);
35 
36     auto enc = Cerealiser();
37     enc ~= pkt;
38     enc.bytes.shouldEqual(bytes);
39 }
40 
41 
42 struct PacketWithArrayLengthExpr {
43     static struct Header {
44         ubyte ub;
45         ushort us;
46         ushort length;
47     }
48 
49     enum headerSize = unalignedSizeof!Header;
50     alias header this;
51 
52     Header header;
53     @ArrayLength("length - headerSize") Unit[] units;
54 }
55 
56 void testArrayLengthExpr() {
57     immutable ubyte[] bytes = [3, 0, 7, 0, 8, //header
58                                0, 7, 1, 2,
59                                0, 6, 2, 3,
60                                0, 5, 4, 5];
61     auto pkt = decerealise!PacketWithArrayLengthExpr(bytes);
62 
63     pkt.ub.shouldEqual(3);
64     pkt.us.shouldEqual(7);
65     pkt.units.length.shouldEqual(3);
66 
67     pkt.units[2].us.shouldEqual(5);
68     pkt.units[2].ub1.shouldEqual(4);
69     pkt.units[2].ub2.shouldEqual(5);
70 
71     auto enc = Cerealiser();
72     enc ~= pkt;
73     enc.bytes.shouldEqual(bytes);
74 }
75 
76 
77 struct NegativeStruct {
78     enum len = -1;
79     ushort us;
80     @ArrayLength("len") Unit[] units;
81 }
82 
83 void testNegativeLength() {
84     immutable ubyte[] bytes = [1, 2, 3, 4, 5];
85     decerealise!NegativeStruct(bytes).shouldThrow!CerealException;
86 }
87 
88 
89 void testNotEnoughBytes() {
90     immutable ubyte[] bytes = [3, 0, 7, 0, 8, //header
91                                0, 7]; //truncated
92     decerealise!PacketWithArrayLengthExpr(bytes).shouldThrow!CerealException;
93 }
94 
95 
96 struct PacketWithLengthInBytes {
97     static struct Header {
98         ubyte ub;
99         ushort lengthNoHeader;
100     }
101 
102     enum headerSize = unalignedSizeof!Header;
103     alias header this;
104 
105     Header header;
106     @LengthInBytes("lengthNoHeader - headerSize") Unit[] units;
107 }
108 
109 void testLengthInBytes() {
110     immutable ubyte[] bytes = [ 7, 0, 11, //header (11 bytes = hdr + 2 units of 4 bytes each)
111                                 0, 3, 1, 2,
112                                 0, 9, 3, 4,
113         ];
114     auto pkt = decerealise!PacketWithLengthInBytes(bytes);
115 
116     pkt.ub.shouldEqual(7);
117     pkt.lengthNoHeader.shouldEqual(11);
118     pkt.units.length.shouldEqual(2);
119 
120     pkt.units[0].us.shouldEqual(3);
121     pkt.units[0].ub1.shouldEqual(1);
122     pkt.units[0].ub2.shouldEqual(2);
123 
124     pkt.units[1].us.shouldEqual(9);
125     pkt.units[1].ub1.shouldEqual(3);
126     pkt.units[1].ub2.shouldEqual(4);
127 
128     auto enc = Cerealiser();
129     enc ~= pkt;
130     enc.bytes.shouldEqual(bytes);
131 }
132 
133 
134 struct BigUnit {
135     int i1;
136     int i2;
137 }
138 
139 struct BigUnitPacket {
140     enum headerSize = totalLength.sizeof;
141     ushort totalLength;
142     @LengthInBytes("totalLength - headerSize") BigUnit[] units;
143 }
144 
145 void testLengthInBytesOneUnit() {
146     immutable ubyte[] bytes = [ 0, 10, //totalLength = 1 unit of size 8 + header size of 1
147                                 0, 0, 0, 1, 0, 0, 0, 2
148         ];
149     auto pkt = decerealise!BigUnitPacket(bytes);
150 
151     pkt.totalLength.shouldEqual(bytes.length);
152     pkt.units.length.shouldEqual(1);
153     pkt.units[0].i1.shouldEqual(1);
154     pkt.units[0].i2.shouldEqual(2);
155 
156     auto enc = Cerealiser();
157     enc ~= pkt;
158     enc.bytes.shouldEqual(bytes);
159 }
160 
161 
162 @("RestOfPacket with LengthInBytes")
163 unittest {
164     struct Small {
165         ushort v;
166     }
167     struct Unit {
168         ushort length;
169         @LengthInBytes("length - 2") Small[] smalls;
170     }
171     struct Struct {
172         @RestOfPacket Unit[] units;
173     }
174     immutable ubyte[] bytes =
175         [
176             0, 6, //length
177             0, 1, 0, 2, // smalls
178             0, 4, //length
179             0, 3, //smalls
180         ];
181 
182     auto dec = Decerealiser(bytes);
183     auto pkt = dec.value!Struct;
184 
185     pkt.shouldEqual(
186         Struct([Unit(6,
187                      [
188                          Small(1),
189                          Small(2),
190                      ]
191                        ),
192                 Unit(4,
193                     [
194                         Small(3),
195                     ]
196                     )]));
197 }