1 module text.json.ValidationTest;
2 
3 version(unittest) import dshould;
4 import std.datetime;
5 import std.json;
6 import std.typecons;
7 import text.json.Validation;
8 
9 @("gets object members")
10 unittest
11 {
12     // given
13     JSONValue[string] members = ["foo": JSONValue("bar")];
14 
15     // when
16     JSONObject actual = JSONValue(members).requireObject;
17 
18     // then
19     actual.should.equal(members);
20 }
21 
22 @("fails to get object members from non-object")
23 unittest
24 {
25     // given
26     JSONValue[] elements = [JSONValue(2), JSONValue(3)];
27 
28     // when/then
29     JSONValue(elements).requireObject.should.throwA!JSONException;
30 }
31 
32 @("gets object members as associative array")
33 unittest
34 {
35     // given
36     string[string] members = ["foo": "bar"];
37 
38     // when
39     string[string] actual = JSONValue(members).requireObject!string;
40 
41     // then
42     actual.should.equal(members);
43 }
44 
45 @("gets array elements")
46 unittest
47 {
48     // given
49     JSONValue[] elements = [JSONValue(2), JSONValue(3)];
50 
51     // when
52     JSONValue[] actual = JSONValue(elements).requireArray;
53 
54     // then
55     actual.should.equal(elements);
56 }
57 
58 @("fails to get array elements from non-array")
59 unittest
60 {
61     // given
62     JSONValue value = JSONValue(["foo": JSONValue("bar")]);
63 
64     // when/then
65     value.requireArray.should.throwA!JSONException;
66 }
67 
68 @("gets array of string elements")
69 unittest
70 {
71     // given
72     JSONValue[] elements = [JSONValue("foo"), JSONValue("bar"), JSONValue("baz")];
73 
74     // when
75     string[] actual = JSONValue(elements).requireArray!string;
76 
77     // then
78     actual.should.equal(["foo", "bar", "baz"]);
79 }
80 
81 @("fails to get array of string elements from heterogenous array")
82 unittest
83 {
84     // given
85     JSONValue[] elements = [JSONValue("foo"), JSONValue(2)];
86 
87     // when/then
88     JSONValue(elements).requireArray!string.should.throwA!JSONException;
89 }
90 
91 @("gets bool")
92 @safe unittest
93 {
94     // when
95     bool actual = JSONValue(true).require!bool;
96 
97     // then
98     actual.should.equal(true);
99 }
100 
101 @("fails to get bool from number")
102 unittest
103 {
104     // when/then
105     JSONValue(42).require!bool.should.throwA!JSONException;
106 }
107 
108 @("gets int")
109 @safe unittest
110 {
111     // when
112     int actual = JSONValue(42).require!int;
113 
114     // then
115     actual.should.equal(42);
116 }
117 
118 @("gets ulong")
119 @safe unittest
120 {
121     // when
122     ulong actual = JSONValue(ulong.max).require!ulong;
123 
124     // then
125     actual.should.equal(ulong.max);
126 }
127 
128 @("fails to get invalid int")
129 unittest
130 {
131     // when/then
132     JSONValue(4.2).require!int.should.throwA!JSONException;
133 }
134 
135 @("fails to get byte out of bounds")
136 unittest
137 {
138     // when/then
139     JSONValue(byte.max + 1).require!byte.should.throwA!JSONException;
140 }
141 
142 @("gets float")
143 @safe unittest
144 {
145     // when
146     float actual = JSONValue(42.3).require!float;
147 
148     // then
149     actual.should.be.approximately(42.3, error = 1e-3);
150 }
151 
152 @("gets double")
153 @safe unittest
154 {
155     // when
156     double actual = JSONValue(42).require!double;
157 
158     // then
159     actual.should.be.approximately(42, error = 1e-6);
160 }
161 
162 @("gets real")
163 @safe unittest
164 {
165     // when
166     real actual = JSONValue(uint.max).require!real;
167 
168     // then
169     actual.should.be.approximately(uint.max, error = 1e-6);
170 }
171 
172 @("fails to get double from string")
173 unittest
174 {
175     // when/then
176     JSONValue("foo").require!double.should.throwA!JSONException;
177 }
178 
179 @("gets string")
180 @safe unittest
181 {
182     // when
183     string actual = JSONValue("foo").require!string;
184 
185     // then
186     actual.should.equal("foo");
187 }
188 
189 @("fails to get string from number")
190 unittest
191 {
192     // when/then
193     JSONValue(42).require!string.should.throwA!JSONException;
194 }
195 
196 @("gets enumeration member")
197 @safe unittest
198 {
199     // given
200     enum Enumeration
201     {
202         VALUE,
203     }
204 
205     // when
206     Enumeration actual = JSONValue("VALUE").require!Enumeration;
207 
208     // then
209     actual.should.equal(Enumeration.VALUE);
210 }
211 
212 @("fails to get invalid enumeration member")
213 unittest
214 {
215     // given
216     enum Enumeration
217     {
218         VALUE,
219     }
220 
221     // when/then
222     JSONValue("foo").require!Enumeration.should.throwA!JSONException;
223 }
224 
225 @("gets flag")
226 @safe unittest
227 {
228     // given
229     alias Answer = Flag!"answer";
230 
231     // when
232     Answer actual = JSONValue(true).require!Answer;
233 
234     // then
235     actual.should.equal(Answer.yes);
236 }
237 
238 @("gets date")
239 @safe unittest
240 {
241     // when
242     Date actual = JSONValue("2003-02-01").require!Date;
243 
244     // then
245     actual.should.equal(Date(2003, 2, 1));
246 }
247 
248 @("gets duration")
249 @safe unittest
250 {
251     // when
252     Duration actual = JSONValue("PT1H2M3S").require!Duration;
253 
254     // then
255     actual.should.equal(1.hours + 2.minutes + 3.seconds);
256 }
257 
258 @("fails to get invalid duration")
259 unittest
260 {
261     // when/then
262     JSONValue("foo").require!Duration.should.throwA!JSONException;
263 }
264 
265 @("gets SysTime")
266 @safe unittest
267 {
268     // when
269     SysTime actual = JSONValue("2003-02-01T11:55:00").require!SysTime;
270 
271     // then
272     actual.should.equal(SysTime(DateTime(2003, 2, 1, 11, 55)));
273 }
274 
275 @("gets time of day")
276 @safe unittest
277 {
278     // when
279     TimeOfDay actual = JSONValue("01:02:03").require!TimeOfDay;
280 
281     // then
282     actual.should.equal(TimeOfDay(1, 2, 3));
283 }
284 
285 @("gets required value")
286 @safe unittest
287 {
288     // given
289     JSONObject object = JSONObject(["foo": JSONValue("bar")]);
290 
291     // when
292     JSONValue actual = object.require("foo");
293 
294     // then
295     actual.should.equal(JSONValue("bar"));
296 }
297 
298 @("fails to get missing value")
299 unittest
300 {
301     // given
302     JSONObject object = JSONObject(["foo": JSONValue("bar")]);
303 
304     // when/then
305     object.require("bar").should.throwA!JSONException;
306 }
307 
308 @("gets required value instead of fallback")
309 @safe unittest
310 {
311     // given
312     JSONObject object = JSONObject(["foo": JSONValue(-1)]);
313 
314     // when
315     int actual = object.require!int("foo", 42);
316 
317     // then
318     actual.should.equal(-1);
319 }
320 
321 @("gets fallback when required value is missing")
322 @safe unittest
323 {
324     // given
325     JSONObject object = JSONObject(["foo": JSONValue(-1)]);
326 
327     // when
328     int actual = object.require!int("bar", 42);
329 
330     // then
331     actual.should.equal(42);
332 }
333 
334 @("fails to get invalid value instead of fallback")
335 unittest
336 {
337     // given
338     JSONObject object = JSONObject(["foo": JSONValue(true)]);
339 
340     // when/then
341     object.require!int("foo", 42).should.throwA!JSONException;
342 }
343 
344 @("gets nullable value")
345 @safe unittest
346 {
347     // given
348     JSONObject object = JSONObject(["foo": JSONValue(-1)]);
349 
350     // when
351     Nullable!int actual = object.require!(Nullable!int)("foo");
352 
353     // then
354     actual.isNull.should.equal(false);
355     actual.get.should.equal(-1);
356 }
357 
358 @("gets null when required value is missing")
359 @safe unittest
360 {
361     // given
362     JSONObject object = JSONObject(["foo": JSONValue(-1)]);
363 
364     // when
365     Nullable!int actual = object.require!(Nullable!int)("bar");
366 
367     // then
368     actual.isNull.should.equal(true);
369 }
370 
371 @("fails to get invalid nullable value")
372 unittest
373 {
374     // given
375     JSONObject object = JSONObject(["foo": JSONValue(true)]);
376 
377     // when/then
378     object.require!(Nullable!int)("foo").should.throwA!JSONException;
379 }