1 module tests.decode;
2 
3 import unit_threaded;
4 import cerealed.decerealiser;
5 import core.exception;
6 
7 void testDecodeBool() {
8     import cerealed.cereal: grain;
9     auto cereal = Decerealiser([1, 0, 1, 0, 0, 1]);
10     bool val;
11     cereal.grain(val); shouldEqual(val, true);
12     cereal.grain(val); shouldEqual(val, false);
13     cereal.grain(val); shouldEqual(val, true);
14     cereal.grain(val); shouldEqual(val, false);
15     cereal.grain(val); shouldEqual(val, false);
16     cereal.grain(val); shouldEqual(val, true);
17     cereal.value!bool.shouldThrow!RangeError; //no more bytes
18 }
19 
20 
21 void testDecodeByte() {
22     auto cereal = Decerealiser([0x0, 0x2, 0xfc]);
23     cereal.value!byte.shouldEqual(0);
24     cereal.value!byte.shouldEqual(2);
25     cereal.value!byte.shouldEqual(-4);
26     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
27 }
28 
29 void testDecodeRefByte() {
30     import cerealed.cereal: grain;
31     auto cereal = Decerealiser([0xfc]);
32     byte val;
33     cereal.grain(val);
34     val.shouldEqual(-4);
35 }
36 
37 void testDecodeUByte() {
38     auto cereal = Decerealiser([0x0, 0x2, 0xfc]);
39     cereal.value!ubyte.shouldEqual(0);
40     cereal.value!ubyte.shouldEqual(2);
41     cereal.value!ubyte.shouldEqual(252);
42     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
43 }
44 
45 void testDecodeShort() {
46     auto cereal = Decerealiser([0xff, 0xfe, 0x0, 0x3]);
47     cereal.value!short.shouldEqual(-2);
48     cereal.value!short.shouldEqual(3);
49     shouldThrow!RangeError(cereal.value!short); //no more bytes
50 }
51 
52 void testDecodeRefShort() {
53     import cerealed.cereal: grain;
54     auto cereal = Decerealiser([0xff, 0xfe]);
55     short val;
56     cereal.grain(val);
57     val.shouldEqual(-2);
58 }
59 
60 void testDecodeInt() {
61     auto cereal = Decerealiser([ 0xff, 0xf0, 0xbd, 0xc0]);
62     cereal.value!int.shouldEqual(-1_000_000);
63     shouldThrow!RangeError(cereal.value!int); //no more bytes
64 }
65 
66 void testDecodeRefInt() {
67     import cerealed.cereal: grain;
68     auto cereal = Decerealiser([0xff, 0xf0, 0xbd, 0xc0]);
69     int val;
70     cereal.grain(val);
71     val.shouldEqual(-1_000_000);
72 }
73 
74 void testDecodeLong() {
75     auto cereal = Decerealiser([ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
76     cereal.value!long.shouldEqual(1);
77     cereal.value!long.shouldEqual(2);
78     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
79 }
80 
81 void testDecodeRefLong() {
82     import cerealed.cereal: grain;
83     auto cereal = Decerealiser([ 0, 0, 0, 0, 0, 0, 0, 1]);
84     long val;
85     cereal.grain(val);
86     val.shouldEqual(1);
87 }
88 
89 
90 void testDecodeBigULong() {
91     auto dec = Decerealiser([0xd8, 0xbf, 0xc7, 0xcd, 0x2d, 0x9b, 0xa1, 0xb1]);
92     dec.value!ulong.shouldEqual(0xd8bfc7cd2d9ba1b1);
93     shouldThrow!RangeError(dec.value!ubyte); //no more bytes
94 }
95 
96 
97 void testDecodeDouble() {
98     auto cereal = Decerealiser([ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
99     shouldNotThrow(cereal.value!double);
100     shouldNotThrow(cereal.value!double);
101     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
102 }
103 
104 void testDecodeChars() {
105     auto cereal = Decerealiser([ 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff ]);
106     cereal.value!char.shouldEqual(0xff);
107     cereal.value!wchar.shouldEqual(0xffff);
108     cereal.value!dchar.shouldEqual(0x0000ffff);
109     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
110 }
111 
112 void testDecodeRefChar() {
113     import cerealed.cereal: grain;
114     auto cereal = Decerealiser([0xff]);
115     char val;
116     cereal.grain(val);
117     val.shouldEqual(0xff);
118 }
119 
120 
121 void testDecodeArray() {
122     auto cereal = Decerealiser([ 0, 3, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 9 ]);
123     cereal.value!(int[]).shouldEqual([ 2, 6, 9 ]);
124     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
125 }
126 
127 void testDecodeRefArray() {
128     import cerealed.cereal: grain;
129     auto cereal = Decerealiser([0, 1, 0, 0, 0, 2]);
130     int[] val;
131     cereal.grain(val);
132     val.shouldEqual([2]);
133 }
134 
135 void testDecodeArrayLongLength() {
136     auto cereal = Decerealiser([ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 9 ]);
137     cereal.value!(int[], long).shouldEqual([ 2, 6, 9 ]);
138     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
139 }
140 
141 void testDecodeAssocArray() {
142     auto cereal = Decerealiser([ 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 6 ]);
143     cereal.value!(int[int]).shouldEqual([ 1:2, 3:6]);
144     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
145 }
146 
147 
148 void testDecodeRefAssocArray() {
149     import cerealed.cereal: grain;
150     auto cereal = Decerealiser([0, 1, 0, 0, 0, 2, 0, 0, 0, 3]);
151     int[int] val;
152     cereal.grain(val);
153     val.shouldEqual([2:3]);
154 }
155 
156 void testDecodeAssocArrayIntLength() {
157     auto cereal = Decerealiser([ 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 6 ]);
158     cereal.value!(int[int], int).shouldEqual([ 1:2, 3:6]);
159     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
160 }
161 
162 void testDecodeString() {
163     auto cereal = Decerealiser([0, 5, 'a', 't', 'o', 'y', 'n']);
164     cereal.value!(string).shouldEqual("atoyn");
165     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
166 }
167 
168 void testDecodeRefString() {
169     import cerealed.cereal: grain;
170     auto cereal = Decerealiser([0, 5, 'a', 't', 'o', 'y', 'n']);
171     string val;
172     cereal.grain(val);
173     val.shouldEqual("atoyn");
174     cereal.value!ubyte.shouldThrow!RangeError; //no more bytes
175 }
176 
177 void testDecodeBits() {
178     auto cereal = Decerealiser([ 0x9e, 0xea]);
179     //1001 1110 1110 1010 or
180     //100 111 10111 01 010
181     cereal.readBits(3).shouldEqual(4);
182     cereal.readBits(3).shouldEqual(7);
183     cereal.readBits(5).shouldEqual(23);
184     cereal.readBits(2).shouldEqual(1);
185     cereal.readBits(3).shouldEqual(2);
186 
187     cereal.reset();
188     cereal.readBits(3).shouldEqual(4);
189     cereal.readBits(3).shouldEqual(7);
190     cereal.readBits(5).shouldEqual(23);
191     cereal.readBits(2).shouldEqual(1);
192     cereal.readBits(3).shouldEqual(2);
193 }
194 
195 void testDecodeBitsMultiByte() {
196     auto cereal = Decerealiser([ 0x9e, 0xea]);
197     cereal.readBits(9).shouldEqual(317);
198     cereal.readBits(7).shouldEqual(0x6a);
199 }
200 
201 void testDecodeStringArray() {
202     auto dec = Decerealiser([ 0, 3,
203                               0, 3, 'f', 'o', 'o',
204                               0, 4, 'w', '0', '0', 't',
205                               0, 2, 'l', 'i']);
206     dec.value!(string[]).shouldEqual(["foo", "w00t", "li"]);
207 }
208 
209 @("Decode enum with bad value")
210 unittest {
211     struct Foo {
212         enum Type {
213             foo,
214             bar,
215         }
216         Type type;
217     }
218 
219     Decerealiser([0, 0, 0, 42]).value!(Foo.Type).shouldThrow;
220     Decerealiser([0, 0, 0, 42]).value!Foo.shouldThrow;
221 }
222 
223 
224 @("Throws if length of array is larger than packet")
225 unittest {
226     Decerealiser([0, 8, 1, 2]).value!(ubyte[]).shouldThrowWithMessage(
227         "Not enough bytes left to decerealise ubyte[] of 8 elements\n" ~
228         "Bytes left: 2, Needed: 8, bytes: [1, 2]");
229 
230     Decerealiser([0, 8, 1, 2]).value!(int[]).shouldThrowWithMessage(
231         "Not enough bytes left to decerealise int[] of 8 elements\n" ~
232         "Bytes left: 2, Needed: 32, bytes: [1, 2]");
233 }
234 
235 @("Types with @disable this can be encoded/decoded")
236 @safe unittest {
237     static struct NoDefault {
238         ubyte i;
239         @disable this();
240         this(ubyte i) { this.i = i; }
241     }
242 
243     [5].decerealise!NoDefault.shouldEqual(NoDefault(5));
244 }