diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/renderer/extensions/json_schema_unittest.cc | 5 | ||||
-rw-r--r-- | chrome/renderer/renderer_resources.grd | 2 | ||||
-rw-r--r-- | chrome/renderer/resources/json_schema.js | 36 | ||||
-rw-r--r-- | chrome/test/data/extensions/json_schema_test.js | 78 |
4 files changed, 118 insertions, 3 deletions
diff --git a/chrome/renderer/extensions/json_schema_unittest.cc b/chrome/renderer/extensions/json_schema_unittest.cc index 7d4073f..9b53094 100644 --- a/chrome/renderer/extensions/json_schema_unittest.cc +++ b/chrome/renderer/extensions/json_schema_unittest.cc @@ -77,3 +77,8 @@ TEST_F(JsonSchemaTest, TestNumber) { TEST_F(JsonSchemaTest, TestType) { TestFunction("testType"); } + +TEST_F(JsonSchemaTest, TestTypeReference) { + TestFunction("testTypeReference"); +} + diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index ec1d32c..5ec2309 100644 --- a/chrome/renderer/renderer_resources.grd +++ b/chrome/renderer/renderer_resources.grd @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- This comment is only here because changes to resources are not picked up -without changes to the corresponding grd file. ek2 --> +without changes to the corresponding grd file. rw --> <grit latest_public_release="0" current_release="1"> <outputs> <output filename="grit/renderer_resources.h" type="rc_header"> diff --git a/chrome/renderer/resources/json_schema.js b/chrome/renderer/resources/json_schema.js index f5d06c6..70dd26f 100644 --- a/chrome/renderer/resources/json_schema.js +++ b/chrome/renderer/resources/json_schema.js @@ -55,6 +55,7 @@ var chrome = chrome || {}; */ chrome.JSONSchemaValidator = function() { this.errors = []; + this.types = []; }; chrome.JSONSchemaValidator.messages = { @@ -74,6 +75,7 @@ chrome.JSONSchemaValidator.messages = { invalidChoice: "Value does not match any valid type choices.", invalidPropertyType: "Missing property type.", schemaRequired: "Schema value required.", + unknownSchemaReference: "Unknown schema reference: *." }; /** @@ -115,6 +117,27 @@ chrome.JSONSchemaValidator.getType = function(value) { }; /** + * Add types that may be referenced by validated schemas that reference them + * with "$ref": <typeId>. Each type must be a valid schema and define an + * "id" property. + */ +chrome.JSONSchemaValidator.prototype.addTypes = function(typeOrTypeList) { + function addType(validator, type) { + if(!type.id) + throw "Attempt to addType with missing 'id' property"; + validator.types[type.id] = type; + } + + if (typeOrTypeList instanceof Array) { + for (var i = 0; i < typeOrTypeList.length; i++) { + addType(this, typeOrTypeList[i]); + } + } else { + addType(this, typeOrTypeList); + } +} + +/** * Validates an instance against a schema. The instance can be any JavaScript * value and will be validated recursively. When this method returns, the * |errors| property will contain a list of errors, if any. @@ -128,10 +151,23 @@ chrome.JSONSchemaValidator.prototype.validate = function(instance, schema, return; } + // If this schema defines itself as reference type, save it in this.types. + if (schema.id) + this.types[schema.id] = schema; + // If the schema has an extends property, the instance must validate against // that schema too. if (schema.extends) this.validate(instance, schema.extends, path); + + // If the schema has a $ref property, the instance must validate against + // that schema too. It must be present in this.types to be referenced. + if (schema["$ref"]) { + if (!this.types[schema["$ref"]]) + this.addError(path, "unknownSchemaReference", [ schema["$ref"] ]); + else + this.validate(instance, this.types[schema["$ref"]], path) + } // If the schema has a choices property, the instance must validate against at // least one of the items in that array. diff --git a/chrome/test/data/extensions/json_schema_test.js b/chrome/test/data/extensions/json_schema_test.js index 195dcba..4231888 100644 --- a/chrome/test/data/extensions/json_schema_test.js +++ b/chrome/test/data/extensions/json_schema_test.js @@ -7,8 +7,10 @@ function assert(truth) { throw new Error("Assertion failed."); } -function assertValid(type, instance, schema) { +function assertValid(type, instance, schema, types) { var validator = new chrome.JSONSchemaValidator(); + if (types) + validator.addTypes(types); validator["validate" + type](instance, schema, ""); if (validator.errors.length != 0) { log("Got unexpected errors"); @@ -17,8 +19,10 @@ function assertValid(type, instance, schema) { } } -function assertNotValid(type, instance, schema, errors) { +function assertNotValid(type, instance, schema, errors, types) { var validator = new chrome.JSONSchemaValidator(); + if (types) + validator.addTypes(types); validator["validate" + type](instance, schema, ""); assert(validator.errors.length === errors.length); for (var i = 0; i < errors.length; i++) { @@ -199,6 +203,76 @@ function testObject() { [formatError("invalidType", ["integer", "string"])]); } +function testTypeReference() { + var referencedTypes = [ + { + id: "MinLengthString", + type: "string", + minLength: 2 + }, + { + id: "Max10Int", + type: "integer", + maximum: 10 + } + ]; + + var schema = { + type: "object", + properties: { + "foo": { + type: "string" + }, + "bar": { + $ref: "Max10Int" + }, + "baz": { + $ref: "MinLengthString" + } + } + }; + + var schemaInlineReference = { + type: "object", + properties: { + "foo": { + type: "string" + }, + "bar": { + id: "NegativeInt", + type: "integer", + maximum: 0 + }, + "baz": { + $ref: "NegativeInt" + } + } + } + + // Valid type references externally added. + assertValid("", {foo:"foo",bar:4,baz:"ab"}, schema, referencedTypes); + + // Valida type references internally defined. + assertValid("", {foo:"foo",bar:-4,baz:-2}, schemaInlineReference); + + // Failures in validation, but succesful schema reference. + assertNotValid("", {foo:"foo",bar:4,baz:"a"}, schema, + [formatError("stringMinLength", [2])], referencedTypes); + assertNotValid("", {foo:"foo",bar:20,baz:"abc"}, schema, + [formatError("numberMaxValue", [10])], referencedTypes); + + // Remove MinLengthString type. + referencedTypes.shift(); + assertNotValid("", {foo:"foo",bar:4,baz:"ab"}, schema, + [formatError("unknownSchemaReference", ["MinLengthString"])], + referencedTypes); + + // Remove internal type "NegativeInt" + delete schemaInlineReference.properties.bar; + assertNotValid("", {foo:"foo",baz:-2}, schemaInlineReference, + [formatError("unknownSchemaReference", ["NegativeInt"])]); +} + function testArrayTuple() { var schema = { items: [ |