1 /** Module containing general helper routines and templates to minimize dupblicate code */
2 module test_pattern_generator;
3 
4 import std.stdint;
5 import std.format;
6 
7 /* Test Pattern Generator */
8 
9 /** PatternGenerator Modes */
10 enum PatterMode
11 {
12     Unknown, /** Unknown default init value */
13     Uniform, /** Uniform fill with same byte, maximum redundancy */
14     RepeatN, /** Repeating 0..255 data, near maximum redundancy */
15     PRandom, /** Pseudo random byte stream from XorShift18 and same seed, no redundancy */
16     Sparse1, /** Sparsed data, mix of random sequence with
17                      inserted [0..ArgN] byte value strings every ArgM bytes, 
18                      only one string pattern within random data */
19     SparseN /** Sparsed data, mix of random sequence with
20                      inserted random value strings every ArgM bytes, 
21                      multiple string pattern within random data */
22 }
23 
24 /** Structure with test pattern mode and parameters */
25 struct TestPattern {
26     PatterMode mode;
27     uint N;
28     int M, O;
29 
30     string toString() const
31     {
32         return format("(%s:%05x:%05x:%02x)", mode, N, M, O);
33     }
34 }
35 
36 unittest
37 {
38     const auto tp = TestPattern().toString;
39     assert ( tp == "(Unknown:00000:00000:00)" );
40     const auto tp1 = TestPattern(PatterMode.Uniform, 255, 0, 0 ).toString;
41     assert ( tp1 == "(Uniform:000ff:00000:00)" );
42     const auto tp2 = TestPattern(PatterMode.PRandom, 32, 0, 0 ).toString;
43     assert ( tp2 == "(PRandom:00020:00000:00)" );
44     const auto tp3 = TestPattern(PatterMode.Sparse1, 1024, 2048, 2 ).toString;
45     assert ( tp3 == "(Sparse1:00400:00800:02)" );
46 }
47 
48 auto testPatternSet = [
49     TestPattern( PatterMode.Uniform,       0,       0, 0 ), // Uniform fill with zero, maximum redundancy 
50     TestPattern( PatterMode.Uniform,    0x55,       0, 0 ), // Uniform fill with 0x55, maximum redundancy 
51     TestPattern( PatterMode.Uniform,    0xff,       0, 0 ), // Uniform fill with 0x55, maximum redundancy 
52     TestPattern( PatterMode.RepeatN,      32,       0, 0 ), // Repeating fill from [0..32] , high redundancy
53     TestPattern( PatterMode.RepeatN,     128,       0, 0 ), // Repeating fill from [0..128], high redundancy
54     TestPattern( PatterMode.RepeatN,     256,       0, 0 ), // Repeating fill from [0..256], high redundancy
55     TestPattern( PatterMode.Sparse1, 0x01000, 0x02000, 0 ), // 50% of data pure random, 50% is of some repeating pattern
56     TestPattern( PatterMode.Sparse1, 0x02000, 0x04000, 0 ), // 50% of data pure random, 50% is of some repeating pattern
57     TestPattern( PatterMode.Sparse1, 0x04000, 0x08000, 0 ), // 50% of data pure random, 50% is of some repeating pattern
58     TestPattern( PatterMode.Sparse1, 0x08000, 0x10000, 0 ), // 50% of data pure random, 50% is of some repeating pattern
59     TestPattern( PatterMode.Sparse1, 0x10000, 0x20000, 0 ), // 50% of data pure random, 50% is of some repeating pattern
60     TestPattern( PatterMode.Sparse1, 0x20000, 0x40000, 0 ), // 50% of data pure random, 50% is of some repeating pattern
61     TestPattern( PatterMode.Sparse1, 0x30000, 0x60000, 0 ), // 50% of data pure random, 50% is of some repeating pattern
62     TestPattern( PatterMode.Sparse1, 0x40000, 0x80000, 0 ), // 50% of data pure random, 50% is of some repeating pattern
63     TestPattern( PatterMode.SparseN,  0x0400,  0x0800, 8 ), // 50% of data pure random, 50% are of 8 different patterns
64     TestPattern( PatterMode.SparseN,  0x0800,  0x1000, 8 ), // 50% of data pure random, 50% are of 8 different patterns
65     TestPattern( PatterMode.SparseN,  0x1000,  0x2000, 8 ), // 50% of data pure random, 50% are of 8 different patterns
66     TestPattern( PatterMode.SparseN,  0x2000,  0x4000, 8 ), // 50% of data pure random, 50% are of 8 different patterns
67     TestPattern( PatterMode.SparseN,  0x3000,  0x6000, 8 ), // 50% of data pure random, 50% are of 8 different patterns
68     TestPattern( PatterMode.SparseN,  0x4000,  0x8000, 8 ), // 50% of data pure random, 50% are of 8 different patterns
69     TestPattern( PatterMode.PRandom,      32,       0, 0 ), // 5 Bit random data, 50% use of token, minimal redundancy  
70     TestPattern( PatterMode.PRandom,     128,       0, 0 ), // 7 Bit random data, 50% use of token, minimal redundancy
71     TestPattern( PatterMode.PRandom,     256,       0, 0 )  // Full random data, no redudancy
72 ];
73 
74 
75 /** Fill the input buffer with a test pattern 
76  *
77  * Param:  input uint8_t[] Dynamic Array to fill with pattern
78  * Param:  mode PatterMode Fill mode to use
79  * Param:  OptN int Argument 1 for fill pattern mode
80  * Param:  OptN int Argument 2 for fill pattern mode
81  * Throws: assert on unknown modes or parametera
82  */
83 void patternGenerator(uint8_t[] input, PatterMode mode, uint OptN = 255, int OptM = 0x10000, int OptO = 8)
84 {
85     import std.random : Xorshift;
86 
87     bool rc = true;
88     switch (mode)
89     {
90     case PatterMode.Uniform:
91         assert(OptN <= 255, "OptN must be 0..255 range");
92         uint8_t fillbyte = cast(uint8_t)(OptN & 0xff);
93         input[] = fillbyte; // Fill complete array ;-)
94         break;
95     case PatterMode.RepeatN:
96         assert(OptN <= 256, "OptN must be 0..256 range");
97         foreach (idx; 0 .. input.length)
98             input[idx] = cast(uint8_t)((idx % OptN) & 0xff);
99         break;
100     case PatterMode.PRandom:
101         assert(OptN <= 256, "OptN must be 0..256 range");
102         auto rnd = Xorshift(1); // Always the same number sequence
103         foreach (idx; 0 .. input.length)
104         {
105             input[idx] = cast(uint8_t)((rnd.front % OptN) & 0xff);
106             rnd.popFront;
107         }
108         break;
109     case PatterMode.SparseN:
110         assert(OptO > 0, "OptO must be > 0");
111         goto case;
112     case PatterMode.Sparse1:
113         assert(OptN <= OptM, "OptN must be <= OptM");
114         auto rndBack = Xorshift(4711);
115         int rndInsertSeed = 1;
116         for (int idx = 0; idx < input.length;)
117         {
118             // Write fulllength randomnumber sequence 
119             input[idx++] = cast(uint8_t)(rndBack.front & 0xff);
120             rndBack.popFront;
121 
122             // Insert repeating random sequences here
123             const bool inspos = (OptN > 0) && ((idx % OptM) >= 0) && ((idx % OptM) < OptN);
124             if (inspos)
125             {
126                 auto rndInsert = Xorshift(rndInsertSeed);
127                 for (int idx2 = 0; idx < input.length && idx2 < OptN; idx2++)
128                 {
129                     rndBack.popFront;
130                     /* Insert something else here */
131                     input[idx++] = cast(uint8_t)(rndInsert.front & 0xff);
132                     rndInsert.popFront;
133                 }
134                 /* Use alternating patterns */
135                 if (mode == PatterMode.SparseN)
136                     rndInsertSeed = (rndInsertSeed++ % OptO) + 1;
137             }
138         }
139         break;
140     default:
141         rc = false;
142         break;
143     }
144     assert(rc == true, "Internal error, unknown PatternMode");
145 }
146 
147 /* Test uniform pattern */
148 unittest
149 {
150     uint8_t[] data;
151     data.length = 8;
152     uint8_t[] comp;
153     comp.length = 8;
154     patternGenerator(data, PatterMode.Uniform, 0);
155     comp[] = 0;
156     assert(data == comp, "Fill 0x00 failed");
157     patternGenerator(data, PatterMode.Uniform, 0x55);
158     comp[] = 0x55;
159     assert(data == comp, "Fill 0x55 failed");
160     patternGenerator(data, PatterMode.Uniform, 0xaa);
161     comp[] = 0xAA;
162     assert(data == comp, "Fill 0xAA failed");
163     patternGenerator(data, PatterMode.Uniform, 0xff);
164     comp[] = 0xFF;
165     assert(data == comp, "Fill 0xFF failed");
166 }
167 
168 /* Test Repeat pattern */
169 unittest
170 {
171     uint8_t[] data;
172     data.length = 16;
173     uint8_t[] comp;
174     comp.length = 16;
175     patternGenerator(data, PatterMode.RepeatN, 3);
176     comp[] = [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0];
177     assert(data == comp, "Repeat modulo3 failed");
178     patternGenerator(data, PatterMode.RepeatN, 4);
179     comp[] = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3];
180     assert(data == comp, "Repeat modulo4 failed");
181     patternGenerator(data, PatterMode.RepeatN, 8);
182     comp[] = [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7];
183     assert(data == comp, "Repeat modulo4 failed");
184 }
185 
186 /* Test PRandom pattern */
187 unittest
188 {
189     uint8_t[] data;
190     data.length = 16;
191     uint8_t[] comp;
192     comp.length = 16;
193     patternGenerator(data, PatterMode.PRandom, 256, 0);
194     comp[] = [
195         23, 182, 139, 174, 11, 151, 22, 60, 220, 35, 99, 148, 144, 150, 42, 125
196     ];
197     assert(data == comp, "PRandom (256,0) failed");
198     patternGenerator(data, PatterMode.PRandom, 256, 0);
199     assert(data == comp, "Repeated PRandom (256,0) failed");
200 
201     comp.length = data.length = 32;
202     patternGenerator(data, PatterMode.PRandom, 256, 0);
203     comp[] = [
204         23, 182, 139, 174, 11, 151, 22, 60, 220, 35, 99, 148, 144, 150, 42, 125,
205         91, 5, 152, 51, 71, 64, 38, 160, 251, 77, 83, 32, 203, 113, 63, 119
206     ];
207     assert(data == comp, "PRandom (256,0) failed");
208     patternGenerator(data, PatterMode.PRandom, 256, 0);
209     assert(data == comp, "Repeated PRandom (256,0) failed");
210 
211     comp.length = data.length = 16;
212     patternGenerator(data, PatterMode.PRandom, 32, 0);
213     comp[] = [23, 22, 11, 14, 11, 23, 22, 28, 28, 3, 3, 20, 16, 22, 10, 29];
214     assert(data == comp, "PRandom (32,0) failed");
215     patternGenerator(data, PatterMode.PRandom, 32, 0);
216     assert(data == comp, "Repeated PRandom (32,0) failed");
217 
218     comp.length = data.length = 32;
219     patternGenerator(data, PatterMode.PRandom, 32, 0);
220     comp[] = [
221         23, 22, 11, 14, 11, 23, 22, 28, 28, 3, 3, 20, 16, 22, 10, 29, 27, 5, 24,
222         19, 7, 0, 6, 0, 27, 13, 19, 0, 11, 17, 31, 23
223     ];
224     assert(data == comp, "PRandom (32,0) failed");
225     patternGenerator(data, PatterMode.PRandom, 32, 0);
226     assert(data == comp, "Repeated PRandom (32,0) failed");
227 }
228 
229 /* Test Sparse1 pattern */
230 unittest
231 {
232     uint8_t[] data;
233     data.length = 16;
234     uint8_t[] comp;
235     comp.length = 16;
236 
237     patternGenerator(data, PatterMode.Sparse1, 0, 8);
238     comp[] = [
239         72, 19, 198, 31, 24, 146, 131, 103, 250, 62, 193, 79, 113, 24, 85, 117
240     ];
241     assert(data == comp, "Spare1 (0,8) failed");
242     patternGenerator(data, PatterMode.Sparse1, 0, 8);
243     assert(data == comp, "Spare1 (0,8) failed");
244 
245     patternGenerator(data, PatterMode.Sparse1, 1, 8);
246     comp[] = [
247         72, 19, 198, 31, 24, 146, 131, 103, 23, 62, 193, 79, 113, 24, 85, 117
248     ];
249     assert(data == comp, "Spare1 (1,8) failed");
250     patternGenerator(data, PatterMode.Sparse1, 1, 8);
251     assert(data == comp, "Spare1 (1,8) failed");
252 
253     patternGenerator(data, PatterMode.Sparse1, 2, 8);
254     comp[] = [
255         72, 23, 182, 31, 24, 146, 131, 103, 23, 182, 193, 79, 113, 24, 85, 117
256     ];
257     assert(data == comp, "Spare1 (2,8) failed");
258     patternGenerator(data, PatterMode.Sparse1, 2, 8);
259     assert(data == comp, "Spare1 (2,8) failed");
260 
261     patternGenerator(data, PatterMode.Sparse1, 3, 8);
262     comp[] = [
263         72, 23, 182, 139, 24, 146, 131, 103, 23, 182, 139, 79, 113, 24, 85, 117
264     ];
265     assert(data == comp, "Spare1 (3,8) failed");
266     patternGenerator(data, PatterMode.Sparse1, 3, 8);
267     assert(data == comp, "Spare1 (3,8) failed");
268 
269     patternGenerator(data, PatterMode.Sparse1, 7, 8);
270     comp[] = [
271         72, 23, 182, 139, 174, 11, 151, 22, 250, 23, 182, 139, 174, 11, 151, 22
272     ];
273     assert(data == comp, "Spare1 (7,8) failed");
274     patternGenerator(data, PatterMode.Sparse1, 7, 8);
275     assert(data == comp, "Spare1 (7,8) failed");
276 }
277 
278 /* Test SparseN pattern */
279 unittest
280 {
281     uint8_t[] data;
282     data.length = 16;
283     uint8_t[] comp;
284     comp.length = 16;
285 
286     patternGenerator(data, PatterMode.SparseN, 0, 4, 2);
287     comp[] = [
288         72, 19, 198, 31, 24, 146, 131, 103, 250, 62, 193, 79, 113, 24, 85, 117
289     ];
290     assert(data == comp, "SpareN (0,4,2) failed");
291     patternGenerator(data, PatterMode.SparseN, 0, 4, 2);
292     assert(data == comp, "SpareN (0,4,2) failed");
293 
294     patternGenerator(data, PatterMode.SparseN, 2, 8, 2);
295     comp[] = [
296         72, 23, 182, 31, 24, 146, 131, 103, 31, 27, 193, 79, 113, 24, 85, 117
297     ];
298     assert(data == comp, "SpareN (2,8,2) failed");
299     patternGenerator(data, PatterMode.SparseN, 2, 8, 2);
300     assert(data == comp, "SpareN (2,8,2) failed");
301 
302 }