Electroneum
schematest.cpp
Go to the documentation of this file.
1 // Tencent is pleased to support the open source community by making RapidJSON available.
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 #include "unittest.h"
16 #include "rapidjson/schema.h"
17 #include "rapidjson/stringbuffer.h"
18 #include "rapidjson/writer.h"
19 
20 #ifdef __clang__
21 RAPIDJSON_DIAG_PUSH
22 RAPIDJSON_DIAG_OFF(variadic-macros)
23 #elif defined(_MSC_VER)
24 RAPIDJSON_DIAG_PUSH
25 RAPIDJSON_DIAG_OFF(4822) // local class member function does not have a body
26 #endif
27 
28 using namespace rapidjson;
29 
30 #define TEST_HASHER(json1, json2, expected) \
31 {\
32  Document d1, d2;\
33  d1.Parse(json1);\
34  ASSERT_FALSE(d1.HasParseError());\
35  d2.Parse(json2);\
36  ASSERT_FALSE(d2.HasParseError());\
37  internal::Hasher<Value, CrtAllocator> h1, h2;\
38  d1.Accept(h1);\
39  d2.Accept(h2);\
40  ASSERT_TRUE(h1.IsValid());\
41  ASSERT_TRUE(h2.IsValid());\
42  /*printf("%s: 0x%016llx\n%s: 0x%016llx\n\n", json1, h1.GetHashCode(), json2, h2.GetHashCode());*/\
43  EXPECT_TRUE(expected == (h1.GetHashCode() == h2.GetHashCode()));\
44 }
45 
47  TEST_HASHER("null", "null", true);
48 
49  TEST_HASHER("true", "true", true);
50  TEST_HASHER("false", "false", true);
51  TEST_HASHER("true", "false", false);
52  TEST_HASHER("false", "true", false);
53  TEST_HASHER("true", "null", false);
54  TEST_HASHER("false", "null", false);
55 
56  TEST_HASHER("1", "1", true);
57  TEST_HASHER("2147483648", "2147483648", true); // 2^31 can only be fit in unsigned
58  TEST_HASHER("-2147483649", "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
59  TEST_HASHER("2147483648", "2147483648", true); // 2^31 can only be fit in unsigned
60  TEST_HASHER("4294967296", "4294967296", true); // 2^32 can only be fit in int64_t
61  TEST_HASHER("9223372036854775808", "9223372036854775808", true); // 2^63 can only be fit in uint64_t
62  TEST_HASHER("1.5", "1.5", true);
63  TEST_HASHER("1", "1.0", true);
64  TEST_HASHER("1", "-1", false);
65  TEST_HASHER("0.0", "-0.0", false);
66  TEST_HASHER("1", "true", false);
67  TEST_HASHER("0", "false", false);
68  TEST_HASHER("0", "null", false);
69 
70  TEST_HASHER("\"\"", "\"\"", true);
71  TEST_HASHER("\"\"", "\"\\u0000\"", false);
72  TEST_HASHER("\"Hello\"", "\"Hello\"", true);
73  TEST_HASHER("\"Hello\"", "\"World\"", false);
74  TEST_HASHER("\"Hello\"", "null", false);
75  TEST_HASHER("\"Hello\\u0000\"", "\"Hello\"", false);
76  TEST_HASHER("\"\"", "null", false);
77  TEST_HASHER("\"\"", "true", false);
78  TEST_HASHER("\"\"", "false", false);
79 
80  TEST_HASHER("[]", "[ ]", true);
81  TEST_HASHER("[1, true, false]", "[1, true, false]", true);
82  TEST_HASHER("[1, true, false]", "[1, true]", false);
83  TEST_HASHER("[1, 2]", "[2, 1]", false);
84  TEST_HASHER("[[1], 2]", "[[1, 2]]", false);
85  TEST_HASHER("[1, 2]", "[1, [2]]", false);
86  TEST_HASHER("[]", "null", false);
87  TEST_HASHER("[]", "true", false);
88  TEST_HASHER("[]", "false", false);
89  TEST_HASHER("[]", "0", false);
90  TEST_HASHER("[]", "0.0", false);
91  TEST_HASHER("[]", "\"\"", false);
92 
93  TEST_HASHER("{}", "{ }", true);
94  TEST_HASHER("{\"a\":1}", "{\"a\":1}", true);
95  TEST_HASHER("{\"a\":1}", "{\"b\":1}", false);
96  TEST_HASHER("{\"a\":1}", "{\"a\":2}", false);
97  TEST_HASHER("{\"a\":1, \"b\":2}", "{\"b\":2, \"a\":1}", true); // Member order insensitive
98  TEST_HASHER("{}", "null", false);
99  TEST_HASHER("{}", "false", false);
100  TEST_HASHER("{}", "true", false);
101  TEST_HASHER("{}", "0", false);
102  TEST_HASHER("{}", "0.0", false);
103  TEST_HASHER("{}", "\"\"", false);
104 }
105 
106 // Test cases following http://spacetelescope.github.io/understanding-json-schema
107 
108 #define VALIDATE(schema, json, expected) \
109 {\
110  SchemaValidator validator(schema);\
111  Document d;\
112  /*printf("\n%s\n", json);*/\
113  d.Parse(json);\
114  EXPECT_FALSE(d.HasParseError());\
115  EXPECT_TRUE(expected == d.Accept(validator));\
116  EXPECT_TRUE(expected == validator.IsValid());\
117  if ((expected) && !validator.IsValid()) {\
118  StringBuffer sb;\
119  validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\
120  printf("Invalid schema: %s\n", sb.GetString());\
121  printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());\
122  sb.Clear();\
123  validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\
124  printf("Invalid document: %s\n", sb.GetString());\
125  sb.Clear();\
126  Writer<StringBuffer> w(sb);\
127  validator.GetError().Accept(w);\
128  printf("Validation error: %s\n", sb.GetString());\
129  }\
130 }
131 
132 #define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error) \
133 {\
134  INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, SchemaValidator, Pointer) \
135 }
136 
137 #define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, \
138  SchemaValidatorType, PointerType) \
139 {\
140  SchemaValidatorType validator(schema);\
141  Document d;\
142  /*printf("\n%s\n", json);*/\
143  d.Parse(json);\
144  EXPECT_FALSE(d.HasParseError());\
145  EXPECT_FALSE(d.Accept(validator));\
146  EXPECT_FALSE(validator.IsValid());\
147  if (validator.GetInvalidSchemaPointer() != PointerType(invalidSchemaPointer)) {\
148  StringBuffer sb;\
149  validator.GetInvalidSchemaPointer().Stringify(sb);\
150  printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\
151  ADD_FAILURE();\
152  }\
153  ASSERT_TRUE(validator.GetInvalidSchemaKeyword() != 0);\
154  if (strcmp(validator.GetInvalidSchemaKeyword(), invalidSchemaKeyword) != 0) {\
155  printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\
156  ADD_FAILURE();\
157  }\
158  if (validator.GetInvalidDocumentPointer() != PointerType(invalidDocumentPointer)) {\
159  StringBuffer sb;\
160  validator.GetInvalidDocumentPointer().Stringify(sb);\
161  printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\
162  ADD_FAILURE();\
163  }\
164  Document e;\
165  e.Parse(error);\
166  if (validator.GetError() != e) {\
167  StringBuffer sb;\
168  Writer<StringBuffer> w(sb);\
169  validator.GetError().Accept(w);\
170  printf("GetError() Expected: %s Actual: %s\n", error, sb.GetString());\
171  ADD_FAILURE();\
172  }\
173 }
174 
175 TEST(SchemaValidator, Typeless) {
176  Document sd;
177  sd.Parse("{}");
178  SchemaDocument s(sd);
179 
180  VALIDATE(s, "42", true);
181  VALIDATE(s, "\"I'm a string\"", true);
182  VALIDATE(s, "{ \"an\": [ \"arbitrarily\", \"nested\" ], \"data\": \"structure\" }", true);
183 }
184 
185 TEST(SchemaValidator, MultiType) {
186  Document sd;
187  sd.Parse("{ \"type\": [\"number\", \"string\"] }");
188  SchemaDocument s(sd);
189 
190  VALIDATE(s, "42", true);
191  VALIDATE(s, "\"Life, the universe, and everything\"", true);
192  INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
193  "{ \"type\": {"
194  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
195  " \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
196  "}}");
197 }
198 
199 TEST(SchemaValidator, Enum_Typed) {
200  Document sd;
201  sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
202  SchemaDocument s(sd);
203 
204  VALIDATE(s, "\"red\"", true);
205  INVALIDATE(s, "\"blue\"", "", "enum", "",
206  "{ \"enum\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
207 }
208 
209 TEST(SchemaValidator, Enum_Typless) {
210  Document sd;
211  sd.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }");
212  SchemaDocument s(sd);
213 
214  VALIDATE(s, "\"red\"", true);
215  VALIDATE(s, "null", true);
216  VALIDATE(s, "42", true);
217  INVALIDATE(s, "0", "", "enum", "",
218  "{ \"enum\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
219 }
220 
221 TEST(SchemaValidator, Enum_InvalidType) {
222  Document sd;
223  sd.Parse("{ \"type\": \"string\", \"enum\": [\"red\", \"amber\", \"green\", null] }");
224  SchemaDocument s(sd);
225 
226  VALIDATE(s, "\"red\"", true);
227  INVALIDATE(s, "null", "", "type", "",
228  "{ \"type\": {"
229  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
230  " \"expected\": [\"string\"], \"actual\": \"null\""
231  "}}");
232 }
233 
235  {
236  Document sd;
237  sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"string\", \"maxLength\": 5 }]}");
238  SchemaDocument s(sd);
239 
240  VALIDATE(s, "\"ok\"", true);
241  INVALIDATE(s, "\"too long\"", "", "allOf", "",
242  "{ \"maxLength\": { "
243  " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", "
244  " \"expected\": 5, \"actual\": \"too long\""
245  "}}");
246  }
247  {
248  Document sd;
249  sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
250  SchemaDocument s(sd);
251 
252  VALIDATE(s, "\"No way\"", false);
253  INVALIDATE(s, "-1", "", "allOf", "",
254  "{ \"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
255  " \"expected\": [\"string\"], \"actual\": \"integer\""
256  "}}");
257  }
258 }
259 
261  Document sd;
262  sd.Parse("{\"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
263  SchemaDocument s(sd);
264 
265  VALIDATE(s, "\"Yes\"", true);
266  VALIDATE(s, "42", true);
267  INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "",
268  "{ \"anyOf\": {"
269  " \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
270  " \"errors\": ["
271  " { \"type\": {"
272  " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\","
273  " \"expected\": [\"string\"], \"actual\": \"object\""
274  " }},"
275  " { \"type\": {"
276  " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/1\","
277  " \"expected\": [\"number\"], \"actual\": \"object\""
278  " }}"
279  " ]"
280  "}}");
281 }
282 
283 TEST(SchemaValidator, OneOf) {
284  Document sd;
285  sd.Parse("{\"oneOf\": [{ \"type\": \"number\", \"multipleOf\": 5 }, { \"type\": \"number\", \"multipleOf\": 3 } ] }");
286  SchemaDocument s(sd);
287 
288  VALIDATE(s, "10", true);
289  VALIDATE(s, "9", true);
290  INVALIDATE(s, "2", "", "oneOf", "",
291  "{ \"oneOf\": {"
292  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
293  " \"errors\": ["
294  " { \"multipleOf\": {"
295  " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/0\","
296  " \"expected\": 5, \"actual\": 2"
297  " }},"
298  " { \"multipleOf\": {"
299  " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/1\","
300  " \"expected\": 3, \"actual\": 2"
301  " }}"
302  " ]"
303  "}}");
304  INVALIDATE(s, "15", "", "oneOf", "",
305  "{ \"oneOf\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"errors\": [{}, {}]}}");
306 }
307 
308 TEST(SchemaValidator, Not) {
309  Document sd;
310  sd.Parse("{\"not\":{ \"type\": \"string\"}}");
311  SchemaDocument s(sd);
312 
313  VALIDATE(s, "42", true);
314  VALIDATE(s, "{ \"key\": \"value\" }", true);
315  INVALIDATE(s, "\"I am a string\"", "", "not", "",
316  "{ \"not\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
317 }
318 
320  Document sd;
321  sd.Parse(
322  "{"
323  " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
324  ""
325  " \"definitions\": {"
326  " \"address\": {"
327  " \"type\": \"object\","
328  " \"properties\": {"
329  " \"street_address\": { \"type\": \"string\" },"
330  " \"city\": { \"type\": \"string\" },"
331  " \"state\": { \"type\": \"string\" }"
332  " },"
333  " \"required\": [\"street_address\", \"city\", \"state\"]"
334  " }"
335  " },"
336  " \"type\": \"object\","
337  " \"properties\": {"
338  " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
339  " \"shipping_address\": { \"$ref\": \"#/definitions/address\" }"
340  " }"
341  "}");
342  SchemaDocument s(sd);
343 
344  VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"}, \"billing_address\": {\"street_address\": \"1st Street SE\", \"city\": \"Washington\", \"state\": \"DC\"} }", true);
345 }
346 
347 TEST(SchemaValidator, Ref_AllOf) {
348  Document sd;
349  sd.Parse(
350  "{"
351  " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
352  ""
353  " \"definitions\": {"
354  " \"address\": {"
355  " \"type\": \"object\","
356  " \"properties\": {"
357  " \"street_address\": { \"type\": \"string\" },"
358  " \"city\": { \"type\": \"string\" },"
359  " \"state\": { \"type\": \"string\" }"
360  " },"
361  " \"required\": [\"street_address\", \"city\", \"state\"]"
362  " }"
363  " },"
364  " \"type\": \"object\","
365  " \"properties\": {"
366  " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
367  " \"shipping_address\": {"
368  " \"allOf\": ["
369  " { \"$ref\": \"#/definitions/address\" },"
370  " { \"properties\":"
371  " { \"type\": { \"enum\": [ \"residential\", \"business\" ] } },"
372  " \"required\": [\"type\"]"
373  " }"
374  " ]"
375  " }"
376  " }"
377  "}");
378  SchemaDocument s(sd);
379 
380  INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address",
381  "{ \"required\": {"
382  " \"instanceRef\": \"#/shipping_address\","
383  " \"schemaRef\": \"#/properties/shipping_address/allOf/1\","
384  " \"missing\": [\"type\"]"
385  "}}");
386  VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true);
387 }
388 
389 TEST(SchemaValidator, String) {
390  Document sd;
391  sd.Parse("{\"type\":\"string\"}");
392  SchemaDocument s(sd);
393 
394  VALIDATE(s, "\"I'm a string\"", true);
395  INVALIDATE(s, "42", "", "type", "",
396  "{ \"type\": {"
397  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
398  " \"expected\": [\"string\"], \"actual\": \"integer\""
399  "}}");
400  INVALIDATE(s, "2147483648", "", "type", "",
401  "{ \"type\": {"
402  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
403  " \"expected\": [\"string\"], \"actual\": \"integer\""
404  "}}"); // 2^31 can only be fit in unsigned
405  INVALIDATE(s, "-2147483649", "", "type", "",
406  "{ \"type\": {"
407  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
408  " \"expected\": [\"string\"], \"actual\": \"integer\""
409  "}}"); // -2^31 - 1 can only be fit in int64_t
410  INVALIDATE(s, "4294967296", "", "type", "",
411  "{ \"type\": {"
412  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
413  " \"expected\": [\"string\"], \"actual\": \"integer\""
414  "}}"); // 2^32 can only be fit in int64_t
415  INVALIDATE(s, "3.1415926", "", "type", "",
416  "{ \"type\": {"
417  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
418  " \"expected\": [\"string\"], \"actual\": \"number\""
419  "}}");
420 }
421 
422 TEST(SchemaValidator, String_LengthRange) {
423  Document sd;
424  sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
425  SchemaDocument s(sd);
426 
427  INVALIDATE(s, "\"A\"", "", "minLength", "",
428  "{ \"minLength\": {"
429  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
430  " \"expected\": 2, \"actual\": \"A\""
431  "}}");
432  VALIDATE(s, "\"AB\"", true);
433  VALIDATE(s, "\"ABC\"", true);
434  INVALIDATE(s, "\"ABCD\"", "", "maxLength", "",
435  "{ \"maxLength\": {"
436  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
437  " \"expected\": 3, \"actual\": \"ABCD\""
438  "}}");
439 }
440 
441 #if RAPIDJSON_SCHEMA_HAS_REGEX
442 TEST(SchemaValidator, String_Pattern) {
443  Document sd;
444  sd.Parse("{\"type\":\"string\",\"pattern\":\"^(\\\\([0-9]{3}\\\\))?[0-9]{3}-[0-9]{4}$\"}");
445  SchemaDocument s(sd);
446 
447  VALIDATE(s, "\"555-1212\"", true);
448  VALIDATE(s, "\"(888)555-1212\"", true);
449  INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "",
450  "{ \"pattern\": {"
451  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
452  " \"actual\": \"(888)555-1212 ext. 532\""
453  "}}");
454  INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "",
455  "{ \"pattern\": {"
456  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
457  " \"actual\": \"(800)FLOWERS\""
458  "}}");
459 }
460 
461 TEST(SchemaValidator, String_Pattern_Invalid) {
462  Document sd;
463  sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}"); // TODO: report regex is invalid somehow
464  SchemaDocument s(sd);
465 
466  VALIDATE(s, "\"\"", true);
467  VALIDATE(s, "\"a\"", true);
468  VALIDATE(s, "\"aa\"", true);
469 }
470 #endif
471 
472 TEST(SchemaValidator, Integer) {
473  Document sd;
474  sd.Parse("{\"type\":\"integer\"}");
475  SchemaDocument s(sd);
476 
477  VALIDATE(s, "42", true);
478  VALIDATE(s, "-1", true);
479  VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned
480  VALIDATE(s, "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
481  VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned
482  VALIDATE(s, "4294967296", true); // 2^32 can only be fit in int64_t
483  INVALIDATE(s, "3.1415926", "", "type", "",
484  "{ \"type\": {"
485  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
486  " \"expected\": [\"integer\"], \"actual\": \"number\""
487  "}}");
488  INVALIDATE(s, "\"42\"", "", "type", "",
489  "{ \"type\": {"
490  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
491  " \"expected\": [\"integer\"], \"actual\": \"string\""
492  "}}");
493 }
494 
495 TEST(SchemaValidator, Integer_Range) {
496  Document sd;
497  sd.Parse("{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
498  SchemaDocument s(sd);
499 
500  INVALIDATE(s, "-1", "", "minimum", "",
501  "{ \"minimum\": {"
502  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
503  " \"expected\": 0, \"actual\": -1"
504  "}}");
505  VALIDATE(s, "0", true);
506  VALIDATE(s, "10", true);
507  VALIDATE(s, "99", true);
508  INVALIDATE(s, "100", "", "maximum", "",
509  "{ \"maximum\": {"
510  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
511  " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
512  "}}");
513  INVALIDATE(s, "101", "", "maximum", "",
514  "{ \"maximum\": {"
515  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
516  " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101"
517  "}}");
518 }
519 
520 TEST(SchemaValidator, Integer_Range64Boundary) {
521  Document sd;
522  sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":9223372036854775806}");
523  SchemaDocument s(sd);
524 
525  INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
526  "{ \"minimum\": {"
527  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
528  " \"expected\": -9223372036854775807, \"actual\": -9223372036854775808"
529  "}}");
530  VALIDATE(s, "-9223372036854775807", true);
531  VALIDATE(s, "-2147483648", true); // int min
532  VALIDATE(s, "0", true);
533  VALIDATE(s, "2147483647", true); // int max
534  VALIDATE(s, "2147483648", true); // unsigned first
535  VALIDATE(s, "4294967295", true); // unsigned max
536  VALIDATE(s, "9223372036854775806", true);
537  INVALIDATE(s, "9223372036854775807", "", "maximum", "",
538  "{ \"maximum\": {"
539  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
540  " \"expected\": 9223372036854775806, \"actual\": 9223372036854775807"
541  "}}");
542  INVALIDATE(s, "18446744073709551615", "", "maximum", "",
543  "{ \"maximum\": {"
544  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
545  " \"expected\": 9223372036854775806, \"actual\": 18446744073709551615"
546  "}}"); // uint64_t max
547 }
548 
549 TEST(SchemaValidator, Integer_RangeU64Boundary) {
550  Document sd;
551  sd.Parse("{\"type\":\"integer\",\"minimum\":9223372036854775808,\"maximum\":18446744073709551614}");
552  SchemaDocument s(sd);
553 
554  INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
555  "{ \"minimum\": {"
556  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
557  " \"expected\": 9223372036854775808, \"actual\": -9223372036854775808"
558  "}}");
559  INVALIDATE(s, "9223372036854775807", "", "minimum", "",
560  "{ \"minimum\": {"
561  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
562  " \"expected\": 9223372036854775808, \"actual\": 9223372036854775807"
563  "}}");
564  INVALIDATE(s, "-2147483648", "", "minimum", "",
565  "{ \"minimum\": {"
566  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
567  " \"expected\": 9223372036854775808, \"actual\": -2147483648"
568  "}}"); // int min
569  INVALIDATE(s, "0", "", "minimum", "",
570  "{ \"minimum\": {"
571  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
572  " \"expected\": 9223372036854775808, \"actual\": 0"
573  "}}");
574  INVALIDATE(s, "2147483647", "", "minimum", "",
575  "{ \"minimum\": {"
576  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
577  " \"expected\": 9223372036854775808, \"actual\": 2147483647"
578  "}}"); // int max
579  INVALIDATE(s, "2147483648", "", "minimum", "",
580  "{ \"minimum\": {"
581  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
582  " \"expected\": 9223372036854775808, \"actual\": 2147483648"
583  "}}"); // unsigned first
584  INVALIDATE(s, "4294967295", "", "minimum", "",
585  "{ \"minimum\": {"
586  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
587  " \"expected\": 9223372036854775808, \"actual\": 4294967295"
588  "}}"); // unsigned max
589  VALIDATE(s, "9223372036854775808", true);
590  VALIDATE(s, "18446744073709551614", true);
591  INVALIDATE(s, "18446744073709551615", "", "maximum", "",
592  "{ \"maximum\": {"
593  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
594  " \"expected\": 18446744073709551614, \"actual\": 18446744073709551615"
595  "}}");
596 }
597 
598 TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
599  Document sd;
600  sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}");
601  SchemaDocument s(sd);
602 
603  INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
604  "{ \"minimum\": {"
605  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
606  " \"expected\": -9223372036854775808, \"exclusiveMinimum\": true, "
607  " \"actual\": -9223372036854775808"
608  "}}");
609  VALIDATE(s, "-9223372036854775807", true);
610  VALIDATE(s, "18446744073709551614", true);
611  INVALIDATE(s, "18446744073709551615", "", "maximum", "",
612  "{ \"maximum\": {"
613  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
614  " \"expected\": 18446744073709551615, \"exclusiveMaximum\": true, "
615  " \"actual\": 18446744073709551615"
616  "}}");
617 }
618 
619 TEST(SchemaValidator, Integer_MultipleOf) {
620  Document sd;
621  sd.Parse("{\"type\":\"integer\",\"multipleOf\":10}");
622  SchemaDocument s(sd);
623 
624  VALIDATE(s, "0", true);
625  VALIDATE(s, "10", true);
626  VALIDATE(s, "-10", true);
627  VALIDATE(s, "20", true);
628  INVALIDATE(s, "23", "", "multipleOf", "",
629  "{ \"multipleOf\": {"
630  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
631  " \"expected\": 10, \"actual\": 23"
632  "}}");
633  INVALIDATE(s, "-23", "", "multipleOf", "",
634  "{ \"multipleOf\": {"
635  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
636  " \"expected\": 10, \"actual\": -23"
637  "}}");
638 }
639 
640 TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
641  Document sd;
642  sd.Parse("{\"type\":\"integer\",\"multipleOf\":18446744073709551615}");
643  SchemaDocument s(sd);
644 
645  VALIDATE(s, "0", true);
646  VALIDATE(s, "18446744073709551615", true);
647  INVALIDATE(s, "18446744073709551614", "", "multipleOf", "",
648  "{ \"multipleOf\": {"
649  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
650  " \"expected\": 18446744073709551615, \"actual\": 18446744073709551614"
651  "}}");
652 }
653 
654 TEST(SchemaValidator, Number_Range) {
655  Document sd;
656  sd.Parse("{\"type\":\"number\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
657  SchemaDocument s(sd);
658 
659  INVALIDATE(s, "-1", "", "minimum", "",
660  "{ \"minimum\": {"
661  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
662  " \"expected\": 0, \"actual\": -1"
663  "}}");
664  VALIDATE(s, "0", true);
665  VALIDATE(s, "0.1", true);
666  VALIDATE(s, "10", true);
667  VALIDATE(s, "99", true);
668  VALIDATE(s, "99.9", true);
669  INVALIDATE(s, "100", "", "maximum", "",
670  "{ \"maximum\": {"
671  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
672  " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
673  "}}");
674  INVALIDATE(s, "100.0", "", "maximum", "",
675  "{ \"maximum\": {"
676  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
677  " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100.0"
678  "}}");
679  INVALIDATE(s, "101.5", "", "maximum", "",
680  "{ \"maximum\": {"
681  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
682  " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101.5"
683  "}}");
684 }
685 
686 TEST(SchemaValidator, Number_RangeInt) {
687  Document sd;
688  sd.Parse("{\"type\":\"number\",\"minimum\":-100,\"maximum\":-1,\"exclusiveMaximum\":true}");
689  SchemaDocument s(sd);
690 
691  INVALIDATE(s, "-101", "", "minimum", "",
692  "{ \"minimum\": {"
693  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
694  " \"expected\": -100, \"actual\": -101"
695  "}}");
696  INVALIDATE(s, "-100.1", "", "minimum", "",
697  "{ \"minimum\": {"
698  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
699  " \"expected\": -100, \"actual\": -100.1"
700  "}}");
701  VALIDATE(s, "-100", true);
702  VALIDATE(s, "-2", true);
703  INVALIDATE(s, "-1", "", "maximum", "",
704  "{ \"maximum\": {"
705  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
706  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -1"
707  "}}");
708  INVALIDATE(s, "-0.9", "", "maximum", "",
709  "{ \"maximum\": {"
710  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
711  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -0.9"
712  "}}");
713  INVALIDATE(s, "0", "", "maximum", "",
714  "{ \"maximum\": {"
715  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
716  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 0"
717  "}}");
718  INVALIDATE(s, "2147483647", "", "maximum", "",
719  "{ \"maximum\": {"
720  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
721  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
722  "}}"); // int max
723  INVALIDATE(s, "2147483648", "", "maximum", "",
724  "{ \"maximum\": {"
725  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
726  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
727  "}}"); // unsigned first
728  INVALIDATE(s, "4294967295", "", "maximum", "",
729  "{ \"maximum\": {"
730  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
731  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
732  "}}"); // unsigned max
733  INVALIDATE(s, "9223372036854775808", "", "maximum", "",
734  "{ \"maximum\": {"
735  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
736  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
737  "}}");
738  INVALIDATE(s, "18446744073709551614", "", "maximum", "",
739  "{ \"maximum\": {"
740  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
741  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
742  "}}");
743  INVALIDATE(s, "18446744073709551615", "", "maximum", "",
744  "{ \"maximum\": {"
745  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
746  " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
747  "}}");
748 }
749 
750 TEST(SchemaValidator, Number_RangeDouble) {
751  Document sd;
752  sd.Parse("{\"type\":\"number\",\"minimum\":0.1,\"maximum\":100.1,\"exclusiveMaximum\":true}");
753  SchemaDocument s(sd);
754 
755  INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
756  "{ \"minimum\": {"
757  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
758  " \"expected\": 0.1, \"actual\": -9223372036854775808"
759  "}}");
760  INVALIDATE(s, "-2147483648", "", "minimum", "",
761  "{ \"minimum\": {"
762  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
763  " \"expected\": 0.1, \"actual\": -2147483648"
764  "}}"); // int min
765  INVALIDATE(s, "-1", "", "minimum", "",
766  "{ \"minimum\": {"
767  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
768  " \"expected\": 0.1, \"actual\": -1"
769  "}}");
770  VALIDATE(s, "0.1", true);
771  VALIDATE(s, "10", true);
772  VALIDATE(s, "99", true);
773  VALIDATE(s, "100", true);
774  INVALIDATE(s, "101", "", "maximum", "",
775  "{ \"maximum\": {"
776  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
777  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101"
778  "}}");
779  INVALIDATE(s, "101.5", "", "maximum", "",
780  "{ \"maximum\": {"
781  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
782  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101.5"
783  "}}");
784  INVALIDATE(s, "18446744073709551614", "", "maximum", "",
785  "{ \"maximum\": {"
786  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
787  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
788  "}}");
789  INVALIDATE(s, "18446744073709551615", "", "maximum", "",
790  "{ \"maximum\": {"
791  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
792  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
793  "}}");
794  INVALIDATE(s, "2147483647", "", "maximum", "",
795  "{ \"maximum\": {"
796  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
797  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
798  "}}"); // int max
799  INVALIDATE(s, "2147483648", "", "maximum", "",
800  "{ \"maximum\": {"
801  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
802  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
803  "}}"); // unsigned first
804  INVALIDATE(s, "4294967295", "", "maximum", "",
805  "{ \"maximum\": {"
806  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
807  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
808  "}}"); // unsigned max
809  INVALIDATE(s, "9223372036854775808", "", "maximum", "",
810  "{ \"maximum\": {"
811  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
812  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
813  "}}");
814  INVALIDATE(s, "18446744073709551614", "", "maximum", "",
815  "{ \"maximum\": {"
816  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
817  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
818  "}}");
819  INVALIDATE(s, "18446744073709551615", "", "maximum", "",
820  "{ \"maximum\": {"
821  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
822  " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
823  "}}");
824 }
825 
826 TEST(SchemaValidator, Number_RangeDoubleU64Boundary) {
827  Document sd;
828  sd.Parse("{\"type\":\"number\",\"minimum\":9223372036854775808.0,\"maximum\":18446744073709550000.0}");
829  SchemaDocument s(sd);
830 
831  INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
832  "{ \"minimum\": {"
833  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
834  " \"expected\": 9223372036854775808.0, \"actual\": -9223372036854775808"
835  "}}");
836  INVALIDATE(s, "-2147483648", "", "minimum", "",
837  "{ \"minimum\": {"
838  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
839  " \"expected\": 9223372036854775808.0, \"actual\": -2147483648"
840  "}}"); // int min
841  INVALIDATE(s, "0", "", "minimum", "",
842  "{ \"minimum\": {"
843  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
844  " \"expected\": 9223372036854775808.0, \"actual\": 0"
845  "}}");
846  INVALIDATE(s, "2147483647", "", "minimum", "",
847  "{ \"minimum\": {"
848  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
849  " \"expected\": 9223372036854775808.0, \"actual\": 2147483647"
850  "}}"); // int max
851  INVALIDATE(s, "2147483648", "", "minimum", "",
852  "{ \"minimum\": {"
853  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
854  " \"expected\": 9223372036854775808.0, \"actual\": 2147483648"
855  "}}"); // unsigned first
856  INVALIDATE(s, "4294967295", "", "minimum", "",
857  "{ \"minimum\": {"
858  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
859  " \"expected\": 9223372036854775808.0, \"actual\": 4294967295"
860  "}}"); // unsigned max
861  VALIDATE(s, "9223372036854775808", true);
862  VALIDATE(s, "18446744073709540000", true);
863  INVALIDATE(s, "18446744073709551615", "", "maximum", "",
864  "{ \"maximum\": {"
865  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
866  " \"expected\": 18446744073709550000.0, \"actual\": 18446744073709551615"
867  "}}");
868 }
869 
870 TEST(SchemaValidator, Number_MultipleOf) {
871  Document sd;
872  sd.Parse("{\"type\":\"number\",\"multipleOf\":10.0}");
873  SchemaDocument s(sd);
874 
875  VALIDATE(s, "0", true);
876  VALIDATE(s, "10", true);
877  VALIDATE(s, "-10", true);
878  VALIDATE(s, "20", true);
879  INVALIDATE(s, "23", "", "multipleOf", "",
880  "{ \"multipleOf\": {"
881  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
882  " \"expected\": 10.0, \"actual\": 23"
883  "}}");
884  INVALIDATE(s, "-2147483648", "", "multipleOf", "",
885  "{ \"multipleOf\": {"
886  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
887  " \"expected\": 10.0, \"actual\": -2147483648"
888  "}}"); // int min
889  VALIDATE(s, "-2147483640", true);
890  INVALIDATE(s, "2147483647", "", "multipleOf", "",
891  "{ \"multipleOf\": {"
892  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
893  " \"expected\": 10.0, \"actual\": 2147483647"
894  "}}"); // int max
895  INVALIDATE(s, "2147483648", "", "multipleOf", "",
896  "{ \"multipleOf\": {"
897  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
898  " \"expected\": 10.0, \"actual\": 2147483648"
899  "}}"); // unsigned first
900  VALIDATE(s, "2147483650", true);
901  INVALIDATE(s, "4294967295", "", "multipleOf", "",
902  "{ \"multipleOf\": {"
903  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
904  " \"expected\": 10.0, \"actual\": 4294967295"
905  "}}"); // unsigned max
906  VALIDATE(s, "4294967300", true);
907 }
908 
909 TEST(SchemaValidator, Number_MultipleOfOne) {
910  Document sd;
911  sd.Parse("{\"type\":\"number\",\"multipleOf\":1}");
912  SchemaDocument s(sd);
913 
914  VALIDATE(s, "42", true);
915  VALIDATE(s, "42.0", true);
916  INVALIDATE(s, "3.1415926", "", "multipleOf", "",
917  "{ \"multipleOf\": {"
918  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
919  " \"expected\": 1, \"actual\": 3.1415926"
920  "}}");
921 }
922 
923 TEST(SchemaValidator, Object) {
924  Document sd;
925  sd.Parse("{\"type\":\"object\"}");
926  SchemaDocument s(sd);
927 
928  VALIDATE(s, "{\"key\":\"value\",\"another_key\":\"another_value\"}", true);
929  VALIDATE(s, "{\"Sun\":1.9891e30,\"Jupiter\":1.8986e27,\"Saturn\":5.6846e26,\"Neptune\":10.243e25,\"Uranus\":8.6810e25,\"Earth\":5.9736e24,\"Venus\":4.8685e24,\"Mars\":6.4185e23,\"Mercury\":3.3022e23,\"Moon\":7.349e22,\"Pluto\":1.25e22}", true);
930  INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "",
931  "{ \"type\": {"
932  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
933  " \"expected\": [\"object\"], \"actual\": \"array\""
934  "}}");
935  INVALIDATE(s, "\"Not an object\"", "", "type", "",
936  "{ \"type\": {"
937  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
938  " \"expected\": [\"object\"], \"actual\": \"string\""
939  "}}");
940 }
941 
942 TEST(SchemaValidator, Object_Properties) {
943  Document sd;
944  sd.Parse(
945  "{"
946  " \"type\": \"object\","
947  " \"properties\" : {"
948  " \"number\": { \"type\": \"number\" },"
949  " \"street_name\" : { \"type\": \"string\" },"
950  " \"street_type\" : { \"type\": \"string\", \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"] }"
951  " }"
952  "}");
953 
954  SchemaDocument s(sd);
955 
956  VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
957  INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number",
958  "{ \"type\": {"
959  " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
960  " \"expected\": [\"number\"], \"actual\": \"string\""
961  "}}");
962  INVALIDATE(s, "{ \"number\": \"One\", \"street_name\": \"Microsoft\", \"street_type\": \"Way\" }",
963  "/properties/number", "type", "/number",
964  "{ \"type\": {"
965  " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
966  " \"expected\": [\"number\"], \"actual\": \"string\""
967  "}}"); // fail fast
968  VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\" }", true);
969  VALIDATE(s, "{}", true);
970  VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
971 }
972 
973 TEST(SchemaValidator, Object_AdditionalPropertiesBoolean) {
974  Document sd;
975  sd.Parse(
976  "{"
977  " \"type\": \"object\","
978  " \"properties\" : {"
979  " \"number\": { \"type\": \"number\" },"
980  " \"street_name\" : { \"type\": \"string\" },"
981  " \"street_type\" : { \"type\": \"string\","
982  " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
983  " }"
984  " },"
985  " \"additionalProperties\": false"
986  "}");
987 
988  SchemaDocument s(sd);
989 
990  VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
991  INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction",
992  "{ \"additionalProperties\": {"
993  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
994  " \"disallowed\": \"direction\""
995  "}}");
996 }
997 
998 TEST(SchemaValidator, Object_AdditionalPropertiesObject) {
999  Document sd;
1000  sd.Parse(
1001  "{"
1002  " \"type\": \"object\","
1003  " \"properties\" : {"
1004  " \"number\": { \"type\": \"number\" },"
1005  " \"street_name\" : { \"type\": \"string\" },"
1006  " \"street_type\" : { \"type\": \"string\","
1007  " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
1008  " }"
1009  " },"
1010  " \"additionalProperties\": { \"type\": \"string\" }"
1011  "}");
1012  SchemaDocument s(sd);
1013 
1014  VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
1015  VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
1016  INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number",
1017  "{ \"type\": {"
1018  " \"instanceRef\": \"#/office_number\", \"schemaRef\": \"#/additionalProperties\","
1019  " \"expected\": [\"string\"], \"actual\": \"integer\""
1020  "}}");
1021 }
1022 
1023 TEST(SchemaValidator, Object_Required) {
1024  Document sd;
1025  sd.Parse(
1026  "{"
1027  " \"type\": \"object\","
1028  " \"properties\" : {"
1029  " \"name\": { \"type\": \"string\" },"
1030  " \"email\" : { \"type\": \"string\" },"
1031  " \"address\" : { \"type\": \"string\" },"
1032  " \"telephone\" : { \"type\": \"string\" }"
1033  " },"
1034  " \"required\":[\"name\", \"email\"]"
1035  "}");
1036  SchemaDocument s(sd);
1037 
1038  VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\" }", true);
1039  VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
1040  INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
1041  "{ \"required\": {"
1042  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1043  " \"missing\": [\"email\"]"
1044  "}}");
1045  INVALIDATE(s, "{}", "", "required", "",
1046  "{ \"required\": {"
1047  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1048  " \"missing\": [\"name\", \"email\"]"
1049  "}}");
1050 }
1051 
1052 TEST(SchemaValidator, Object_Required_PassWithDefault) {
1053  Document sd;
1054  sd.Parse(
1055  "{"
1056  " \"type\": \"object\","
1057  " \"properties\" : {"
1058  " \"name\": { \"type\": \"string\", \"default\": \"William Shakespeare\" },"
1059  " \"email\" : { \"type\": \"string\", \"default\": \"\" },"
1060  " \"address\" : { \"type\": \"string\" },"
1061  " \"telephone\" : { \"type\": \"string\" }"
1062  " },"
1063  " \"required\":[\"name\", \"email\"]"
1064  "}");
1065  SchemaDocument s(sd);
1066 
1067  VALIDATE(s, "{ \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
1068  INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
1069  "{ \"required\": {"
1070  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1071  " \"missing\": [\"email\"]"
1072  "}}");
1073  INVALIDATE(s, "{}", "", "required", "",
1074  "{ \"required\": {"
1075  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1076  " \"missing\": [\"email\"]"
1077  "}}");
1078 }
1079 
1080 TEST(SchemaValidator, Object_PropertiesRange) {
1081  Document sd;
1082  sd.Parse("{\"type\":\"object\", \"minProperties\":2, \"maxProperties\":3}");
1083  SchemaDocument s(sd);
1084 
1085  INVALIDATE(s, "{}", "", "minProperties", "",
1086  "{ \"minProperties\": {"
1087  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1088  " \"expected\": 2, \"actual\": 0"
1089  "}}");
1090  INVALIDATE(s, "{\"a\":0}", "", "minProperties", "",
1091  "{ \"minProperties\": {"
1092  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1093  " \"expected\": 2, \"actual\": 1"
1094  "}}");
1095  VALIDATE(s, "{\"a\":0,\"b\":1}", true);
1096  VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2}", true);
1097  INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "",
1098  "{ \"maxProperties\": {"
1099  " \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
1100  " \"expected\": 3, \"actual\": 4"
1101  "}}");
1102 }
1103 
1104 TEST(SchemaValidator, Object_PropertyDependencies) {
1105  Document sd;
1106  sd.Parse(
1107  "{"
1108  " \"type\": \"object\","
1109  " \"properties\": {"
1110  " \"name\": { \"type\": \"string\" },"
1111  " \"credit_card\": { \"type\": \"number\" },"
1112  " \"cvv_code\": { \"type\": \"number\" },"
1113  " \"billing_address\": { \"type\": \"string\" }"
1114  " },"
1115  " \"required\": [\"name\"],"
1116  " \"dependencies\": {"
1117  " \"credit_card\": [\"cvv_code\", \"billing_address\"]"
1118  " }"
1119  "}");
1120  SchemaDocument s(sd);
1121 
1122  VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"cvv_code\": 777, "
1123  "\"billing_address\": \"555 Debtor's Lane\" }", true);
1124  INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "",
1125  "{ \"dependencies\": {"
1126  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1127  " \"errors\": {\"credit_card\": [\"cvv_code\", \"billing_address\"]}"
1128  "}}");
1129  VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
1130  VALIDATE(s, "{ \"name\": \"John Doe\", \"cvv_code\": 777, \"billing_address\": \"555 Debtor's Lane\" }", true);
1131 }
1132 
1133 TEST(SchemaValidator, Object_SchemaDependencies) {
1134  Document sd;
1135  sd.Parse(
1136  "{"
1137  " \"type\": \"object\","
1138  " \"properties\" : {"
1139  " \"name\": { \"type\": \"string\" },"
1140  " \"credit_card\" : { \"type\": \"number\" }"
1141  " },"
1142  " \"required\" : [\"name\"],"
1143  " \"dependencies\" : {"
1144  " \"credit_card\": {"
1145  " \"properties\": {"
1146  " \"billing_address\": { \"type\": \"string\" }"
1147  " },"
1148  " \"required\" : [\"billing_address\"]"
1149  " }"
1150  " }"
1151  "}");
1152  SchemaDocument s(sd);
1153 
1154  VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
1155  INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "",
1156  "{ \"dependencies\": {"
1157  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1158  " \"errors\": {"
1159  " \"credit_card\": {"
1160  " \"required\": {"
1161  " \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\","
1162  " \"missing\": [\"billing_address\"]"
1163  " } } }"
1164  "}}");
1165  VALIDATE(s, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true);
1166 }
1167 
1168 #if RAPIDJSON_SCHEMA_HAS_REGEX
1169 TEST(SchemaValidator, Object_PatternProperties) {
1170  Document sd;
1171  sd.Parse(
1172  "{"
1173  " \"type\": \"object\","
1174  " \"patternProperties\": {"
1175  " \"^S_\": { \"type\": \"string\" },"
1176  " \"^I_\": { \"type\": \"integer\" }"
1177  " }"
1178  "}");
1179  SchemaDocument s(sd);
1180 
1181  VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
1182  VALIDATE(s, "{ \"I_0\": 42 }", true);
1183  INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0",
1184  "{ \"type\": {"
1185  " \"instanceRef\": \"#/S_0\", \"schemaRef\": \"#/patternProperties/%5ES_\","
1186  " \"expected\": [\"string\"], \"actual\": \"integer\""
1187  "}}");
1188  INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42",
1189  "{ \"type\": {"
1190  " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
1191  " \"expected\": [\"integer\"], \"actual\": \"string\""
1192  "}}");
1193  VALIDATE(s, "{ \"keyword\": \"value\" }", true);
1194 }
1195 
1196 TEST(SchemaValidator, Object_PattternProperties_ErrorConflict) {
1197  Document sd;
1198  sd.Parse(
1199  "{"
1200  " \"type\": \"object\","
1201  " \"patternProperties\": {"
1202  " \"^I_\": { \"multipleOf\": 5 },"
1203  " \"30$\": { \"multipleOf\": 6 }"
1204  " }"
1205  "}");
1206  SchemaDocument s(sd);
1207 
1208  VALIDATE(s, "{ \"I_30\": 30 }", true);
1209  INVALIDATE(s, "{ \"I_30\": 7 }", "", "patternProperties", "/I_30",
1210  "{ \"multipleOf\": ["
1211  " {"
1212  " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/%5EI_\","
1213  " \"expected\": 5, \"actual\": 7"
1214  " }, {"
1215  " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/30%24\","
1216  " \"expected\": 6, \"actual\": 7"
1217  " }"
1218  "]}");
1219 }
1220 
1221 TEST(SchemaValidator, Object_Properties_PatternProperties) {
1222  Document sd;
1223  sd.Parse(
1224  "{"
1225  " \"type\": \"object\","
1226  " \"properties\": {"
1227  " \"I_42\": { \"type\": \"integer\", \"minimum\": 73 }"
1228  " },"
1229  " \"patternProperties\": {"
1230  " \"^I_\": { \"type\": \"integer\", \"multipleOf\": 6 }"
1231  " }"
1232  "}");
1233  SchemaDocument s(sd);
1234 
1235  VALIDATE(s, "{ \"I_6\": 6 }", true);
1236  VALIDATE(s, "{ \"I_42\": 78 }", true);
1237  INVALIDATE(s, "{ \"I_42\": 42 }", "", "patternProperties", "/I_42",
1238  "{ \"minimum\": {"
1239  " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
1240  " \"expected\": 73, \"actual\": 42"
1241  "}}");
1242  INVALIDATE(s, "{ \"I_42\": 7 }", "", "patternProperties", "/I_42",
1243  "{ \"minimum\": {"
1244  " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
1245  " \"expected\": 73, \"actual\": 7"
1246  " },"
1247  " \"multipleOf\": {"
1248  " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
1249  " \"expected\": 6, \"actual\": 7"
1250  " }"
1251  "}");
1252 }
1253 
1254 TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
1255  Document sd;
1256  sd.Parse(
1257  "{"
1258  " \"type\": \"object\","
1259  " \"properties\": {"
1260  " \"builtin\": { \"type\": \"number\" }"
1261  " },"
1262  " \"patternProperties\": {"
1263  " \"^S_\": { \"type\": \"string\" },"
1264  " \"^I_\": { \"type\": \"integer\" }"
1265  " },"
1266  " \"additionalProperties\": { \"type\": \"string\" }"
1267  "}");
1268  SchemaDocument s(sd);
1269 
1270  VALIDATE(s, "{ \"builtin\": 42 }", true);
1271  VALIDATE(s, "{ \"keyword\": \"value\" }", true);
1272  INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword",
1273  "{ \"type\": {"
1274  " \"instanceRef\": \"#/keyword\", \"schemaRef\": \"#/additionalProperties\","
1275  " \"expected\": [\"string\"], \"actual\": \"integer\""
1276  "}}");
1277 }
1278 #endif
1279 
1280 TEST(SchemaValidator, Array) {
1281  Document sd;
1282  sd.Parse("{\"type\":\"array\"}");
1283  SchemaDocument s(sd);
1284 
1285  VALIDATE(s, "[1, 2, 3, 4, 5]", true);
1286  VALIDATE(s, "[3, \"different\", { \"types\" : \"of values\" }]", true);
1287  INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "",
1288  "{ \"type\": {"
1289  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1290  " \"expected\": [\"array\"], \"actual\": \"object\""
1291  "}}");
1292 }
1293 
1294 TEST(SchemaValidator, Array_ItemsList) {
1295  Document sd;
1296  sd.Parse(
1297  "{"
1298  " \"type\": \"array\","
1299  " \"items\" : {"
1300  " \"type\": \"number\""
1301  " }"
1302  "}");
1303  SchemaDocument s(sd);
1304 
1305  VALIDATE(s, "[1, 2, 3, 4, 5]", true);
1306  INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2",
1307  "{ \"type\": {"
1308  " \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items\","
1309  " \"expected\": [\"number\"], \"actual\": \"string\""
1310  "}}");
1311  VALIDATE(s, "[]", true);
1312 }
1313 
1314 TEST(SchemaValidator, Array_ItemsTuple) {
1315  Document sd;
1316  sd.Parse(
1317  "{"
1318  " \"type\": \"array\","
1319  " \"items\": ["
1320  " {"
1321  " \"type\": \"number\""
1322  " },"
1323  " {"
1324  " \"type\": \"string\""
1325  " },"
1326  " {"
1327  " \"type\": \"string\","
1328  " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
1329  " },"
1330  " {"
1331  " \"type\": \"string\","
1332  " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
1333  " }"
1334  " ]"
1335  "}");
1336  SchemaDocument s(sd);
1337 
1338  VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
1339  INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2",
1340  "{ \"enum\": { \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items/2\" }}");
1341  INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0",
1342  "{ \"type\": {"
1343  " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
1344  " \"expected\": [\"number\"], \"actual\": \"string\""
1345  "}}");
1346  INVALIDATE(s, "[\"Twenty-four\", \"Sussex\", \"Drive\"]", "/items/0", "type", "/0",
1347  "{ \"type\": {"
1348  " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
1349  " \"expected\": [\"number\"], \"actual\": \"string\""
1350  "}}"); // fail fast
1351  VALIDATE(s, "[10, \"Downing\", \"Street\"]", true);
1352  VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true);
1353 }
1354 
1355 TEST(SchemaValidator, Array_AdditionalItmes) {
1356  Document sd;
1357  sd.Parse(
1358  "{"
1359  " \"type\": \"array\","
1360  " \"items\": ["
1361  " {"
1362  " \"type\": \"number\""
1363  " },"
1364  " {"
1365  " \"type\": \"string\""
1366  " },"
1367  " {"
1368  " \"type\": \"string\","
1369  " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
1370  " },"
1371  " {"
1372  " \"type\": \"string\","
1373  " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
1374  " }"
1375  " ],"
1376  " \"additionalItems\": false"
1377  "}");
1378  SchemaDocument s(sd);
1379 
1380  VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
1381  VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\"]", true);
1382  INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4",
1383  "{ \"additionalItems\": {"
1384  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1385  " \"disallowed\": 4"
1386  "}}");
1387 }
1388 
1389 TEST(SchemaValidator, Array_ItemsRange) {
1390  Document sd;
1391  sd.Parse("{\"type\": \"array\",\"minItems\": 2,\"maxItems\" : 3}");
1392  SchemaDocument s(sd);
1393 
1394  INVALIDATE(s, "[]", "", "minItems", "",
1395  "{ \"minItems\": {"
1396  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1397  " \"expected\": 2, \"actual\": 0"
1398  "}}");
1399  INVALIDATE(s, "[1]", "", "minItems", "",
1400  "{ \"minItems\": {"
1401  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1402  " \"expected\": 2, \"actual\": 1"
1403  "}}");
1404  VALIDATE(s, "[1, 2]", true);
1405  VALIDATE(s, "[1, 2, 3]", true);
1406  INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "",
1407  "{ \"maxItems\": {"
1408  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1409  " \"expected\": 3, \"actual\": 4"
1410  "}}");
1411 }
1412 
1413 TEST(SchemaValidator, Array_UniqueItems) {
1414  Document sd;
1415  sd.Parse("{\"type\": \"array\", \"uniqueItems\": true}");
1416  SchemaDocument s(sd);
1417 
1418  VALIDATE(s, "[1, 2, 3, 4, 5]", true);
1419  INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3",
1420  "{ \"uniqueItems\": {"
1421  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1422  " \"duplicates\": [2, 3]"
1423  "}}");
1424  INVALIDATE(s, "[1, 2, 3, 3, 3]", "", "uniqueItems", "/3",
1425  "{ \"uniqueItems\": {"
1426  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1427  " \"duplicates\": [2, 3]"
1428  "}}"); // fail fast
1429  VALIDATE(s, "[]", true);
1430 }
1431 
1432 TEST(SchemaValidator, Boolean) {
1433  Document sd;
1434  sd.Parse("{\"type\":\"boolean\"}");
1435  SchemaDocument s(sd);
1436 
1437  VALIDATE(s, "true", true);
1438  VALIDATE(s, "false", true);
1439  INVALIDATE(s, "\"true\"", "", "type", "",
1440  "{ \"type\": {"
1441  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1442  " \"expected\": [\"boolean\"], \"actual\": \"string\""
1443  "}}");
1444  INVALIDATE(s, "0", "", "type", "",
1445  "{ \"type\": {"
1446  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1447  " \"expected\": [\"boolean\"], \"actual\": \"integer\""
1448  "}}");
1449 }
1450 
1451 TEST(SchemaValidator, Null) {
1452  Document sd;
1453  sd.Parse("{\"type\":\"null\"}");
1454  SchemaDocument s(sd);
1455 
1456  VALIDATE(s, "null", true);
1457  INVALIDATE(s, "false", "", "type", "",
1458  "{ \"type\": {"
1459  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1460  " \"expected\": [\"null\"], \"actual\": \"boolean\""
1461  "}}");
1462  INVALIDATE(s, "0", "", "type", "",
1463  "{ \"type\": {"
1464  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1465  " \"expected\": [\"null\"], \"actual\": \"integer\""
1466  "}}");
1467  INVALIDATE(s, "\"\"", "", "type", "",
1468  "{ \"type\": {"
1469  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1470  " \"expected\": [\"null\"], \"actual\": \"string\""
1471  "}}");
1472 }
1473 
1474 // Additional tests
1475 
1476 TEST(SchemaValidator, ObjectInArray) {
1477  Document sd;
1478  sd.Parse("{\"type\":\"array\", \"items\": { \"type\":\"string\" }}");
1479  SchemaDocument s(sd);
1480 
1481  VALIDATE(s, "[\"a\"]", true);
1482  INVALIDATE(s, "[1]", "/items", "type", "/0",
1483  "{ \"type\": {"
1484  " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
1485  " \"expected\": [\"string\"], \"actual\": \"integer\""
1486  "}}");
1487  INVALIDATE(s, "[{}]", "/items", "type", "/0",
1488  "{ \"type\": {"
1489  " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
1490  " \"expected\": [\"string\"], \"actual\": \"object\""
1491  "}}");
1492 }
1493 
1494 TEST(SchemaValidator, MultiTypeInObject) {
1495  Document sd;
1496  sd.Parse(
1497  "{"
1498  " \"type\":\"object\","
1499  " \"properties\": {"
1500  " \"tel\" : {"
1501  " \"type\":[\"integer\", \"string\"]"
1502  " }"
1503  " }"
1504  "}");
1505  SchemaDocument s(sd);
1506 
1507  VALIDATE(s, "{ \"tel\": 999 }", true);
1508  VALIDATE(s, "{ \"tel\": \"123-456\" }", true);
1509  INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel",
1510  "{ \"type\": {"
1511  " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
1512  " \"expected\": [\"string\", \"integer\"], \"actual\": \"boolean\""
1513  "}}");
1514 }
1515 
1516 TEST(SchemaValidator, MultiTypeWithObject) {
1517  Document sd;
1518  sd.Parse(
1519  "{"
1520  " \"type\": [\"object\",\"string\"],"
1521  " \"properties\": {"
1522  " \"tel\" : {"
1523  " \"type\": \"integer\""
1524  " }"
1525  " }"
1526  "}");
1527  SchemaDocument s(sd);
1528 
1529  VALIDATE(s, "\"Hello\"", true);
1530  VALIDATE(s, "{ \"tel\": 999 }", true);
1531  INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel",
1532  "{ \"type\": {"
1533  " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
1534  " \"expected\": [\"integer\"], \"actual\": \"string\""
1535  "}}");
1536 }
1537 
1538 TEST(SchemaValidator, AllOf_Nested) {
1539  Document sd;
1540  sd.Parse(
1541  "{"
1542  " \"allOf\": ["
1543  " { \"type\": \"string\", \"minLength\": 2 },"
1544  " { \"type\": \"string\", \"maxLength\": 5 },"
1545  " { \"allOf\": [ { \"enum\" : [\"ok\", \"okay\", \"OK\", \"o\"] }, { \"enum\" : [\"ok\", \"OK\", \"o\"]} ] }"
1546  " ]"
1547  "}");
1548  SchemaDocument s(sd);
1549 
1550  VALIDATE(s, "\"ok\"", true);
1551  VALIDATE(s, "\"OK\"", true);
1552  INVALIDATE(s, "\"okay\"", "", "allOf", "",
1553  "{ \"enum\": {"
1554  " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\""
1555  "}}");
1556  INVALIDATE(s, "\"o\"", "", "allOf", "",
1557  "{ \"minLength\": {"
1558  " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
1559  " \"expected\": 2, \"actual\": \"o\""
1560  "}}");
1561  INVALIDATE(s, "\"n\"", "", "allOf", "",
1562  "{ \"minLength\": {"
1563  " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
1564  " \"expected\": 2, \"actual\": \"n\""
1565  " },"
1566  " \"enum\": ["
1567  " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
1568  " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
1569  " ]"
1570  "}")
1571  INVALIDATE(s, "\"too long\"", "", "allOf", "",
1572  "{ \"maxLength\": {"
1573  " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\","
1574  " \"expected\": 5, \"actual\": \"too long\""
1575  " },"
1576  " \"enum\": ["
1577  " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
1578  " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
1579  " ]"
1580  "}");
1581  INVALIDATE(s, "123", "", "allOf", "",
1582  "{ \"type\": ["
1583  " { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\","
1584  " \"expected\": [\"string\"], \"actual\": \"integer\""
1585  " },"
1586  " { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\","
1587  " \"expected\": [\"string\"], \"actual\": \"integer\""
1588  " }"
1589  " ],"
1590  " \"enum\": ["
1591  " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"},"
1592  " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}"
1593  " ]"
1594  "}");
1595 }
1596 
1597 TEST(SchemaValidator, EscapedPointer) {
1598  Document sd;
1599  sd.Parse(
1600  "{"
1601  " \"type\": \"object\","
1602  " \"properties\": {"
1603  " \"~/\": { \"type\": \"number\" }"
1604  " }"
1605  "}");
1606  SchemaDocument s(sd);
1607  INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1",
1608  "{ \"type\": {"
1609  " \"instanceRef\": \"#/~0~1\", \"schemaRef\": \"#/properties/~0~1\","
1610  " \"expected\": [\"number\"], \"actual\": \"boolean\""
1611  "}}");
1612 }
1613 
1614 template <typename Allocator>
1615 static char* ReadFile(const char* filename, Allocator& allocator) {
1616  const char *paths[] = {
1617  "",
1618  "bin/",
1619  "../bin/",
1620  "../../bin/",
1621  "../../../bin/"
1622  };
1623  char buffer[1024];
1624  FILE *fp = 0;
1625  for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
1626  sprintf(buffer, "%s%s", paths[i], filename);
1627  fp = fopen(buffer, "rb");
1628  if (fp)
1629  break;
1630  }
1631 
1632  if (!fp)
1633  return 0;
1634 
1635  fseek(fp, 0, SEEK_END);
1636  size_t length = static_cast<size_t>(ftell(fp));
1637  fseek(fp, 0, SEEK_SET);
1638  char* json = reinterpret_cast<char*>(allocator.Malloc(length + 1));
1639  size_t readLength = fread(json, 1, length, fp);
1640  json[readLength] = '\0';
1641  fclose(fp);
1642  return json;
1643 }
1644 
1645 TEST(SchemaValidator, ValidateMetaSchema) {
1646  CrtAllocator allocator;
1647  char* json = ReadFile("draft-04/schema", allocator);
1648  Document d;
1649  d.Parse(json);
1651  SchemaDocument sd(d);
1652  SchemaValidator validator(sd);
1653  if (!d.Accept(validator)) {
1654  StringBuffer sb;
1655  validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
1656  printf("Invalid schema: %s\n", sb.GetString());
1657  printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
1658  sb.Clear();
1659  validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
1660  printf("Invalid document: %s\n", sb.GetString());
1661  sb.Clear();
1662  Writer<StringBuffer> w(sb);
1663  validator.GetError().Accept(w);
1664  printf("Validation error: %s\n", sb.GetString());
1665  ADD_FAILURE();
1666  }
1668 }
1669 
1670 TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
1671  typedef GenericDocument<UTF16<> > D;
1673  typedef GenericSchemaValidator<SD> SV;
1674 
1675  CrtAllocator allocator;
1676  char* json = ReadFile("draft-04/schema", allocator);
1677 
1678  D d;
1679  StringStream ss(json);
1680  d.ParseStream<0, UTF8<> >(ss);
1681  ASSERT_FALSE(d.HasParseError());
1682  SD sd(d);
1683  SV validator(sd);
1684  if (!d.Accept(validator)) {
1686  validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
1687  wprintf(L"Invalid schema: %ls\n", sb.GetString());
1688  wprintf(L"Invalid keyword: %ls\n", validator.GetInvalidSchemaKeyword());
1689  sb.Clear();
1690  validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
1691  wprintf(L"Invalid document: %ls\n", sb.GetString());
1692  sb.Clear();
1694  validator.GetError().Accept(w);
1695  printf("Validation error: %ls\n", sb.GetString());
1696  ADD_FAILURE();
1697  }
1699 }
1700 
1701 template <typename SchemaDocumentType = SchemaDocument>
1702 class RemoteSchemaDocumentProvider : public IGenericRemoteSchemaDocumentProvider<SchemaDocumentType> {
1703 public:
1704  RemoteSchemaDocumentProvider() :
1705  documentAllocator_(documentBuffer_, sizeof(documentBuffer_)),
1706  schemaAllocator_(schemaBuffer_, sizeof(schemaBuffer_))
1707  {
1708  const char* filenames[kCount] = {
1709  "jsonschema/remotes/integer.json",
1710  "jsonschema/remotes/subSchemas.json",
1711  "jsonschema/remotes/folder/folderInteger.json",
1712  "draft-04/schema"
1713  };
1714  const char* uris[kCount] = {
1715  "http://localhost:1234/integer.json",
1716  "http://localhost:1234/subSchemas.json",
1717  "http://localhost:1234/folder/folderInteger.json",
1718  "http://json-schema.org/draft-04/schema"
1719  };
1720 
1721  for (size_t i = 0; i < kCount; i++) {
1722  sd_[i] = 0;
1723 
1724  char jsonBuffer[8192];
1725  MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
1726  char* json = ReadFile(filenames[i], jsonAllocator);
1727  if (!json) {
1728  printf("json remote file %s not found", filenames[i]);
1729  ADD_FAILURE();
1730  }
1731  else {
1732  char stackBuffer[4096];
1733  MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer));
1734  DocumentType d(&documentAllocator_, 1024, &stackAllocator);
1735  d.Parse(json);
1736  sd_[i] = new SchemaDocumentType(d, uris[i], static_cast<SizeType>(strlen(uris[i])), 0, &schemaAllocator_);
1738  }
1739  };
1740  }
1741 
1742  ~RemoteSchemaDocumentProvider() {
1743  for (size_t i = 0; i < kCount; i++)
1744  delete sd_[i];
1745  }
1746 
1747  virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) {
1748  for (size_t i = 0; i < kCount; i++)
1749  if (typename SchemaDocumentType::URIType(uri, length) == sd_[i]->GetURI())
1750  return sd_[i];
1751  return 0;
1752  }
1753 
1754 private:
1756 
1757  RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider&);
1758  RemoteSchemaDocumentProvider& operator=(const RemoteSchemaDocumentProvider&);
1759 
1760  static const size_t kCount = 4;
1761  SchemaDocumentType* sd_[kCount];
1762  typename DocumentType::AllocatorType documentAllocator_;
1763  typename SchemaDocumentType::AllocatorType schemaAllocator_;
1764  char documentBuffer_[16384];
1765  char schemaBuffer_[128 * 1024];
1766 };
1767 
1768 TEST(SchemaValidator, TestSuite) {
1769  const char* filenames[] = {
1770  "additionalItems.json",
1771  "additionalProperties.json",
1772  "allOf.json",
1773  "anyOf.json",
1774  "default.json",
1775  "definitions.json",
1776  "dependencies.json",
1777  "enum.json",
1778  "items.json",
1779  "maximum.json",
1780  "maxItems.json",
1781  "maxLength.json",
1782  "maxProperties.json",
1783  "minimum.json",
1784  "minItems.json",
1785  "minLength.json",
1786  "minProperties.json",
1787  "multipleOf.json",
1788  "not.json",
1789  "oneOf.json",
1790  "pattern.json",
1791  "patternProperties.json",
1792  "properties.json",
1793  "ref.json",
1794  "refRemote.json",
1795  "required.json",
1796  "type.json",
1797  "uniqueItems.json"
1798  };
1799 
1800  const char* onlyRunDescription = 0;
1801  //const char* onlyRunDescription = "a string is a string";
1802 
1803  unsigned testCount = 0;
1804  unsigned passCount = 0;
1805 
1806  typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
1807  RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
1808 
1809  char jsonBuffer[65536];
1810  char documentBuffer[65536];
1811  char documentStackBuffer[65536];
1812  char schemaBuffer[65536];
1813  char validatorBuffer[65536];
1814  MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
1815  MemoryPoolAllocator<> documentAllocator(documentBuffer, sizeof(documentBuffer));
1816  MemoryPoolAllocator<> documentStackAllocator(documentStackBuffer, sizeof(documentStackBuffer));
1817  MemoryPoolAllocator<> schemaAllocator(schemaBuffer, sizeof(schemaBuffer));
1818  MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
1819 
1820  for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
1821  char filename[FILENAME_MAX];
1822  sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
1823  char* json = ReadFile(filename, jsonAllocator);
1824  if (!json) {
1825  printf("json test suite file %s not found", filename);
1826  ADD_FAILURE();
1827  }
1828  else {
1829  GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > d(&documentAllocator, 1024, &documentStackAllocator);
1830  d.Parse(json);
1831  if (d.HasParseError()) {
1832  printf("json test suite file %s has parse error", filename);
1833  ADD_FAILURE();
1834  }
1835  else {
1836  for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
1837  {
1838  SchemaDocumentType schema((*schemaItr)["schema"], filenames[i], static_cast<SizeType>(strlen(filenames[i])), &provider, &schemaAllocator);
1840  const char* description1 = (*schemaItr)["description"].GetString();
1841  const Value& tests = (*schemaItr)["tests"];
1842  for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
1843  const char* description2 = (*testItr)["description"].GetString();
1844  if (!onlyRunDescription || strcmp(description2, onlyRunDescription) == 0) {
1845  const Value& data = (*testItr)["data"];
1846  bool expected = (*testItr)["valid"].GetBool();
1847  testCount++;
1848  validator.Reset();
1849  bool actual = data.Accept(validator);
1850  if (expected != actual)
1851  printf("Fail: %30s \"%s\" \"%s\"\n", filename, description1, description2);
1852  else
1853  passCount++;
1854  }
1855  }
1856  //printf("%zu %zu %zu\n", documentAllocator.Size(), schemaAllocator.Size(), validatorAllocator.Size());
1857  }
1858  schemaAllocator.Clear();
1859  validatorAllocator.Clear();
1860  }
1861  }
1862  }
1863  documentAllocator.Clear();
1865  jsonAllocator.Clear();
1866  }
1867  printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount);
1868  // if (passCount != testCount)
1869  // ADD_FAILURE();
1870 }
1871 
1872 TEST(SchemaValidatingReader, Simple) {
1873  Document sd;
1874  sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
1875  SchemaDocument s(sd);
1876 
1877  Document d;
1878  StringStream ss("\"red\"");
1880  d.Populate(reader);
1881  EXPECT_TRUE(reader.GetParseResult());
1882  EXPECT_TRUE(reader.IsValid());
1883  EXPECT_TRUE(d.IsString());
1884  EXPECT_STREQ("red", d.GetString());
1885 }
1886 
1887 TEST(SchemaValidatingReader, Invalid) {
1888  Document sd;
1889  sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
1890  SchemaDocument s(sd);
1891 
1892  Document d;
1893  StringStream ss("\"ABCD\"");
1895  d.Populate(reader);
1896  EXPECT_FALSE(reader.GetParseResult());
1897  EXPECT_FALSE(reader.IsValid());
1898  EXPECT_EQ(kParseErrorTermination, reader.GetParseResult().Code());
1899  EXPECT_STREQ("maxLength", reader.GetInvalidSchemaKeyword());
1900  EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
1901  EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
1902  EXPECT_TRUE(d.IsNull());
1903  Document e;
1904  e.Parse(
1905  "{ \"maxLength\": {"
1906  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1907  " \"expected\": 3, \"actual\": \"ABCD\""
1908  "}}");
1909  if (e != reader.GetError()) {
1910  ADD_FAILURE();
1911  }
1912 }
1913 
1914 TEST(SchemaValidatingWriter, Simple) {
1915  Document sd;
1916  sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
1917  SchemaDocument s(sd);
1918 
1919  Document d;
1920  StringBuffer sb;
1921  Writer<StringBuffer> writer(sb);
1923 
1924  d.Parse("\"red\"");
1925  EXPECT_TRUE(d.Accept(validator));
1926  EXPECT_TRUE(validator.IsValid());
1927  EXPECT_STREQ("\"red\"", sb.GetString());
1928 
1929  sb.Clear();
1930  validator.Reset();
1931  d.Parse("\"ABCD\"");
1932  EXPECT_FALSE(d.Accept(validator));
1933  EXPECT_FALSE(validator.IsValid());
1934  EXPECT_TRUE(validator.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
1935  EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
1936  Document e;
1937  e.Parse(
1938  "{ \"maxLength\": {"
1939  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1940  " \"expected\": 3, \"actual\": \"ABCD\""
1941  "}}");
1942  EXPECT_EQ(e, validator.GetError());
1943 }
1944 
1945 TEST(Schema, Issue848) {
1948  rapidjson::GenericSchemaValidator<rapidjson::SchemaDocument, rapidjson::Document> v(s);
1949 }
1950 
1951 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1952 
1953 static SchemaDocument ReturnSchemaDocument() {
1954  Document sd;
1955  sd.Parse("{ \"type\": [\"number\", \"string\"] }");
1956  SchemaDocument s(sd);
1957  return s;
1958 }
1959 
1960 TEST(Schema, Issue552) {
1961  SchemaDocument s = ReturnSchemaDocument();
1962  VALIDATE(s, "42", true);
1963  VALIDATE(s, "\"Life, the universe, and everything\"", true);
1964  INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
1965  "{ \"type\": {"
1966  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1967  " \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
1968  "}}");
1969 }
1970 
1971 #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
1972 
1973 TEST(SchemaValidator, Issue608) {
1974  Document sd;
1975  sd.Parse("{\"required\": [\"a\", \"b\"] }");
1976  SchemaDocument s(sd);
1977 
1978  VALIDATE(s, "{\"a\" : null, \"b\": null}", true);
1979  INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "",
1980  "{ \"required\": {"
1981  " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
1982  " \"missing\": [\"b\"]"
1983  "}}");
1984 }
1985 
1986 // Fail to resolve $ref in allOf causes crash in SchemaValidator::StartObject()
1987 TEST(SchemaValidator, Issue728_AllOfRef) {
1988  Document sd;
1989  sd.Parse("{\"allOf\": [{\"$ref\": \"#/abc\"}]}");
1990  SchemaDocument s(sd);
1991  VALIDATE(s, "{\"key1\": \"abc\", \"key2\": \"def\"}", true);
1992 }
1993 
1994 TEST(SchemaValidator, Issue825) {
1995  Document sd;
1996  sd.Parse("{\"type\": \"object\", \"additionalProperties\": false, \"patternProperties\": {\"^i\": { \"type\": \"string\" } } }");
1997  SchemaDocument s(sd);
1998  VALIDATE(s, "{ \"item\": \"hello\" }", true);
1999 }
2000 
2001 TEST(SchemaValidator, Issue1017_allOfHandler) {
2002  Document sd;
2003  sd.Parse("{\"allOf\": [{\"type\": \"object\",\"properties\": {\"cyanArray2\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}}},{\"type\": \"object\",\"properties\": {\"blackArray\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}},\"required\": [ \"blackArray\" ]}]}");
2004  SchemaDocument s(sd);
2005  StringBuffer sb;
2006  Writer<StringBuffer> writer(sb);
2008  EXPECT_TRUE(validator.StartObject());
2009  EXPECT_TRUE(validator.Key("cyanArray2", 10, false));
2010  EXPECT_TRUE(validator.StartArray());
2011  EXPECT_TRUE(validator.EndArray(0));
2012  EXPECT_TRUE(validator.Key("blackArray", 10, false));
2013  EXPECT_TRUE(validator.StartArray());
2014  EXPECT_TRUE(validator.EndArray(0));
2015  EXPECT_TRUE(validator.EndObject(0));
2016  EXPECT_TRUE(validator.IsValid());
2017  EXPECT_STREQ("{\"cyanArray2\":[],\"blackArray\":[]}", sb.GetString());
2018 }
2019 
2020 TEST(SchemaValidator, Ref_remote) {
2021  typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
2022  RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
2023  Document sd;
2024  sd.Parse("{\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}");
2025  SchemaDocumentType s(sd, 0, 0, &provider);
2027  typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
2028  INVALIDATE_(s, "null", "/integer", "type", "",
2029  "{ \"type\": {"
2030  " \"instanceRef\": \"#\","
2031  " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
2032  " \"expected\": [\"integer\"], \"actual\": \"null\""
2033  "}}",
2034  SchemaValidatorType, PointerType);
2035 }
2036 
2037 TEST(SchemaValidator, Ref_remote_issue1210) {
2038  class SchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
2039  SchemaDocument** collection;
2040 
2041  SchemaDocumentProvider(const SchemaDocumentProvider&);
2042  SchemaDocumentProvider& operator=(const SchemaDocumentProvider&);
2043 
2044  public:
2045  SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { }
2046  virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
2047  int i = 0;
2048  while (collection[i] && SchemaDocument::URIType(uri, length) != collection[i]->GetURI()) ++i;
2049  return collection[i];
2050  }
2051  };
2052  SchemaDocument* collection[] = { 0, 0, 0 };
2053  SchemaDocumentProvider provider(collection);
2054 
2055  Document x, y, z;
2056  x.Parse("{\"properties\":{\"country\":{\"$ref\":\"y.json#/definitions/country_remote\"}},\"type\":\"object\"}");
2057  y.Parse("{\"definitions\":{\"country_remote\":{\"$ref\":\"z.json#/definitions/country_list\"}}}");
2058  z.Parse("{\"definitions\":{\"country_list\":{\"enum\":[\"US\"]}}}");
2059 
2060  SchemaDocument sz(z, "z.json", 6, &provider);
2061  collection[0] = &sz;
2062  SchemaDocument sy(y, "y.json", 6, &provider);
2063  collection[1] = &sy;
2064  SchemaDocument sx(x, "x.json", 6, &provider);
2065 
2066  VALIDATE(sx, "{\"country\":\"UK\"}", false);
2067  VALIDATE(sx, "{\"country\":\"US\"}", true);
2068 }
2069 
2070 #if defined(_MSC_VER) || defined(__clang__)
2071 RAPIDJSON_DIAG_POP
2072 #endif
#define ADD_FAILURE()
Definition: gtest.h:1808
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:389
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define EXPECT_STREQ(s1, s2)
Definition: gtest.h:1995
static void Free(void *ptr)
Frees a memory block (concept Allocator)
Definition: allocators.h:238
C-runtime library allocator.
Definition: allocators.h:75
TEST(SchemaValidator, Hasher)
Definition: schematest.cpp:46
internal::AnyOfResult2< M1, M2 >::type AnyOf(M1 m1, M2 m2)
Represents a JSON value. Use Value for UTF8 encoding and default allocator.
Definition: document.h:57
JSON writer.
Definition: fwd.h:95
A helper class for parsing with validation.
Definition: schema.h:2435
#define VALIDATE(schema, json, expected)
JSON Schema Validator.
Definition: fwd.h:145
#define ASSERT_FALSE(condition)
Definition: gtest.h:1868
GenericDocument & Populate(Generator &g)
Populate this document by a generator which produces SAX events.
Definition: document.h:2245
bool HasParseError() const
Whether a parse error has occurred in the last parsing.
Definition: document.h:2394
Read-only string stream.
Definition: fwd.h:47
GenericDocument< UTF8<> > Document
GenericDocument with UTF8 encoding.
Definition: document.h:2512
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition: fwd.h:126
#define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error)
main RapidJSON namespace
#define TEST_HASHER(json1, json2, expected)
Definition: schematest.cpp:30
GenericDocument & Parse(const typename SourceEncoding::Ch *str)
Parse JSON text from a read-only string (with Encoding conversion)
Definition: document.h:2331
#define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, SchemaValidatorType, PointerType)
JSON schema document.
Definition: fwd.h:136
static void Free(void *ptr)
Definition: allocators.h:92
GenericPointer< ValueType, Allocator > PointerType
Definition: schema.h:1507
const Ch * GetString() const
Definition: stringbuffer.h:73
UTF-16 encoding.
Definition: encodings.h:269
Parsing was terminated.
Definition: error.h:88
connection< TProtocol > & operator=(const connection< TProtocol > &obj)
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
Concept for allocating, resizing and freeing memory block.
GenericSchemaDocument< Value, CrtAllocator > SchemaDocument
Definition: fwd.h:136
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
rapidjson::Document json
Definition: transport.cpp:49
internal::RefMatcher< T & > Ref(T &x)
UTF-8 encoding.
Definition: encodings.h:96
internal::AllOfResult2< M1, M2 >::type AllOf(M1 m1, M2 m2)