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 }