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 }