1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 var AssertTrue
= requireNative('assert').AssertTrue
;
6 var JSONSchemaValidator
= require('json_schema').JSONSchemaValidator
;
7 var LOG
= requireNative('logging').LOG
;
9 function assertValid(type
, instance
, schema
, types
) {
10 var validator
= new JSONSchemaValidator();
12 validator
.addTypes(types
);
13 validator
["validate" + type
](instance
, schema
, "");
15 if (validator
.errors
.length
!= 0) {
16 LOG("Got unexpected errors");
17 for (var i
= 0; i
< validator
.errors
.length
; i
++) {
18 LOG(validator
.errors
[i
].message
+ " path: " + validator
.errors
[i
].path
);
25 function assertNotValid(type
, instance
, schema
, errors
, types
) {
26 var validator
= new JSONSchemaValidator();
28 validator
.addTypes(types
);
29 validator
["validate" + type
](instance
, schema
, "");
30 AssertTrue(validator
.errors
.length
=== errors
.length
);
32 for (var i
= 0; i
< errors
.length
; i
++) {
33 if (validator
.errors
[i
].message
== errors
[i
]) {
34 LOG("Got expected error: " + validator
.errors
[i
].message
+
35 " for path: " + validator
.errors
[i
].path
);
37 LOG("Missed expected error: " + errors
[i
] + ". Got: " +
38 validator
.errors
[i
].message
+ " instead.");
45 function assertListConsistsOfElements(list
, elements
) {
47 for (var li
= 0; li
< list
.length
; li
++) {
48 for (var ei
= 0; ei
< elements
.length
&& list
[li
] != elements
[ei
]; ei
++) { }
49 if (ei
== elements
.length
) {
50 LOG("Expected type not found: " + list
[li
]);
57 function assertEqualSets(set1
, set2
) {
58 assertListConsistsOfElements(set1
, set2
);
59 assertListConsistsOfElements(set2
, set1
);
62 function formatError(key
, replacements
) {
63 return JSONSchemaValidator
.formatError(key
, replacements
);
66 function testFormatError() {
67 AssertTrue(formatError("propertyRequired") == "Property is required.");
68 AssertTrue(formatError("invalidEnum", ["foo, bar"]) ==
69 "Value must be one of: [foo, bar].");
70 AssertTrue(formatError("invalidType", ["foo", "bar"]) ==
71 "Expected 'foo' but got 'bar'.");
74 function testComplex() {
101 { type
: "function", optional
: true },
102 { type
: "function", optional
: true }
109 url
: "http://www.google.com/",
117 assertValid("", instance
, schema
);
119 assertValid("", instance
, schema
);
122 assertNotValid("", instance
, schema
,
123 [formatError("invalidType", ["function", "object"])]);
124 instance
[1] = function(){};
126 instance
[0].url
= "foo";
127 assertNotValid("", instance
, schema
,
128 [formatError("stringPattern",
129 [schema
.items
[0].properties
.url
.pattern
])]);
130 delete instance
[0].url
;
131 assertValid("", instance
, schema
);
134 assertNotValid("", instance
, schema
,
135 [formatError("numberMinValue",
136 [schema
.items
[0].properties
.id
.minimum
])]);
139 function testEnum() {
141 enum: ["foo", 42, false]
144 assertValid("", "foo", schema
);
145 assertValid("", 42, schema
);
146 assertValid("", false, schema
);
147 assertNotValid("", "42", schema
, [formatError("invalidEnum",
148 [schema
.enum.join(", ")])]);
149 assertNotValid("", null, schema
, [formatError("invalidEnum",
150 [schema
.enum.join(", ")])]);
153 function testChoices() {
157 { type
: "undefined" },
158 { type
: "integer", minimum
:42, maximum
:42 },
159 { type
: "object", properties
: { foo
: { type
: "string" } } }
162 assertValid("", null, schema
);
163 assertValid("", undefined, schema
);
164 assertValid("", 42, schema
);
165 assertValid("", {foo
: "bar"}, schema
);
167 assertNotValid("", "foo", schema
, [formatError("invalidChoice", [])]);
168 assertNotValid("", [], schema
, [formatError("invalidChoice", [])]);
169 assertNotValid("", {foo
: 42}, schema
, [formatError("invalidChoice", [])]);
172 function testExtends() {
180 assertValid("", 42, schema
);
181 assertNotValid("", "42", schema
,
182 [formatError("invalidType", ["number", "string"])]);
184 // Make the derived schema more restrictive
186 assertNotValid("", 42, schema
, [formatError("numberMinValue", [43])]);
187 assertValid("", 43, schema
);
190 function testObject() {
202 assertValid("Object", {foo
:"foo", bar
:42}, schema
);
203 assertNotValid("Object", {foo
:"foo", bar
:42,"extra":true}, schema
,
204 [formatError("unexpectedProperty")]);
205 assertNotValid("Object", {foo
:"foo"}, schema
,
206 [formatError("propertyRequired")]);
207 assertNotValid("Object", {foo
:"foo", bar
:"42"}, schema
,
208 [formatError("invalidType", ["integer", "string"])]);
210 schema
.additionalProperties
= { type
: "any" };
211 assertValid("Object", {foo
:"foo", bar
:42, "extra":true}, schema
);
212 assertValid("Object", {foo
:"foo", bar
:42, "extra":"foo"}, schema
);
214 schema
.additionalProperties
= { type
: "boolean" };
215 assertValid("Object", {foo
:"foo", bar
:42, "extra":true}, schema
);
216 assertNotValid("Object", {foo
:"foo", bar
:42, "extra":"foo"}, schema
,
217 [formatError("invalidType", ["boolean", "string"])]);
219 schema
.properties
.bar
.optional
= true;
220 assertValid("Object", {foo
:"foo", bar
:42}, schema
);
221 assertValid("Object", {foo
:"foo"}, schema
);
222 assertValid("Object", {foo
:"foo", bar
:null}, schema
);
223 assertValid("Object", {foo
:"foo", bar
:undefined}, schema
);
224 assertNotValid("Object", {foo
:"foo", bar
:"42"}, schema
,
225 [formatError("invalidType", ["integer", "string"])]);
228 function testTypeReference() {
229 var referencedTypes
= [
231 id
: "MinLengthString",
252 $ref
: "MinLengthString"
257 var schemaInlineReference
= {
274 // Valid type references externally added.
275 assertValid("", {foo
:"foo",bar
:4,baz
:"ab"}, schema
, referencedTypes
);
277 // Valida type references internally defined.
278 assertValid("", {foo
:"foo",bar
:-4,baz
:-2}, schemaInlineReference
);
280 // Failures in validation, but succesful schema reference.
281 assertNotValid("", {foo
:"foo",bar
:4,baz
:"a"}, schema
,
282 [formatError("stringMinLength", [2])], referencedTypes
);
283 assertNotValid("", {foo
:"foo",bar
:20,baz
:"abc"}, schema
,
284 [formatError("numberMaxValue", [10])], referencedTypes
);
286 // Remove MinLengthString type.
287 referencedTypes
.shift();
288 assertNotValid("", {foo
:"foo",bar
:4,baz
:"ab"}, schema
,
289 [formatError("unknownSchemaReference", ["MinLengthString"])],
292 // Remove internal type "NegativeInt"
293 delete schemaInlineReference
.properties
.bar
;
294 assertNotValid("", {foo
:"foo",baz
:-2}, schemaInlineReference
,
295 [formatError("unknownSchemaReference", ["NegativeInt"])]);
298 function testArrayTuple() {
310 assertValid("Array", ["42", 42], schema
);
311 assertNotValid("Array", ["42", 42, "anything"], schema
,
312 [formatError("arrayMaxItems", [schema
.items
.length
])]);
313 assertNotValid("Array", ["42"], schema
, [formatError("itemRequired")]);
314 assertNotValid("Array", [42, 42], schema
,
315 [formatError("invalidType", ["string", "integer"])]);
317 schema
.additionalProperties
= { type
: "any" };
318 assertValid("Array", ["42", 42, "anything"], schema
);
319 assertValid("Array", ["42", 42, []], schema
);
321 schema
.additionalProperties
= { type
: "boolean" };
322 assertNotValid("Array", ["42", 42, "anything"], schema
,
323 [formatError("invalidType", ["boolean", "string"])]);
324 assertValid("Array", ["42", 42, false], schema
);
326 schema
.items
[0].optional
= true;
327 assertValid("Array", ["42", 42], schema
);
328 assertValid("Array", [, 42], schema
);
329 assertValid("Array", [null, 42], schema
);
330 assertValid("Array", [undefined, 42], schema
);
331 assertNotValid("Array", [42, 42], schema
,
332 [formatError("invalidType", ["string", "integer"])]);
335 function testArrayNonTuple() {
344 assertValid("Array", ["x", "x"], schema
);
345 assertValid("Array", ["x", "x", "x"], schema
);
347 assertNotValid("Array", ["x"], schema
,
348 [formatError("arrayMinItems", [schema
.minItems
])]);
349 assertNotValid("Array", ["x", "x", "x", "x"], schema
,
350 [formatError("arrayMaxItems", [schema
.maxItems
])]);
351 assertNotValid("Array", [42], schema
,
352 [formatError("arrayMinItems", [schema
.minItems
]),
353 formatError("invalidType", ["string", "integer"])]);
356 function testString() {
363 assertValid("String", "x", schema
);
364 assertValid("String", "xxxxxxxxxx", schema
);
366 assertNotValid("String", "y", schema
,
367 [formatError("stringPattern", [schema
.pattern
])]);
368 assertNotValid("String", "xxxxxxxxxxx", schema
,
369 [formatError("stringMaxLength", [schema
.maxLength
])]);
370 assertNotValid("String", "", schema
,
371 [formatError("stringMinLength", [schema
.minLength
]),
372 formatError("stringPattern", [schema
.pattern
])]);
375 function testNumber() {
382 assertValid("Number", 1, schema
);
383 assertValid("Number", 50, schema
);
384 assertValid("Number", 100, schema
);
385 assertValid("Number", 88.88, schema
);
387 assertNotValid("Number", 0.5, schema
,
388 [formatError("numberMinValue", [schema
.minimum
])]);
389 assertNotValid("Number", 100.1, schema
,
390 [formatError("numberMaxValue", [schema
.maximum
])]);
391 assertNotValid("Number", 100.111, schema
,
392 [formatError("numberMaxValue", [schema
.maximum
]),
393 formatError("numberMaxDecimal", [schema
.maxDecimal
])]);
396 AssertTrue(isNaN(nan
));
397 assertNotValid("Number", nan
, schema
,
398 [formatError("numberFiniteNotNan", ["NaN"])]);
400 assertNotValid("Number", Number
.POSITIVE_INFINITY
, schema
,
401 [formatError("numberFiniteNotNan", ["Infinity"]),
402 formatError("numberMaxValue", [schema
.maximum
])
405 assertNotValid("Number", Number
.NEGATIVE_INFINITY
, schema
,
406 [formatError("numberFiniteNotNan", ["-Infinity"]),
407 formatError("numberMinValue", [schema
.minimum
])
411 function testIntegerBounds() {
412 assertValid("Number", 0, {type
:"integer"});
413 assertValid("Number", -1, {type
:"integer"});
414 assertValid("Number", 2147483647, {type
:"integer"});
415 assertValid("Number", -2147483648, {type
:"integer"});
416 assertNotValid("Number", 0.5, {type
:"integer"},
417 [formatError("numberIntValue", [])]);
418 assertNotValid("Number", 10000000000, {type
:"integer"},
419 [formatError("numberIntValue", [])]);
420 assertNotValid("Number", 2147483647.5, {type
:"integer"},
421 [formatError("numberIntValue", [])]);
422 assertNotValid("Number", 2147483648, {type
:"integer"},
423 [formatError("numberIntValue", [])]);
424 assertNotValid("Number", 2147483649, {type
:"integer"},
425 [formatError("numberIntValue", [])]);
426 assertNotValid("Number", -2147483649, {type
:"integer"},
427 [formatError("numberIntValue", [])]);
430 function testType() {
432 assertValid("Type", {}, {type
:"object"});
433 assertValid("Type", [], {type
:"array"});
434 assertValid("Type", function(){}, {type
:"function"});
435 assertValid("Type", "foobar", {type
:"string"});
436 assertValid("Type", "", {type
:"string"});
437 assertValid("Type", 88.8, {type
:"number"});
438 assertValid("Type", 42, {type
:"number"});
439 assertValid("Type", 0, {type
:"number"});
440 assertValid("Type", 42, {type
:"integer"});
441 assertValid("Type", 0, {type
:"integer"});
442 assertValid("Type", true, {type
:"boolean"});
443 assertValid("Type", false, {type
:"boolean"});
444 assertValid("Type", null, {type
:"null"});
445 assertValid("Type", undefined, {type
:"undefined"});
446 assertValid("Type", new ArrayBuffer(1), {type
:"binary"});
447 assertValid("Type", otherContextArrayBufferContainer
.value
, {type
:"binary"});
450 assertNotValid("Type", [], {type
: "object"},
451 [formatError("invalidType", ["object", "array"])]);
452 assertNotValid("Type", null, {type
: "object"},
453 [formatError("invalidType", ["object", "null"])]);
454 assertNotValid("Type", function(){}, {type
: "object"},
455 [formatError("invalidType", ["object", "function"])]);
456 assertNotValid("Type", 42, {type
: "array"},
457 [formatError("invalidType", ["array", "integer"])]);
458 assertNotValid("Type", 42, {type
: "string"},
459 [formatError("invalidType", ["string", "integer"])]);
460 assertNotValid("Type", "42", {type
: "number"},
461 [formatError("invalidType", ["number", "string"])]);
462 assertNotValid("Type", 88.8, {type
: "integer"},
463 [formatError("invalidTypeIntegerNumber")]);
464 assertNotValid("Type", 1, {type
: "boolean"},
465 [formatError("invalidType", ["boolean", "integer"])]);
466 assertNotValid("Type", false, {type
: "null"},
467 [formatError("invalidType", ["null", "boolean"])]);
468 assertNotValid("Type", undefined, {type
: "null"},
469 [formatError("invalidType", ["null", "undefined"])]);
470 assertNotValid("Type", {}, {type
: "function"},
471 [formatError("invalidType", ["function", "object"])]);
474 function testGetAllTypesForSchema() {
475 var referencedTypes
= [
493 var choicesSchema
= {
500 var objectRefSchema
= {
504 var complexSchema
= {
506 { $ref
: "ChoicesRef" },
507 { type
: "function" },
508 { $ref
: "ObjectRef" }
512 var validator
= new JSONSchemaValidator();
513 validator
.addTypes(referencedTypes
);
515 var arraySchemaTypes
= validator
.getAllTypesForSchema(arraySchema
);
516 assertEqualSets(arraySchemaTypes
, ["array"]);
518 var choicesSchemaTypes
= validator
.getAllTypesForSchema(choicesSchema
);
519 assertEqualSets(choicesSchemaTypes
, ["object", "function"]);
521 var objectRefSchemaTypes
= validator
.getAllTypesForSchema(objectRefSchema
);
522 assertEqualSets(objectRefSchemaTypes
, ["object"]);
524 var complexSchemaTypes
= validator
.getAllTypesForSchema(complexSchema
);
525 assertEqualSets(complexSchemaTypes
,
526 ["integer", "string", "function", "object"]);
529 function testIsValidSchemaType() {
530 var referencedTypes
= [
545 var complexSchema
= {
547 { $ref
: "ChoicesRef" },
548 { type
: "function" },
552 var validator
= new JSONSchemaValidator();
553 validator
.addTypes(referencedTypes
);
555 AssertTrue(validator
.isValidSchemaType("object", objectSchema
));
556 AssertTrue(!validator
.isValidSchemaType("integer", objectSchema
));
557 AssertTrue(!validator
.isValidSchemaType("array", objectSchema
));
558 AssertTrue(validator
.isValidSchemaType("null", objectSchema
));
559 AssertTrue(validator
.isValidSchemaType("undefined", objectSchema
));
561 AssertTrue(validator
.isValidSchemaType("integer", complexSchema
));
562 AssertTrue(validator
.isValidSchemaType("function", complexSchema
));
563 AssertTrue(validator
.isValidSchemaType("string", complexSchema
));
564 AssertTrue(!validator
.isValidSchemaType("object", complexSchema
));
565 AssertTrue(!validator
.isValidSchemaType("null", complexSchema
));
566 AssertTrue(!validator
.isValidSchemaType("undefined", complexSchema
));
569 function testCheckSchemaOverlap() {
570 var referencedTypes
= [
588 var choicesSchema
= {
595 var objectRefSchema
= {
599 var complexSchema
= {
601 { $ref
: "ChoicesRef" },
602 { type
: "function" },
603 { $ref
: "ObjectRef" }
607 var validator
= new JSONSchemaValidator();
608 validator
.addTypes(referencedTypes
);
610 AssertTrue(!validator
.checkSchemaOverlap(arraySchema
, choicesSchema
));
611 AssertTrue(!validator
.checkSchemaOverlap(arraySchema
, objectRefSchema
));
612 AssertTrue(!validator
.checkSchemaOverlap(arraySchema
, complexSchema
));
613 AssertTrue(validator
.checkSchemaOverlap(choicesSchema
, objectRefSchema
));
614 AssertTrue(validator
.checkSchemaOverlap(choicesSchema
, complexSchema
));
615 AssertTrue(validator
.checkSchemaOverlap(objectRefSchema
, complexSchema
));
618 function testInstanceOf() {
619 function Animal() {};
622 Cat
.prototype = new Animal
;
623 Cat
.prototype.constructor = Cat
;
624 Dog
.prototype = new Animal
;
625 Dog
.prototype.constructor = Dog
;
628 var num
= new Number(1);
630 // instanceOf should check type by walking up prototype chain.
631 assertValid("", cat
, {type
:"object", isInstanceOf
:"Cat"});
632 assertValid("", cat
, {type
:"object", isInstanceOf
:"Animal"});
633 assertValid("", cat
, {type
:"object", isInstanceOf
:"Object"});
634 assertValid("", dog
, {type
:"object", isInstanceOf
:"Dog"});
635 assertValid("", dog
, {type
:"object", isInstanceOf
:"Animal"});
636 assertValid("", dog
, {type
:"object", isInstanceOf
:"Object"});
637 assertValid("", num
, {type
:"object", isInstanceOf
:"Number"});
638 assertValid("", num
, {type
:"object", isInstanceOf
:"Object"});
640 assertNotValid("", cat
, {type
:"object", isInstanceOf
:"Dog"},
641 [formatError("notInstance", ["Dog"])]);
642 assertNotValid("", dog
, {type
:"object", isInstanceOf
:"Cat"},
643 [formatError("notInstance", ["Cat"])]);
644 assertNotValid("", cat
, {type
:"object", isInstanceOf
:"String"},
645 [formatError("notInstance", ["String"])]);
646 assertNotValid("", dog
, {type
:"object", isInstanceOf
:"String"},
647 [formatError("notInstance", ["String"])]);
648 assertNotValid("", num
, {type
:"object", isInstanceOf
:"Array"},
649 [formatError("notInstance", ["Array"])]);
650 assertNotValid("", num
, {type
:"object", isInstanceOf
:"String"},
651 [formatError("notInstance", ["String"])]);
654 // Tests exposed to schema_unittest.cc.
655 exports
.testFormatError
= testFormatError
;
656 exports
.testComplex
= testComplex
;
657 exports
.testEnum
= testEnum
;
658 exports
.testExtends
= testExtends
;
659 exports
.testObject
= testObject
;
660 exports
.testArrayTuple
= testArrayTuple
;
661 exports
.testArrayNonTuple
= testArrayNonTuple
;
662 exports
.testString
= testString
;
663 exports
.testNumber
= testNumber
;
664 exports
.testIntegerBounds
= testIntegerBounds
;
665 exports
.testType
= testType
;
666 exports
.testTypeReference
= testTypeReference
;
667 exports
.testGetAllTypesForSchema
= testGetAllTypesForSchema
;
668 exports
.testIsValidSchemaType
= testIsValidSchemaType
;
669 exports
.testCheckSchemaOverlap
= testCheckSchemaOverlap
;
670 exports
.testInstanceOf
= testInstanceOf
;