1 module toml_foolery.decode.set_data_test;
2 
3 version(unittest)
4 {
5     import exceeds_expectations;
6     import std.array : staticArray;
7     import toml_foolery.decode.set_data;
8 }
9 
10 
11 @("setData — simple as beans")
12 unittest
13 {
14     struct S
15     {
16         int a;
17     }
18 
19     S s;
20     setData(s, ["a"], -44);
21     expect(s.a).toEqual(-44);
22 }
23 
24 @("setData — rather more complex")
25 unittest
26 {
27     struct X
28     {
29         int abc;
30     }
31 
32     struct S
33     {
34         string d;
35         X box;
36     }
37 
38     S target;
39     setData(target, ["box", "abc"], 525_600);
40     expect(target.box.abc).toEqual(525_600);
41 }
42 
43 @("setData — bloody complex")
44 unittest
45 {
46     struct Surprise
47     {
48         int a;
49         int b;
50         int c;
51     }
52 
53     struct Ogres
54     {
55         struct Are
56         {
57             struct Like
58             {
59                 struct Onions
60                 {
61                     Surprise bye;
62                 }
63 
64                 Onions onions;
65             }
66 
67             Like like;
68         }
69 
70         Are are;
71     }
72 
73     struct S
74     {
75         Ogres ogres;
76     }
77 
78     S s;
79 
80     setData(s, ["ogres", "are", "like", "onions", "bye"], Surprise(827, 912, 9));
81     expect(s.ogres.are.like.onions.bye.a).toEqual(827);
82     expect(s.ogres.are.like.onions.bye.b).toEqual(912);
83     expect(s.ogres.are.like.onions.bye.c).toEqual(9);
84 }
85 
86 @("setData — now with methods")
87 unittest
88 {
89     struct S
90     {
91         struct C
92         {
93             int x;
94         }
95 
96         int a;
97         C c;
98 
99         int noArgs()
100         {
101             return 123;
102         }
103 
104         int oneArg(int c)
105         {
106             return c;
107         }
108 
109         int oodlesOfArgs(int one, string two, char three)
110         {
111             return one;
112         }
113 
114         void proc() { }
115 
116         int varargs(int[] x...)
117         {
118             return x.length > 0 ? x[0] : -1;
119         }
120 
121         C returnsStruct(C andTakesOneToo)
122         {
123             return andTakesOneToo;
124         }
125     }
126 
127     S s;
128 
129     setData(s, ["c", "x"], 5);
130     setData(s, ["a"], 9);
131     expect(s.c.x).toEqual(5);
132     expect(s.a).toEqual(9);
133 }
134 
135 @("setData — properties")
136 unittest
137 {
138     struct S
139     {
140         int _x;
141         int x() @property const { return _x; }
142         void x(int newX) @property { _x = newX; }
143     }
144 
145     S s;
146     setData(s, ["x"], 5);
147     expect(s.x).toEqual(5);
148 }
149 
150 @("setData — read-only properties")
151 unittest
152 {
153     struct S
154     {
155         int y;
156         int x() @property const { return y; }
157     }
158 
159     S s;
160     // Just needs to compile:
161     setData(s, ["y"], 5);
162 }
163 
164 @("setData — fail compilation if struct contains a @property of type struct")
165 unittest
166 {
167     struct S
168     {
169         struct C
170         {
171             int x;
172         }
173 
174         C _c;
175         C c() @property const { return _c; }
176     }
177 
178     S s;
179     // C returns an rvalue, which cannot be ref, so it should be ignored by setData.
180     // This should compile but c.x can't be changed.
181     static assert (!__traits(compiles, setData(s, ["c", "x"], 5)));
182 }
183 
184 @("setData — Static array -> Static array")
185 unittest
186 {
187     struct S
188     {
189         int[4] statArr;
190         int[5] badSizeStatArr;
191     }
192 
193     S s;
194 
195     setData(s, ["statArr"], staticArray!(int, 4)([27, 92, 71, -34]));
196     expect(s.statArr).toEqual(staticArray!(int, 4)([27, 92, 71, -34]));
197 
198     expect({ setData(s, ["badSizeStatArr"], staticArray!(int, 4)([62, 12, 92, 10])); }).toThrow!Exception;
199 
200     int[] dynArr = [33, 22, 11, 99];
201     setData(s, ["statArr"], dynArr);
202     expect(s.statArr).toEqual(staticArray!(int, 4)([33, 22, 11, 99]));
203 }
204 
205 @("setData — Into Static Array")
206 unittest
207 {
208     int[5] x;
209 
210     setData(x, ["4"], 99);
211     expect(x[4]).toEqual(99);
212 }
213 
214 @("setData — Into Static Array (out of range)")
215 unittest
216 {
217     int[5] x;
218 
219     setData(x, ["5"], 99);
220 
221     expect(x).toEqual((int[5]).init);
222 }
223 
224 @("setData — Into Dynamic Array (with resizing)")
225 unittest
226 {
227     int[] x;
228 
229     expect(x.length).toEqual(0);
230     setData(x, ["5"], 88);
231     expect(x.length).toEqual(6);
232     expect(x[5]).toEqual(88);
233 }
234 
235 @("setData — Into static array of arrays")
236 unittest
237 {
238     int[6][4] x;
239 
240     setData(x, ["3", "5"], 88);
241     expect(x[3][5]).toEqual(88);
242 }
243 
244 @("setData — Into dynamic array of arrays")
245 unittest
246 {
247     int[][] x;
248 
249     setData(x, ["5", "3"], 88);
250     expect(x.length).toEqual(6);
251     expect(x[5].length).toEqual(4);
252     expect(x[5][3]).toEqual(88);
253 }
254 
255 @("setData — Into dynamic array of structs")
256 unittest
257 {
258     struct S
259     {
260         int x;
261     }
262 
263     S[] s;
264 
265     setData(s, ["5", "x"], 88);
266     expect(s.length).toEqual(6);
267     expect(s[5].x).toEqual(88);
268 }
269 
270 @("setData — Into static array of structs")
271 unittest
272 {
273     struct S
274     {
275         int x;
276     }
277 
278     S[4] s;
279 
280     setData(s, ["3", "x"], 88);
281     expect(s[3].x).toEqual(88);
282 }
283 
284 @("setData — Into field that is static array of ints")
285 unittest
286 {
287     struct S
288     {
289         int[3] i;
290     }
291 
292     S s;
293     setData(s, ["i", "2"], 772);
294 
295     expect(s.i[2]).toEqual(772);
296 }
297 
298 @("setData — Into field that is static array of structs")
299 unittest
300 {
301     struct Outer
302     {
303         struct Inner
304         {
305             int x;
306         }
307 
308         Inner[3] inner;
309     }
310 
311     Outer outer;
312     setData(outer, ["inner", "2", "x"], 202);
313 
314     expect(outer.inner[2].x).toEqual(202);
315 }
316 
317 @("setData — array of struct with array of array of structs")
318 unittest
319 {
320     struct A
321     {
322         struct B
323         {
324             struct C
325             {
326                 int x;
327             }
328 
329             C[4][2] c;
330         }
331 
332         B[3] b;
333     }
334 
335     A a;
336 
337     setData(a, ["b", "2", "c", "1", "3", "x"], 773);
338     expect(a.b[2].c[1][3].x).toEqual(773);
339 }