1 // Tencent is pleased to support the open source community by making RapidJSON available.
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
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
8 // http://opensource.org/licenses/MIT
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.
16 #include "rapidjson/schema.h"
17 #include "rapidjson/stringbuffer.h"
18 #include "rapidjson/writer.h"
22 RAPIDJSON_DIAG_OFF(variadic
-macros
)
25 using namespace rapidjson
;
27 #define TEST_HASHER(json1, json2, expected) \
31 ASSERT_FALSE(d1.HasParseError());\
33 ASSERT_FALSE(d2.HasParseError());\
34 internal::Hasher<Value, CrtAllocator> h1, h2;\
37 ASSERT_TRUE(h1.IsValid());\
38 ASSERT_TRUE(h2.IsValid());\
39 /*printf("%s: 0x%016llx\n%s: 0x%016llx\n\n", json1, h1.GetHashCode(), json2, h2.GetHashCode());*/\
40 EXPECT_TRUE(expected == (h1.GetHashCode() == h2.GetHashCode()));\
43 TEST(SchemaValidator
, Hasher
) {
44 TEST_HASHER("null", "null", true);
46 TEST_HASHER("true", "true", true);
47 TEST_HASHER("false", "false", true);
48 TEST_HASHER("true", "false", false);
49 TEST_HASHER("false", "true", false);
50 TEST_HASHER("true", "null", false);
51 TEST_HASHER("false", "null", false);
53 TEST_HASHER("1", "1", true);
54 TEST_HASHER("2147483648", "2147483648", true); // 2^31 can only be fit in unsigned
55 TEST_HASHER("-2147483649", "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
56 TEST_HASHER("2147483648", "2147483648", true); // 2^31 can only be fit in unsigned
57 TEST_HASHER("4294967296", "4294967296", true); // 2^32 can only be fit in int64_t
58 TEST_HASHER("9223372036854775808", "9223372036854775808", true); // 2^63 can only be fit in uint64_t
59 TEST_HASHER("1.5", "1.5", true);
60 TEST_HASHER("1", "1.0", true);
61 TEST_HASHER("1", "-1", false);
62 TEST_HASHER("0.0", "-0.0", false);
63 TEST_HASHER("1", "true", false);
64 TEST_HASHER("0", "false", false);
65 TEST_HASHER("0", "null", false);
67 TEST_HASHER("\"\"", "\"\"", true);
68 TEST_HASHER("\"\"", "\"\\u0000\"", false);
69 TEST_HASHER("\"Hello\"", "\"Hello\"", true);
70 TEST_HASHER("\"Hello\"", "\"World\"", false);
71 TEST_HASHER("\"Hello\"", "null", false);
72 TEST_HASHER("\"Hello\\u0000\"", "\"Hello\"", false);
73 TEST_HASHER("\"\"", "null", false);
74 TEST_HASHER("\"\"", "true", false);
75 TEST_HASHER("\"\"", "false", false);
77 TEST_HASHER("[]", "[ ]", true);
78 TEST_HASHER("[1, true, false]", "[1, true, false]", true);
79 TEST_HASHER("[1, true, false]", "[1, true]", false);
80 TEST_HASHER("[1, 2]", "[2, 1]", false);
81 TEST_HASHER("[[1], 2]", "[[1, 2]]", false);
82 TEST_HASHER("[1, 2]", "[1, [2]]", false);
83 TEST_HASHER("[]", "null", false);
84 TEST_HASHER("[]", "true", false);
85 TEST_HASHER("[]", "false", false);
86 TEST_HASHER("[]", "0", false);
87 TEST_HASHER("[]", "0.0", false);
88 TEST_HASHER("[]", "\"\"", false);
90 TEST_HASHER("{}", "{ }", true);
91 TEST_HASHER("{\"a\":1}", "{\"a\":1}", true);
92 TEST_HASHER("{\"a\":1}", "{\"b\":1}", false);
93 TEST_HASHER("{\"a\":1}", "{\"a\":2}", false);
94 TEST_HASHER("{\"a\":1, \"b\":2}", "{\"b\":2, \"a\":1}", true); // Member order insensitive
95 TEST_HASHER("{}", "null", false);
96 TEST_HASHER("{}", "false", false);
97 TEST_HASHER("{}", "true", false);
98 TEST_HASHER("{}", "0", false);
99 TEST_HASHER("{}", "0.0", false);
100 TEST_HASHER("{}", "\"\"", false);
103 // Test cases following http://spacetelescope.github.io/understanding-json-schema
105 #define VALIDATE(schema, json, expected) \
107 SchemaValidator validator(schema);\
109 /*printf("\n%s\n", json);*/\
111 EXPECT_FALSE(d.HasParseError());\
112 EXPECT_TRUE(expected == d.Accept(validator));\
113 EXPECT_TRUE(expected == validator.IsValid());\
114 if ((expected) && !validator.IsValid()) {\
116 validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\
117 printf("Invalid schema: %s\n", sb.GetString());\
118 printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());\
120 validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\
121 printf("Invalid document: %s\n", sb.GetString());\
125 #define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer) \
127 SchemaValidator validator(schema);\
129 /*printf("\n%s\n", json);*/\
131 EXPECT_FALSE(d.HasParseError());\
132 EXPECT_FALSE(d.Accept(validator));\
133 EXPECT_FALSE(validator.IsValid());\
134 if (validator.GetInvalidSchemaPointer() != Pointer(invalidSchemaPointer)) {\
136 validator.GetInvalidSchemaPointer().Stringify(sb);\
137 printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\
140 ASSERT_TRUE(validator.GetInvalidSchemaKeyword() != 0);\
141 if (strcmp(validator.GetInvalidSchemaKeyword(), invalidSchemaKeyword) != 0) {\
142 printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\
145 if (validator.GetInvalidDocumentPointer() != Pointer(invalidDocumentPointer)) {\
147 validator.GetInvalidDocumentPointer().Stringify(sb);\
148 printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\
153 TEST(SchemaValidator
, Typeless
) {
156 SchemaDocument
s(sd
);
158 VALIDATE(s
, "42", true);
159 VALIDATE(s
, "\"I'm a string\"", true);
160 VALIDATE(s
, "{ \"an\": [ \"arbitrarily\", \"nested\" ], \"data\": \"structure\" }", true);
163 TEST(SchemaValidator
, MultiType
) {
165 sd
.Parse("{ \"type\": [\"number\", \"string\"] }");
166 SchemaDocument
s(sd
);
168 VALIDATE(s
, "42", true);
169 VALIDATE(s
, "\"Life, the universe, and everything\"", true);
170 INVALIDATE(s
, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
173 TEST(SchemaValidator
, Enum_Typed
) {
175 sd
.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
176 SchemaDocument
s(sd
);
178 VALIDATE(s
, "\"red\"", true);
179 INVALIDATE(s
, "\"blue\"", "", "enum", "");
182 TEST(SchemaValidator
, Enum_Typless
) {
184 sd
.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }");
185 SchemaDocument
s(sd
);
187 VALIDATE(s
, "\"red\"", true);
188 VALIDATE(s
, "null", true);
189 VALIDATE(s
, "42", true);
190 INVALIDATE(s
, "0", "", "enum", "");
193 TEST(SchemaValidator
, Enum_InvalidType
) {
195 sd
.Parse("{ \"type\": \"string\", \"enum\": [\"red\", \"amber\", \"green\", null] }");
196 SchemaDocument
s(sd
);
198 VALIDATE(s
, "\"red\"", true);
199 INVALIDATE(s
, "null", "", "type", "");
202 TEST(SchemaValidator
, AllOf
) {
205 sd
.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"string\", \"maxLength\": 5 }]}");
206 SchemaDocument
s(sd
);
208 VALIDATE(s
, "\"ok\"", true);
209 INVALIDATE(s
, "\"too long\"", "", "allOf", "");
213 sd
.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
214 SchemaDocument
s(sd
);
216 VALIDATE(s
, "\"No way\"", false);
217 INVALIDATE(s
, "-1", "", "allOf", "");
221 TEST(SchemaValidator
, AnyOf
) {
223 sd
.Parse("{\"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
224 SchemaDocument
s(sd
);
226 VALIDATE(s
, "\"Yes\"", true);
227 VALIDATE(s
, "42", true);
228 INVALIDATE(s
, "{ \"Not a\": \"string or number\" }", "", "anyOf", "");
231 TEST(SchemaValidator
, OneOf
) {
233 sd
.Parse("{\"oneOf\": [{ \"type\": \"number\", \"multipleOf\": 5 }, { \"type\": \"number\", \"multipleOf\": 3 } ] }");
234 SchemaDocument
s(sd
);
236 VALIDATE(s
, "10", true);
237 VALIDATE(s
, "9", true);
238 INVALIDATE(s
, "2", "", "oneOf", "");
239 INVALIDATE(s
, "15", "", "oneOf", "");
242 TEST(SchemaValidator
, Not
) {
244 sd
.Parse("{\"not\":{ \"type\": \"string\"}}");
245 SchemaDocument
s(sd
);
247 VALIDATE(s
, "42", true);
248 VALIDATE(s
, "{ \"key\": \"value\" }", true);
249 INVALIDATE(s
, "\"I am a string\"", "", "not", "");
252 TEST(SchemaValidator
, Ref
) {
256 " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
258 " \"definitions\": {"
260 " \"type\": \"object\","
262 " \"street_address\": { \"type\": \"string\" },"
263 " \"city\": { \"type\": \"string\" },"
264 " \"state\": { \"type\": \"string\" }"
266 " \"required\": [\"street_address\", \"city\", \"state\"]"
269 " \"type\": \"object\","
271 " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
272 " \"shipping_address\": { \"$ref\": \"#/definitions/address\" }"
275 SchemaDocument
s(sd
);
277 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);
280 TEST(SchemaValidator
, Ref_AllOf
) {
284 " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
286 " \"definitions\": {"
288 " \"type\": \"object\","
290 " \"street_address\": { \"type\": \"string\" },"
291 " \"city\": { \"type\": \"string\" },"
292 " \"state\": { \"type\": \"string\" }"
294 " \"required\": [\"street_address\", \"city\", \"state\"]"
297 " \"type\": \"object\","
299 " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
300 " \"shipping_address\": {"
302 " { \"$ref\": \"#/definitions/address\" },"
304 " { \"type\": { \"enum\": [ \"residential\", \"business\" ] } },"
305 " \"required\": [\"type\"]"
311 SchemaDocument
s(sd
);
313 INVALIDATE(s
, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address");
314 VALIDATE(s
, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true);
317 TEST(SchemaValidator
, String
) {
319 sd
.Parse("{\"type\":\"string\"}");
320 SchemaDocument
s(sd
);
322 VALIDATE(s
, "\"I'm a string\"", true);
323 INVALIDATE(s
, "42", "", "type", "");
324 INVALIDATE(s
, "2147483648", "", "type", ""); // 2^31 can only be fit in unsigned
325 INVALIDATE(s
, "-2147483649", "", "type", ""); // -2^31 - 1 can only be fit in int64_t
326 INVALIDATE(s
, "4294967296", "", "type", ""); // 2^32 can only be fit in int64_t
327 INVALIDATE(s
, "3.1415926", "", "type", "");
330 TEST(SchemaValidator
, String_LengthRange
) {
332 sd
.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
333 SchemaDocument
s(sd
);
335 INVALIDATE(s
, "\"A\"", "", "minLength", "");
336 VALIDATE(s
, "\"AB\"", true);
337 VALIDATE(s
, "\"ABC\"", true);
338 INVALIDATE(s
, "\"ABCD\"", "", "maxLength", "");
341 #if RAPIDJSON_SCHEMA_HAS_REGEX
342 TEST(SchemaValidator
, String_Pattern
) {
344 sd
.Parse("{\"type\":\"string\",\"pattern\":\"^(\\\\([0-9]{3}\\\\))?[0-9]{3}-[0-9]{4}$\"}");
345 SchemaDocument
s(sd
);
347 VALIDATE(s
, "\"555-1212\"", true);
348 VALIDATE(s
, "\"(888)555-1212\"", true);
349 INVALIDATE(s
, "\"(888)555-1212 ext. 532\"", "", "pattern", "");
350 INVALIDATE(s
, "\"(800)FLOWERS\"", "", "pattern", "");
353 TEST(SchemaValidator
, String_Pattern_Invalid
) {
355 sd
.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}"); // TODO: report regex is invalid somehow
356 SchemaDocument
s(sd
);
358 VALIDATE(s
, "\"\"", true);
359 VALIDATE(s
, "\"a\"", true);
360 VALIDATE(s
, "\"aa\"", true);
364 TEST(SchemaValidator
, Integer
) {
366 sd
.Parse("{\"type\":\"integer\"}");
367 SchemaDocument
s(sd
);
369 VALIDATE(s
, "42", true);
370 VALIDATE(s
, "-1", true);
371 VALIDATE(s
, "2147483648", true); // 2^31 can only be fit in unsigned
372 VALIDATE(s
, "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
373 VALIDATE(s
, "2147483648", true); // 2^31 can only be fit in unsigned
374 VALIDATE(s
, "4294967296", true); // 2^32 can only be fit in int64_t
375 INVALIDATE(s
, "3.1415926", "", "type", "");
376 INVALIDATE(s
, "\"42\"", "", "type", "");
379 TEST(SchemaValidator
, Integer_Range
) {
381 sd
.Parse("{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
382 SchemaDocument
s(sd
);
384 INVALIDATE(s
, "-1", "", "minimum", "");
385 VALIDATE(s
, "0", true);
386 VALIDATE(s
, "10", true);
387 VALIDATE(s
, "99", true);
388 INVALIDATE(s
, "100", "", "maximum", "");
389 INVALIDATE(s
, "101", "", "maximum", "");
392 TEST(SchemaValidator
, Integer_Range64Boundary
) {
394 sd
.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":9223372036854775806}");
395 SchemaDocument
s(sd
);
397 INVALIDATE(s
, "-9223372036854775808", "", "minimum", "");
398 VALIDATE(s
, "-9223372036854775807", true);
399 VALIDATE(s
, "-2147483648", true); // int min
400 VALIDATE(s
, "0", true);
401 VALIDATE(s
, "2147483647", true); // int max
402 VALIDATE(s
, "2147483648", true); // unsigned first
403 VALIDATE(s
, "4294967295", true); // unsigned max
404 VALIDATE(s
, "9223372036854775806", true);
405 INVALIDATE(s
, "9223372036854775807", "", "maximum", "");
406 INVALIDATE(s
, "18446744073709551615", "", "maximum", ""); // uint64_t max
409 TEST(SchemaValidator
, Integer_RangeU64Boundary
) {
411 sd
.Parse("{\"type\":\"integer\",\"minimum\":9223372036854775808,\"maximum\":18446744073709551614}");
412 SchemaDocument
s(sd
);
414 INVALIDATE(s
, "-9223372036854775808", "", "minimum", "");
415 INVALIDATE(s
, "9223372036854775807", "", "minimum", "");
416 INVALIDATE(s
, "-2147483648", "", "minimum", ""); // int min
417 INVALIDATE(s
, "0", "", "minimum", "");
418 INVALIDATE(s
, "2147483647", "", "minimum", ""); // int max
419 INVALIDATE(s
, "2147483648", "", "minimum", ""); // unsigned first
420 INVALIDATE(s
, "4294967295", "", "minimum", ""); // unsigned max
421 VALIDATE(s
, "9223372036854775808", true);
422 VALIDATE(s
, "18446744073709551614", true);
423 INVALIDATE(s
, "18446744073709551615", "", "maximum", "");
426 TEST(SchemaValidator
, Integer_Range64BoundaryExclusive
) {
428 sd
.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}");
429 SchemaDocument
s(sd
);
431 INVALIDATE(s
, "-9223372036854775808", "", "minimum", "");
432 VALIDATE(s
, "-9223372036854775807", true);
433 VALIDATE(s
, "18446744073709551614", true);
434 INVALIDATE(s
, "18446744073709551615", "", "maximum", "");
437 TEST(SchemaValidator
, Integer_MultipleOf
) {
439 sd
.Parse("{\"type\":\"integer\",\"multipleOf\":10}");
440 SchemaDocument
s(sd
);
442 VALIDATE(s
, "0", true);
443 VALIDATE(s
, "10", true);
444 VALIDATE(s
, "-10", true);
445 VALIDATE(s
, "20", true);
446 INVALIDATE(s
, "23", "", "multipleOf", "");
447 INVALIDATE(s
, "-23", "", "multipleOf", "");
450 TEST(SchemaValidator
, Integer_MultipleOf64Boundary
) {
452 sd
.Parse("{\"type\":\"integer\",\"multipleOf\":18446744073709551615}");
453 SchemaDocument
s(sd
);
455 VALIDATE(s
, "0", true);
456 VALIDATE(s
, "18446744073709551615", true);
457 INVALIDATE(s
, "18446744073709551614", "", "multipleOf", "");
460 TEST(SchemaValidator
, Number_Range
) {
462 sd
.Parse("{\"type\":\"number\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
463 SchemaDocument
s(sd
);
465 INVALIDATE(s
, "-1", "", "minimum", "");
466 VALIDATE(s
, "0", true);
467 VALIDATE(s
, "0.1", true);
468 VALIDATE(s
, "10", true);
469 VALIDATE(s
, "99", true);
470 VALIDATE(s
, "99.9", true);
471 INVALIDATE(s
, "100", "", "maximum", "");
472 INVALIDATE(s
, "100.0", "", "maximum", "");
473 INVALIDATE(s
, "101.5", "", "maximum", "");
476 TEST(SchemaValidator
, Number_RangeInt
) {
478 sd
.Parse("{\"type\":\"number\",\"minimum\":-100,\"maximum\":-1,\"exclusiveMaximum\":true}");
479 SchemaDocument
s(sd
);
481 INVALIDATE(s
, "-101", "", "minimum", "");
482 INVALIDATE(s
, "-100.1", "", "minimum", "");
483 VALIDATE(s
, "-100", true);
484 VALIDATE(s
, "-2", true);
485 INVALIDATE(s
, "-1", "", "maximum", "");
486 INVALIDATE(s
, "-0.9", "", "maximum", "");
487 INVALIDATE(s
, "0", "", "maximum", "");
488 INVALIDATE(s
, "2147483647", "", "maximum", ""); // int max
489 INVALIDATE(s
, "2147483648", "", "maximum", ""); // unsigned first
490 INVALIDATE(s
, "4294967295", "", "maximum", ""); // unsigned max
491 INVALIDATE(s
, "9223372036854775808", "", "maximum", "");
492 INVALIDATE(s
, "18446744073709551614", "", "maximum", "");
493 INVALIDATE(s
, "18446744073709551615", "", "maximum", "");
496 TEST(SchemaValidator
, Number_RangeDouble
) {
498 sd
.Parse("{\"type\":\"number\",\"minimum\":0.1,\"maximum\":100.1,\"exclusiveMaximum\":true}");
499 SchemaDocument
s(sd
);
501 INVALIDATE(s
, "-9223372036854775808", "", "minimum", "");
502 INVALIDATE(s
, "-2147483648", "", "minimum", ""); // int min
503 INVALIDATE(s
, "-1", "", "minimum", "");
504 VALIDATE(s
, "0.1", true);
505 VALIDATE(s
, "10", true);
506 VALIDATE(s
, "99", true);
507 VALIDATE(s
, "100", true);
508 INVALIDATE(s
, "101", "", "maximum", "");
509 INVALIDATE(s
, "101.5", "", "maximum", "");
510 INVALIDATE(s
, "18446744073709551614", "", "maximum", "");
511 INVALIDATE(s
, "18446744073709551615", "", "maximum", "");
512 INVALIDATE(s
, "2147483647", "", "maximum", ""); // int max
513 INVALIDATE(s
, "2147483648", "", "maximum", ""); // unsigned first
514 INVALIDATE(s
, "4294967295", "", "maximum", ""); // unsigned max
515 INVALIDATE(s
, "9223372036854775808", "", "maximum", "");
516 INVALIDATE(s
, "18446744073709551614", "", "maximum", "");
517 INVALIDATE(s
, "18446744073709551615", "", "maximum", "");
520 TEST(SchemaValidator
, Number_RangeDoubleU64Boundary
) {
522 sd
.Parse("{\"type\":\"number\",\"minimum\":9223372036854775808.0,\"maximum\":18446744073709550000.0}");
523 SchemaDocument
s(sd
);
525 INVALIDATE(s
, "-9223372036854775808", "", "minimum", "");
526 INVALIDATE(s
, "-2147483648", "", "minimum", ""); // int min
527 INVALIDATE(s
, "0", "", "minimum", "");
528 INVALIDATE(s
, "2147483647", "", "minimum", ""); // int max
529 INVALIDATE(s
, "2147483648", "", "minimum", ""); // unsigned first
530 INVALIDATE(s
, "4294967295", "", "minimum", ""); // unsigned max
531 VALIDATE(s
, "9223372036854775808", true);
532 VALIDATE(s
, "18446744073709540000", true);
533 INVALIDATE(s
, "18446744073709551615", "", "maximum", "");
536 TEST(SchemaValidator
, Number_MultipleOf
) {
538 sd
.Parse("{\"type\":\"number\",\"multipleOf\":10.0}");
539 SchemaDocument
s(sd
);
541 VALIDATE(s
, "0", true);
542 VALIDATE(s
, "10", true);
543 VALIDATE(s
, "-10", true);
544 VALIDATE(s
, "20", true);
545 INVALIDATE(s
, "23", "", "multipleOf", "");
546 INVALIDATE(s
, "-2147483648", "", "multipleOf", ""); // int min
547 VALIDATE(s
, "-2147483640", true);
548 INVALIDATE(s
, "2147483647", "", "multipleOf", ""); // int max
549 INVALIDATE(s
, "2147483648", "", "multipleOf", ""); // unsigned first
550 VALIDATE(s
, "2147483650", true);
551 INVALIDATE(s
, "4294967295", "", "multipleOf", ""); // unsigned max
552 VALIDATE(s
, "4294967300", true);
555 TEST(SchemaValidator
, Number_MultipleOfOne
) {
557 sd
.Parse("{\"type\":\"number\",\"multipleOf\":1}");
558 SchemaDocument
s(sd
);
560 VALIDATE(s
, "42", true);
561 VALIDATE(s
, "42.0", true);
562 INVALIDATE(s
, "3.1415926", "", "multipleOf", "");
565 TEST(SchemaValidator
, Object
) {
567 sd
.Parse("{\"type\":\"object\"}");
568 SchemaDocument
s(sd
);
570 VALIDATE(s
, "{\"key\":\"value\",\"another_key\":\"another_value\"}", true);
571 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);
572 INVALIDATE(s
, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "");
573 INVALIDATE(s
, "\"Not an object\"", "", "type", "");
576 TEST(SchemaValidator
, Object_Properties
) {
580 " \"type\": \"object\","
581 " \"properties\" : {"
582 " \"number\": { \"type\": \"number\" },"
583 " \"street_name\" : { \"type\": \"string\" },"
584 " \"street_type\" : { \"type\": \"string\", \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"] }"
588 SchemaDocument
s(sd
);
590 VALIDATE(s
, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
591 INVALIDATE(s
, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number");
592 VALIDATE(s
, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\" }", true);
593 VALIDATE(s
, "{}", true);
594 VALIDATE(s
, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
597 TEST(SchemaValidator
, Object_AdditionalPropertiesBoolean
) {
601 " \"type\": \"object\","
602 " \"properties\" : {"
603 " \"number\": { \"type\": \"number\" },"
604 " \"street_name\" : { \"type\": \"string\" },"
605 " \"street_type\" : { \"type\": \"string\","
606 " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
609 " \"additionalProperties\": false"
612 SchemaDocument
s(sd
);
614 VALIDATE(s
, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
615 INVALIDATE(s
, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction");
618 TEST(SchemaValidator
, Object_AdditionalPropertiesObject
) {
622 " \"type\": \"object\","
623 " \"properties\" : {"
624 " \"number\": { \"type\": \"number\" },"
625 " \"street_name\" : { \"type\": \"string\" },"
626 " \"street_type\" : { \"type\": \"string\","
627 " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
630 " \"additionalProperties\": { \"type\": \"string\" }"
632 SchemaDocument
s(sd
);
634 VALIDATE(s
, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
635 VALIDATE(s
, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
636 INVALIDATE(s
, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number");
639 TEST(SchemaValidator
, Object_Required
) {
643 " \"type\": \"object\","
644 " \"properties\" : {"
645 " \"name\": { \"type\": \"string\" },"
646 " \"email\" : { \"type\": \"string\" },"
647 " \"address\" : { \"type\": \"string\" },"
648 " \"telephone\" : { \"type\": \"string\" }"
650 " \"required\":[\"name\", \"email\"]"
652 SchemaDocument
s(sd
);
654 VALIDATE(s
, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\" }", true);
655 VALIDATE(s
, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
656 INVALIDATE(s
, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "");
660 TEST(SchemaValidator
, Object_PropertiesRange
) {
662 sd
.Parse("{\"type\":\"object\", \"minProperties\":2, \"maxProperties\":3}");
663 SchemaDocument
s(sd
);
665 INVALIDATE(s
, "{}", "", "minProperties", "");
666 INVALIDATE(s
, "{\"a\":0}", "", "minProperties", "");
667 VALIDATE(s
, "{\"a\":0,\"b\":1}", true);
668 VALIDATE(s
, "{\"a\":0,\"b\":1,\"c\":2}", true);
669 INVALIDATE(s
, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "");
672 TEST(SchemaValidator
, Object_PropertyDependencies
) {
676 " \"type\": \"object\","
678 " \"name\": { \"type\": \"string\" },"
679 " \"credit_card\": { \"type\": \"number\" },"
680 " \"billing_address\": { \"type\": \"string\" }"
682 " \"required\": [\"name\"],"
683 " \"dependencies\": {"
684 " \"credit_card\": [\"billing_address\"]"
687 SchemaDocument
s(sd
);
689 VALIDATE(s
, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"billing_address\": \"555 Debtor's Lane\" }", true);
690 INVALIDATE(s
, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "");
691 VALIDATE(s
, "{ \"name\": \"John Doe\"}", true);
692 VALIDATE(s
, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
695 TEST(SchemaValidator
, Object_SchemaDependencies
) {
699 " \"type\": \"object\","
700 " \"properties\" : {"
701 " \"name\": { \"type\": \"string\" },"
702 " \"credit_card\" : { \"type\": \"number\" }"
704 " \"required\" : [\"name\"],"
705 " \"dependencies\" : {"
706 " \"credit_card\": {"
708 " \"billing_address\": { \"type\": \"string\" }"
710 " \"required\" : [\"billing_address\"]"
714 SchemaDocument
s(sd
);
716 VALIDATE(s
, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
717 INVALIDATE(s
, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "");
718 VALIDATE(s
, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true);
721 #if RAPIDJSON_SCHEMA_HAS_REGEX
722 TEST(SchemaValidator
, Object_PatternProperties
) {
726 " \"type\": \"object\","
727 " \"patternProperties\": {"
728 " \"^S_\": { \"type\": \"string\" },"
729 " \"^I_\": { \"type\": \"integer\" }"
732 SchemaDocument
s(sd
);
734 VALIDATE(s
, "{ \"S_25\": \"This is a string\" }", true);
735 VALIDATE(s
, "{ \"I_0\": 42 }", true);
736 INVALIDATE(s
, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0");
737 INVALIDATE(s
, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42");
738 VALIDATE(s
, "{ \"keyword\": \"value\" }", true);
741 TEST(SchemaValidator
, Object_PatternProperties_AdditionalProperties
) {
745 " \"type\": \"object\","
747 " \"builtin\": { \"type\": \"number\" }"
749 " \"patternProperties\": {"
750 " \"^S_\": { \"type\": \"string\" },"
751 " \"^I_\": { \"type\": \"integer\" }"
753 " \"additionalProperties\": { \"type\": \"string\" }"
755 SchemaDocument
s(sd
);
757 VALIDATE(s
, "{ \"builtin\": 42 }", true);
758 VALIDATE(s
, "{ \"keyword\": \"value\" }", true);
759 INVALIDATE(s
, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword");
763 TEST(SchemaValidator
, Array
) {
765 sd
.Parse("{\"type\":\"array\"}");
766 SchemaDocument
s(sd
);
768 VALIDATE(s
, "[1, 2, 3, 4, 5]", true);
769 VALIDATE(s
, "[3, \"different\", { \"types\" : \"of values\" }]", true);
770 INVALIDATE(s
, "{\"Not\": \"an array\"}", "", "type", "");
773 TEST(SchemaValidator
, Array_ItemsList
) {
777 " \"type\": \"array\","
779 " \"type\": \"number\""
782 SchemaDocument
s(sd
);
784 VALIDATE(s
, "[1, 2, 3, 4, 5]", true);
785 INVALIDATE(s
, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2");
786 VALIDATE(s
, "[]", true);
789 TEST(SchemaValidator
, Array_ItemsTuple
) {
793 " \"type\": \"array\","
796 " \"type\": \"number\""
799 " \"type\": \"string\""
802 " \"type\": \"string\","
803 " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
806 " \"type\": \"string\","
807 " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
811 SchemaDocument
s(sd
);
813 VALIDATE(s
, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
814 INVALIDATE(s
, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2");
815 INVALIDATE(s
, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0");
816 VALIDATE(s
, "[10, \"Downing\", \"Street\"]", true);
817 VALIDATE(s
, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true);
820 TEST(SchemaValidator
, Array_AdditionalItmes
) {
824 " \"type\": \"array\","
827 " \"type\": \"number\""
830 " \"type\": \"string\""
833 " \"type\": \"string\","
834 " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
837 " \"type\": \"string\","
838 " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
841 " \"additionalItems\": false"
843 SchemaDocument
s(sd
);
845 VALIDATE(s
, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
846 VALIDATE(s
, "[1600, \"Pennsylvania\", \"Avenue\"]", true);
847 INVALIDATE(s
, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4");
850 TEST(SchemaValidator
, Array_ItemsRange
) {
852 sd
.Parse("{\"type\": \"array\",\"minItems\": 2,\"maxItems\" : 3}");
853 SchemaDocument
s(sd
);
855 INVALIDATE(s
, "[]", "", "minItems", "");
856 INVALIDATE(s
, "[1]", "", "minItems", "");
857 VALIDATE(s
, "[1, 2]", true);
858 VALIDATE(s
, "[1, 2, 3]", true);
859 INVALIDATE(s
, "[1, 2, 3, 4]", "", "maxItems", "");
862 TEST(SchemaValidator
, Array_UniqueItems
) {
864 sd
.Parse("{\"type\": \"array\", \"uniqueItems\": true}");
865 SchemaDocument
s(sd
);
867 VALIDATE(s
, "[1, 2, 3, 4, 5]", true);
868 INVALIDATE(s
, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3");
869 VALIDATE(s
, "[]", true);
872 TEST(SchemaValidator
, Boolean
) {
874 sd
.Parse("{\"type\":\"boolean\"}");
875 SchemaDocument
s(sd
);
877 VALIDATE(s
, "true", true);
878 VALIDATE(s
, "false", true);
879 INVALIDATE(s
, "\"true\"", "", "type", "");
880 INVALIDATE(s
, "0", "", "type", "");
883 TEST(SchemaValidator
, Null
) {
885 sd
.Parse("{\"type\":\"null\"}");
886 SchemaDocument
s(sd
);
888 VALIDATE(s
, "null", true);
889 INVALIDATE(s
, "false", "", "type", "");
890 INVALIDATE(s
, "0", "", "type", "");
891 INVALIDATE(s
, "\"\"", "", "type", "");
896 TEST(SchemaValidator
, ObjectInArray
) {
898 sd
.Parse("{\"type\":\"array\", \"items\": { \"type\":\"string\" }}");
899 SchemaDocument
s(sd
);
901 VALIDATE(s
, "[\"a\"]", true);
902 INVALIDATE(s
, "[1]", "/items", "type", "/0");
903 INVALIDATE(s
, "[{}]", "/items", "type", "/0");
906 TEST(SchemaValidator
, MultiTypeInObject
) {
910 " \"type\":\"object\","
913 " \"type\":[\"integer\", \"string\"]"
917 SchemaDocument
s(sd
);
919 VALIDATE(s
, "{ \"tel\": 999 }", true);
920 VALIDATE(s
, "{ \"tel\": \"123-456\" }", true);
921 INVALIDATE(s
, "{ \"tel\": true }", "/properties/tel", "type", "/tel");
924 TEST(SchemaValidator
, MultiTypeWithObject
) {
928 " \"type\": [\"object\",\"string\"],"
931 " \"type\": \"integer\""
935 SchemaDocument
s(sd
);
937 VALIDATE(s
, "\"Hello\"", true);
938 VALIDATE(s
, "{ \"tel\": 999 }", true);
939 INVALIDATE(s
, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel");
942 TEST(SchemaValidator
, AllOf_Nested
) {
947 " { \"type\": \"string\", \"minLength\": 2 },"
948 " { \"type\": \"string\", \"maxLength\": 5 },"
949 " { \"allOf\": [ { \"enum\" : [\"ok\", \"okay\", \"OK\", \"o\"] }, { \"enum\" : [\"ok\", \"OK\", \"o\"]} ] }"
952 SchemaDocument
s(sd
);
954 VALIDATE(s
, "\"ok\"", true);
955 VALIDATE(s
, "\"OK\"", true);
956 INVALIDATE(s
, "\"okay\"", "", "allOf", "");
957 INVALIDATE(s
, "\"o\"", "", "allOf", "");
958 INVALIDATE(s
, "\"n\"", "", "allOf", "");
959 INVALIDATE(s
, "\"too long\"", "", "allOf", "");
960 INVALIDATE(s
, "123", "", "allOf", "");
963 TEST(SchemaValidator
, EscapedPointer
) {
967 " \"type\": \"object\","
969 " \"~/\": { \"type\": \"number\" }"
972 SchemaDocument
s(sd
);
973 INVALIDATE(s
, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1");
976 template <typename Allocator
>
977 static char* ReadFile(const char* filename
, Allocator
& allocator
) {
978 const char *paths
[] = {
987 for (size_t i
= 0; i
< sizeof(paths
) / sizeof(paths
[0]); i
++) {
988 sprintf(buffer
, "%s%s", paths
[i
], filename
);
989 fp
= fopen(buffer
, "rb");
997 fseek(fp
, 0, SEEK_END
);
998 size_t length
= static_cast<size_t>(ftell(fp
));
999 fseek(fp
, 0, SEEK_SET
);
1000 char* json
= reinterpret_cast<char*>(allocator
.Malloc(length
+ 1));
1001 size_t readLength
= fread(json
, 1, length
, fp
);
1002 json
[readLength
] = '\0';
1007 TEST(SchemaValidator
, ValidateMetaSchema
) {
1008 CrtAllocator allocator
;
1009 char* json
= ReadFile("draft-04/schema", allocator
);
1012 ASSERT_FALSE(d
.HasParseError());
1013 SchemaDocument
sd(d
);
1014 SchemaValidator
validator(sd
);
1015 if (!d
.Accept(validator
)) {
1017 validator
.GetInvalidSchemaPointer().StringifyUriFragment(sb
);
1018 printf("Invalid schema: %s\n", sb
.GetString());
1019 printf("Invalid keyword: %s\n", validator
.GetInvalidSchemaKeyword());
1021 validator
.GetInvalidDocumentPointer().StringifyUriFragment(sb
);
1022 printf("Invalid document: %s\n", sb
.GetString());
1025 CrtAllocator::Free(json
);
1028 TEST(SchemaValidator
, ValidateMetaSchema_UTF16
) {
1029 typedef GenericDocument
<UTF16
<> > D
;
1030 typedef GenericSchemaDocument
<D::ValueType
> SD
;
1031 typedef GenericSchemaValidator
<SD
> SV
;
1033 CrtAllocator allocator
;
1034 char* json
= ReadFile("draft-04/schema", allocator
);
1037 StringStream
ss(json
);
1038 d
.ParseStream
<0, UTF8
<> >(ss
);
1039 ASSERT_FALSE(d
.HasParseError());
1042 if (!d
.Accept(validator
)) {
1043 GenericStringBuffer
<UTF16
<> > sb
;
1044 validator
.GetInvalidSchemaPointer().StringifyUriFragment(sb
);
1045 wprintf(L
"Invalid schema: %ls\n", sb
.GetString());
1046 wprintf(L
"Invalid keyword: %ls\n", validator
.GetInvalidSchemaKeyword());
1048 validator
.GetInvalidDocumentPointer().StringifyUriFragment(sb
);
1049 wprintf(L
"Invalid document: %ls\n", sb
.GetString());
1052 CrtAllocator::Free(json
);
1055 template <typename SchemaDocumentType
= SchemaDocument
>
1056 class RemoteSchemaDocumentProvider
: public IGenericRemoteSchemaDocumentProvider
<SchemaDocumentType
> {
1058 RemoteSchemaDocumentProvider() :
1059 documentAllocator_(documentBuffer_
, sizeof(documentBuffer_
)),
1060 schemaAllocator_(schemaBuffer_
, sizeof(schemaBuffer_
))
1062 const char* filenames
[kCount
] = {
1063 "jsonschema/remotes/integer.json",
1064 "jsonschema/remotes/subSchemas.json",
1065 "jsonschema/remotes/folder/folderInteger.json",
1069 for (size_t i
= 0; i
< kCount
; i
++) {
1072 char jsonBuffer
[8192];
1073 MemoryPoolAllocator
<> jsonAllocator(jsonBuffer
, sizeof(jsonBuffer
));
1074 char* json
= ReadFile(filenames
[i
], jsonAllocator
);
1076 printf("json remote file %s not found", filenames
[i
]);
1080 char stackBuffer
[4096];
1081 MemoryPoolAllocator
<> stackAllocator(stackBuffer
, sizeof(stackBuffer
));
1082 DocumentType
d(&documentAllocator_
, 1024, &stackAllocator
);
1084 sd_
[i
] = new SchemaDocumentType(d
, 0, &schemaAllocator_
);
1085 MemoryPoolAllocator
<>::Free(json
);
1090 ~RemoteSchemaDocumentProvider() {
1091 for (size_t i
= 0; i
< kCount
; i
++)
1095 virtual const SchemaDocumentType
* GetRemoteDocument(const char* uri
, SizeType length
) {
1096 const char* uris
[kCount
] = {
1097 "http://localhost:1234/integer.json",
1098 "http://localhost:1234/subSchemas.json",
1099 "http://localhost:1234/folder/folderInteger.json",
1100 "http://json-schema.org/draft-04/schema"
1103 for (size_t i
= 0; i
< kCount
; i
++)
1104 if (strncmp(uri
, uris
[i
], length
) == 0)
1110 typedef GenericDocument
<typename
SchemaDocumentType::EncodingType
, MemoryPoolAllocator
<>, MemoryPoolAllocator
<> > DocumentType
;
1112 RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider
&);
1113 RemoteSchemaDocumentProvider
& operator=(const RemoteSchemaDocumentProvider
&);
1115 static const size_t kCount
= 4;
1116 SchemaDocumentType
* sd_
[kCount
];
1117 typename
DocumentType::AllocatorType documentAllocator_
;
1118 typename
SchemaDocumentType::AllocatorType schemaAllocator_
;
1119 char documentBuffer_
[16384];
1120 char schemaBuffer_
[128 * 1024];
1123 TEST(SchemaValidator
, TestSuite
) {
1124 const char* filenames
[] = {
1125 "additionalItems.json",
1126 "additionalProperties.json",
1131 "dependencies.json",
1137 "maxProperties.json",
1141 "minProperties.json",
1146 "patternProperties.json",
1155 const char* onlyRunDescription
= 0;
1156 //const char* onlyRunDescription = "a string is a string";
1158 unsigned testCount
= 0;
1159 unsigned passCount
= 0;
1161 typedef GenericSchemaDocument
<Value
, MemoryPoolAllocator
<> > SchemaDocumentType
;
1162 RemoteSchemaDocumentProvider
<SchemaDocumentType
> provider
;
1164 char jsonBuffer
[65536];
1165 char documentBuffer
[65536];
1166 char documentStackBuffer
[65536];
1167 char schemaBuffer
[65536];
1168 char validatorBuffer
[65536];
1169 MemoryPoolAllocator
<> jsonAllocator(jsonBuffer
, sizeof(jsonBuffer
));
1170 MemoryPoolAllocator
<> documentAllocator(documentBuffer
, sizeof(documentBuffer
));
1171 MemoryPoolAllocator
<> documentStackAllocator(documentStackBuffer
, sizeof(documentStackBuffer
));
1172 MemoryPoolAllocator
<> schemaAllocator(schemaBuffer
, sizeof(schemaBuffer
));
1173 MemoryPoolAllocator
<> validatorAllocator(validatorBuffer
, sizeof(validatorBuffer
));
1175 for (size_t i
= 0; i
< sizeof(filenames
) / sizeof(filenames
[0]); i
++) {
1176 char filename
[FILENAME_MAX
];
1177 sprintf(filename
, "jsonschema/tests/draft4/%s", filenames
[i
]);
1178 char* json
= ReadFile(filename
, jsonAllocator
);
1180 printf("json test suite file %s not found", filename
);
1184 GenericDocument
<UTF8
<>, MemoryPoolAllocator
<>, MemoryPoolAllocator
<> > d(&documentAllocator
, 1024, &documentStackAllocator
);
1186 if (d
.HasParseError()) {
1187 printf("json test suite file %s has parse error", filename
);
1191 for (Value::ConstValueIterator schemaItr
= d
.Begin(); schemaItr
!= d
.End(); ++schemaItr
) {
1193 SchemaDocumentType
schema((*schemaItr
)["schema"], &provider
, &schemaAllocator
);
1194 GenericSchemaValidator
<SchemaDocumentType
, BaseReaderHandler
<UTF8
<> >, MemoryPoolAllocator
<> > validator(schema
, &validatorAllocator
);
1195 const char* description1
= (*schemaItr
)["description"].GetString();
1196 const Value
& tests
= (*schemaItr
)["tests"];
1197 for (Value::ConstValueIterator testItr
= tests
.Begin(); testItr
!= tests
.End(); ++testItr
) {
1198 const char* description2
= (*testItr
)["description"].GetString();
1199 if (!onlyRunDescription
|| strcmp(description2
, onlyRunDescription
) == 0) {
1200 const Value
& data
= (*testItr
)["data"];
1201 bool expected
= (*testItr
)["valid"].GetBool();
1204 bool actual
= data
.Accept(validator
);
1205 if (expected
!= actual
)
1206 printf("Fail: %30s \"%s\" \"%s\"\n", filename
, description1
, description2
);
1211 //printf("%zu %zu %zu\n", documentAllocator.Size(), schemaAllocator.Size(), validatorAllocator.Size());
1213 schemaAllocator
.Clear();
1214 validatorAllocator
.Clear();
1218 documentAllocator
.Clear();
1219 MemoryPoolAllocator
<>::Free(json
);
1220 jsonAllocator
.Clear();
1222 printf("%d / %d passed (%2d%%)\n", passCount
, testCount
, passCount
* 100 / testCount
);
1223 // if (passCount != testCount)
1227 TEST(SchemaValidatingReader
, Simple
) {
1229 sd
.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
1230 SchemaDocument
s(sd
);
1233 StringStream
ss("\"red\"");
1234 SchemaValidatingReader
<kParseDefaultFlags
, StringStream
, UTF8
<> > reader(ss
, s
);
1236 EXPECT_TRUE(reader
.GetParseResult());
1237 EXPECT_TRUE(reader
.IsValid());
1238 EXPECT_TRUE(d
.IsString());
1239 EXPECT_STREQ("red", d
.GetString());
1242 TEST(SchemaValidatingReader
, Invalid
) {
1244 sd
.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
1245 SchemaDocument
s(sd
);
1248 StringStream
ss("\"ABCD\"");
1249 SchemaValidatingReader
<kParseDefaultFlags
, StringStream
, UTF8
<> > reader(ss
, s
);
1251 EXPECT_FALSE(reader
.GetParseResult());
1252 EXPECT_FALSE(reader
.IsValid());
1253 EXPECT_EQ(kParseErrorTermination
, reader
.GetParseResult().Code());
1254 EXPECT_STREQ("maxLength", reader
.GetInvalidSchemaKeyword());
1255 EXPECT_TRUE(reader
.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
1256 EXPECT_TRUE(reader
.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
1257 EXPECT_TRUE(d
.IsNull());
1260 TEST(SchemaValidatingWriter
, Simple
) {
1262 sd
.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
1263 SchemaDocument
s(sd
);
1267 Writer
<StringBuffer
> writer(sb
);
1268 GenericSchemaValidator
<SchemaDocument
, Writer
<StringBuffer
> > validator(s
, writer
);
1271 EXPECT_TRUE(d
.Accept(validator
));
1272 EXPECT_TRUE(validator
.IsValid());
1273 EXPECT_STREQ("\"red\"", sb
.GetString());
1277 d
.Parse("\"ABCD\"");
1278 EXPECT_FALSE(d
.Accept(validator
));
1279 EXPECT_FALSE(validator
.IsValid());
1280 EXPECT_TRUE(validator
.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
1281 EXPECT_TRUE(validator
.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
1284 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1286 static SchemaDocument
ReturnSchemaDocument() {
1288 sd
.Parse("{ \"type\": [\"number\", \"string\"] }");
1289 SchemaDocument
s(sd
);
1293 TEST(Schema
, Issue552
) {
1294 SchemaDocument s
= ReturnSchemaDocument();
1295 VALIDATE(s
, "42", true);
1296 VALIDATE(s
, "\"Life, the universe, and everything\"", true);
1297 INVALIDATE(s
, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
1300 #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
1302 TEST(SchemaValidator
, Issue608
) {
1304 sd
.Parse("{\"required\": [\"a\", \"b\"] }");
1305 SchemaDocument
s(sd
);
1307 VALIDATE(s
, "{\"a\" : null, \"b\": null}", true);
1308 INVALIDATE(s
, "{\"a\" : null, \"a\" : null}", "", "required", "");