1 module tests.range;
2 
3 import unit_threaded;
4 import cerealed;
5 import std.range;
6 import core.exception;
7 
8 
9 void testInputRange() {
10     auto enc = Cerealiser();
11     enc ~= iota(cast(ubyte)5);
12     enc.bytes.shouldEqual([0, 5, 0, 1, 2, 3, 4]);
13 }
14 
15 private ubyte[] gOutputBytes;
16 
17 private struct MyOutputRange {
18     void put(in ubyte b) {
19         gOutputBytes ~= b;
20     }
21 }
22 
23 void testMyOutputRange() {
24     static assert(isOutputRange!(MyOutputRange, ubyte));
25 }
26 
27 @SingleThreaded
28 void testOutputRangeValue() {
29     gOutputBytes = [];
30 
31     auto dec = Decerealiser([0, 5, 2, 3, 9, 6, 1]);
32     auto output = dec.value!MyOutputRange;
33 
34     gOutputBytes.shouldEqual([2, 3, 9, 6, 1]);
35 }
36 
37 @SingleThreaded
38 void testOutputRangeRead() {
39     gOutputBytes = [];
40 
41     auto dec = Decerealiser([0, 5, 2, 3, 9, 6, 1]);
42     auto output = MyOutputRange();
43     dec.read(output);
44 
45     gOutputBytes.shouldEqual([2, 3, 9, 6, 1]);
46 }
47 
48 
49 private ubyte[] gInputBytes;
50 
51 private struct MyInputRange {
52     this(ubyte[] bytes) { gInputBytes = bytes; }
53     ubyte front() { return gInputBytes.front; }
54     void popFront() { gInputBytes.popFront; }
55     bool empty() { return gInputBytes.empty(); }
56     @property ulong length() { return gInputBytes.length; }
57     static assert(isInputRange!MyInputRange);
58 }
59 
60 private struct StructWithInputRange {
61     ubyte b;
62     MyInputRange input;
63 }
64 
65 @SingleThreaded
66 void testEmbeddedInputRange() {
67     auto enc = Cerealiser();
68     auto str = StructWithInputRange(2, MyInputRange([9, 7, 6]));
69     enc ~= str;
70     const bytes = [2, 0, 3, 9, 7, 6];
71     enc.bytes.shouldEqual(bytes);
72 
73     //no deserialisation for InputRange
74     auto dec = Decerealiser(bytes);
75     enum compiles = __traits(compiles, { dec.value!StructWithInputRange; });
76     static assert(!compiles, "Should not be able to read into an InputRange");
77 }
78 
79 private struct StructWithOutputRange {
80     ubyte b1;
81     MyOutputRange output;
82     ubyte b2;
83 }
84 
85 @SingleThreaded
86 void testEmbeddedOutputRange() {
87     auto enc = Cerealiser();
88     enum compiles = __traits(compiles, { enc ~= StructWithOutputRange(); });
89     static assert(!compiles, "Should not be able to read from an OutputRange");
90     gOutputBytes = [];
91     auto dec = Decerealiser([255, //1st byte
92                              0, 3, 9, 7, 6, //length, values
93                              12]); //2nd byte
94     dec.bytes.shouldEqual([255, 0, 3, 9, 7, 6, 12]);
95     const str = dec.value!StructWithOutputRange;
96     writelnUt("dec bytes is ", dec.bytes);
97     dec.value!ubyte.shouldThrow!RangeError; //no more bytes
98 
99     str.b1.shouldEqual(255);
100     str.b2.shouldEqual(12);
101     gOutputBytes.shouldEqual([9, 7, 6]);
102 }