diff options
Diffstat (limited to 'extensions/test')
-rw-r--r-- | extensions/test/data/json_schema_test.js | 668 | ||||
-rw-r--r-- | extensions/test/extensions_unittests_main.cc | 17 |
2 files changed, 683 insertions, 2 deletions
diff --git a/extensions/test/data/json_schema_test.js b/extensions/test/data/json_schema_test.js new file mode 100644 index 0000000..645fd9d --- /dev/null +++ b/extensions/test/data/json_schema_test.js @@ -0,0 +1,668 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var AssertTrue = requireNative('assert').AssertTrue; +var JSONSchemaValidator = require('json_schema').JSONSchemaValidator; +var LOG = requireNative('logging').LOG; + +function assertValid(type, instance, schema, types) { + var validator = new JSONSchemaValidator(); + if (types) + validator.addTypes(types); + validator["validate" + type](instance, schema, ""); + var success = true; + if (validator.errors.length != 0) { + LOG("Got unexpected errors"); + for (var i = 0; i < validator.errors.length; i++) { + LOG(validator.errors[i].message + " path: " + validator.errors[i].path); + } + success = false; + } + AssertTrue(success); +} + +function assertNotValid(type, instance, schema, errors, types) { + var validator = new JSONSchemaValidator(); + if (types) + validator.addTypes(types); + validator["validate" + type](instance, schema, ""); + AssertTrue(validator.errors.length === errors.length); + var success = true; + for (var i = 0; i < errors.length; i++) { + if (validator.errors[i].message == errors[i]) { + LOG("Got expected error: " + validator.errors[i].message + + " for path: " + validator.errors[i].path); + } else { + LOG("Missed expected error: " + errors[i] + ". Got: " + + validator.errors[i].message + " instead."); + success = false; + } + } + AssertTrue(success); +} + +function assertListConsistsOfElements(list, elements) { + var success = true; + for (var li = 0; li < list.length; li++) { + for (var ei = 0; ei < elements.length && list[li] != elements[ei]; ei++) { } + if (ei == elements.length) { + LOG("Expected type not found: " + list[li]); + success = false; + } + } + AssertTrue(success); +} + +function assertEqualSets(set1, set2) { + assertListConsistsOfElements(set1, set2); + assertListConsistsOfElements(set2, set1); +} + +function formatError(key, replacements) { + return JSONSchemaValidator.formatError(key, replacements); +} + +function testFormatError() { + AssertTrue(formatError("propertyRequired") == "Property is required."); + AssertTrue(formatError("invalidEnum", ["foo, bar"]) == + "Value must be one of: [foo, bar]."); + AssertTrue(formatError("invalidType", ["foo", "bar"]) == + "Expected 'foo' but got 'bar'."); +} + +function testComplex() { + var schema = { + type: "array", + items: [ + { + type: "object", + properties: { + id: { + type: "integer", + minimum: 1 + }, + url: { + type: "string", + pattern: /^https?\:/, + optional: true + }, + index: { + type: "integer", + minimum: 0, + optional: true + }, + selected: { + type: "boolean", + optional: true + } + } + }, + { type: "function", optional: true }, + { type: "function", optional: true } + ] + }; + + var instance = [ + { + id: 42, + url: "http://www.google.com/", + index: 2, + selected: true + }, + function(){}, + function(){} + ]; + + assertValid("", instance, schema); + instance.length = 2; + assertValid("", instance, schema); + instance.length = 1; + instance.push({}); + assertNotValid("", instance, schema, + [formatError("invalidType", ["function", "object"])]); + instance[1] = function(){}; + + instance[0].url = "foo"; + assertNotValid("", instance, schema, + [formatError("stringPattern", + [schema.items[0].properties.url.pattern])]); + delete instance[0].url; + assertValid("", instance, schema); + + instance[0].id = 0; + assertNotValid("", instance, schema, + [formatError("numberMinValue", + [schema.items[0].properties.id.minimum])]); +} + +function testEnum() { + var schema = { + enum: ["foo", 42, false] + }; + + assertValid("", "foo", schema); + assertValid("", 42, schema); + assertValid("", false, schema); + assertNotValid("", "42", schema, [formatError("invalidEnum", + [schema.enum.join(", ")])]); + assertNotValid("", null, schema, [formatError("invalidEnum", + [schema.enum.join(", ")])]); +} + +function testChoices() { + var schema = { + choices: [ + { type: "null" }, + { type: "undefined" }, + { type: "integer", minimum:42, maximum:42 }, + { type: "object", properties: { foo: { type: "string" } } } + ] + } + assertValid("", null, schema); + assertValid("", undefined, schema); + assertValid("", 42, schema); + assertValid("", {foo: "bar"}, schema); + + assertNotValid("", "foo", schema, [formatError("invalidChoice", [])]); + assertNotValid("", [], schema, [formatError("invalidChoice", [])]); + assertNotValid("", {foo: 42}, schema, [formatError("invalidChoice", [])]); +} + +function testExtends() { + var parent = { + type: "number" + } + var schema = { + extends: parent + }; + + assertValid("", 42, schema); + assertNotValid("", "42", schema, + [formatError("invalidType", ["number", "string"])]); + + // Make the derived schema more restrictive + parent.minimum = 43; + assertNotValid("", 42, schema, [formatError("numberMinValue", [43])]); + assertValid("", 43, schema); +} + +function testObject() { + var schema = { + properties: { + "foo": { + type: "string" + }, + "bar": { + type: "integer" + } + } + }; + + assertValid("Object", {foo:"foo", bar:42}, schema); + assertNotValid("Object", {foo:"foo", bar:42,"extra":true}, schema, + [formatError("unexpectedProperty")]); + assertNotValid("Object", {foo:"foo"}, schema, + [formatError("propertyRequired")]); + assertNotValid("Object", {foo:"foo", bar:"42"}, schema, + [formatError("invalidType", ["integer", "string"])]); + + schema.additionalProperties = { type: "any" }; + assertValid("Object", {foo:"foo", bar:42, "extra":true}, schema); + assertValid("Object", {foo:"foo", bar:42, "extra":"foo"}, schema); + + schema.additionalProperties = { type: "boolean" }; + assertValid("Object", {foo:"foo", bar:42, "extra":true}, schema); + assertNotValid("Object", {foo:"foo", bar:42, "extra":"foo"}, schema, + [formatError("invalidType", ["boolean", "string"])]); + + schema.properties.bar.optional = true; + assertValid("Object", {foo:"foo", bar:42}, schema); + assertValid("Object", {foo:"foo"}, schema); + assertValid("Object", {foo:"foo", bar:null}, schema); + assertValid("Object", {foo:"foo", bar:undefined}, schema); + assertNotValid("Object", {foo:"foo", bar:"42"}, schema, + [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: [ + { + type: "string" + }, + { + type: "integer" + } + ] + }; + + assertValid("Array", ["42", 42], schema); + assertNotValid("Array", ["42", 42, "anything"], schema, + [formatError("arrayMaxItems", [schema.items.length])]); + assertNotValid("Array", ["42"], schema, [formatError("itemRequired")]); + assertNotValid("Array", [42, 42], schema, + [formatError("invalidType", ["string", "integer"])]); + + schema.additionalProperties = { type: "any" }; + assertValid("Array", ["42", 42, "anything"], schema); + assertValid("Array", ["42", 42, []], schema); + + schema.additionalProperties = { type: "boolean" }; + assertNotValid("Array", ["42", 42, "anything"], schema, + [formatError("invalidType", ["boolean", "string"])]); + assertValid("Array", ["42", 42, false], schema); + + schema.items[0].optional = true; + assertValid("Array", ["42", 42], schema); + assertValid("Array", [, 42], schema); + assertValid("Array", [null, 42], schema); + assertValid("Array", [undefined, 42], schema); + assertNotValid("Array", [42, 42], schema, + [formatError("invalidType", ["string", "integer"])]); +} + +function testArrayNonTuple() { + var schema = { + items: { + type: "string" + }, + minItems: 2, + maxItems: 3 + }; + + assertValid("Array", ["x", "x"], schema); + assertValid("Array", ["x", "x", "x"], schema); + + assertNotValid("Array", ["x"], schema, + [formatError("arrayMinItems", [schema.minItems])]); + assertNotValid("Array", ["x", "x", "x", "x"], schema, + [formatError("arrayMaxItems", [schema.maxItems])]); + assertNotValid("Array", [42], schema, + [formatError("arrayMinItems", [schema.minItems]), + formatError("invalidType", ["string", "integer"])]); +} + +function testString() { + var schema = { + minLength: 1, + maxLength: 10, + pattern: /^x/ + }; + + assertValid("String", "x", schema); + assertValid("String", "xxxxxxxxxx", schema); + + assertNotValid("String", "y", schema, + [formatError("stringPattern", [schema.pattern])]); + assertNotValid("String", "xxxxxxxxxxx", schema, + [formatError("stringMaxLength", [schema.maxLength])]); + assertNotValid("String", "", schema, + [formatError("stringMinLength", [schema.minLength]), + formatError("stringPattern", [schema.pattern])]); +} + +function testNumber() { + var schema = { + minimum: 1, + maximum: 100, + maxDecimal: 2 + }; + + assertValid("Number", 1, schema); + assertValid("Number", 50, schema); + assertValid("Number", 100, schema); + assertValid("Number", 88.88, schema); + + assertNotValid("Number", 0.5, schema, + [formatError("numberMinValue", [schema.minimum])]); + assertNotValid("Number", 100.1, schema, + [formatError("numberMaxValue", [schema.maximum])]); + assertNotValid("Number", 100.111, schema, + [formatError("numberMaxValue", [schema.maximum]), + formatError("numberMaxDecimal", [schema.maxDecimal])]); + + var nan = 0/0; + AssertTrue(isNaN(nan)); + assertNotValid("Number", nan, schema, + [formatError("numberFiniteNotNan", ["NaN"])]); + + assertNotValid("Number", Number.POSITIVE_INFINITY, schema, + [formatError("numberFiniteNotNan", ["Infinity"]), + formatError("numberMaxValue", [schema.maximum]) + ]); + + assertNotValid("Number", Number.NEGATIVE_INFINITY, schema, + [formatError("numberFiniteNotNan", ["-Infinity"]), + formatError("numberMinValue", [schema.minimum]) + ]); +} + +function testIntegerBounds() { + assertValid("Number", 0, {type:"integer"}); + assertValid("Number", -1, {type:"integer"}); + assertValid("Number", 2147483647, {type:"integer"}); + assertValid("Number", -2147483648, {type:"integer"}); + assertNotValid("Number", 0.5, {type:"integer"}, + [formatError("numberIntValue", [])]); + assertNotValid("Number", 10000000000, {type:"integer"}, + [formatError("numberIntValue", [])]); + assertNotValid("Number", 2147483647.5, {type:"integer"}, + [formatError("numberIntValue", [])]); + assertNotValid("Number", 2147483648, {type:"integer"}, + [formatError("numberIntValue", [])]); + assertNotValid("Number", 2147483649, {type:"integer"}, + [formatError("numberIntValue", [])]); + assertNotValid("Number", -2147483649, {type:"integer"}, + [formatError("numberIntValue", [])]); +} + +function testType() { + // valid + assertValid("Type", {}, {type:"object"}); + assertValid("Type", [], {type:"array"}); + assertValid("Type", function(){}, {type:"function"}); + assertValid("Type", "foobar", {type:"string"}); + assertValid("Type", "", {type:"string"}); + assertValid("Type", 88.8, {type:"number"}); + assertValid("Type", 42, {type:"number"}); + assertValid("Type", 0, {type:"number"}); + assertValid("Type", 42, {type:"integer"}); + assertValid("Type", 0, {type:"integer"}); + assertValid("Type", true, {type:"boolean"}); + assertValid("Type", false, {type:"boolean"}); + assertValid("Type", null, {type:"null"}); + assertValid("Type", undefined, {type:"undefined"}); + + // not valid + assertNotValid("Type", [], {type: "object"}, + [formatError("invalidType", ["object", "array"])]); + assertNotValid("Type", null, {type: "object"}, + [formatError("invalidType", ["object", "null"])]); + assertNotValid("Type", function(){}, {type: "object"}, + [formatError("invalidType", ["object", "function"])]); + assertNotValid("Type", 42, {type: "array"}, + [formatError("invalidType", ["array", "integer"])]); + assertNotValid("Type", 42, {type: "string"}, + [formatError("invalidType", ["string", "integer"])]); + assertNotValid("Type", "42", {type: "number"}, + [formatError("invalidType", ["number", "string"])]); + assertNotValid("Type", 88.8, {type: "integer"}, + [formatError("invalidTypeIntegerNumber")]); + assertNotValid("Type", 1, {type: "boolean"}, + [formatError("invalidType", ["boolean", "integer"])]); + assertNotValid("Type", false, {type: "null"}, + [formatError("invalidType", ["null", "boolean"])]); + assertNotValid("Type", undefined, {type: "null"}, + [formatError("invalidType", ["null", "undefined"])]); + assertNotValid("Type", {}, {type: "function"}, + [formatError("invalidType", ["function", "object"])]); +} + +function testGetAllTypesForSchema() { + var referencedTypes = [ + { + id: "ChoicesRef", + choices: [ + { type: "integer" }, + { type: "string" } + ] + }, + { + id: "ObjectRef", + type: "object", + } + ]; + + var arraySchema = { + type: "array" + }; + + var choicesSchema = { + choices: [ + { type: "object" }, + { type: "function" } + ] + }; + + var objectRefSchema = { + $ref: "ObjectRef" + }; + + var complexSchema = { + choices: [ + { $ref: "ChoicesRef" }, + { type: "function" }, + { $ref: "ObjectRef" } + ] + }; + + var validator = new JSONSchemaValidator(); + validator.addTypes(referencedTypes); + + var arraySchemaTypes = validator.getAllTypesForSchema(arraySchema); + assertEqualSets(arraySchemaTypes, ["array"]); + + var choicesSchemaTypes = validator.getAllTypesForSchema(choicesSchema); + assertEqualSets(choicesSchemaTypes, ["object", "function"]); + + var objectRefSchemaTypes = validator.getAllTypesForSchema(objectRefSchema); + assertEqualSets(objectRefSchemaTypes, ["object"]); + + var complexSchemaTypes = validator.getAllTypesForSchema(complexSchema); + assertEqualSets(complexSchemaTypes, + ["integer", "string", "function", "object"]); +} + +function testIsValidSchemaType() { + var referencedTypes = [ + { + id: "ChoicesRef", + choices: [ + { type: "integer" }, + { type: "string" } + ] + } + ]; + + var objectSchema = { + type: "object", + optional: true + }; + + var complexSchema = { + choices: [ + { $ref: "ChoicesRef" }, + { type: "function" }, + ] + }; + + var validator = new JSONSchemaValidator(); + validator.addTypes(referencedTypes); + + AssertTrue(validator.isValidSchemaType("object", objectSchema)); + AssertTrue(!validator.isValidSchemaType("integer", objectSchema)); + AssertTrue(!validator.isValidSchemaType("array", objectSchema)); + AssertTrue(validator.isValidSchemaType("null", objectSchema)); + AssertTrue(validator.isValidSchemaType("undefined", objectSchema)); + + AssertTrue(validator.isValidSchemaType("integer", complexSchema)); + AssertTrue(validator.isValidSchemaType("function", complexSchema)); + AssertTrue(validator.isValidSchemaType("string", complexSchema)); + AssertTrue(!validator.isValidSchemaType("object", complexSchema)); + AssertTrue(!validator.isValidSchemaType("null", complexSchema)); + AssertTrue(!validator.isValidSchemaType("undefined", complexSchema)); +} + +function testCheckSchemaOverlap() { + var referencedTypes = [ + { + id: "ChoicesRef", + choices: [ + { type: "integer" }, + { type: "string" } + ] + }, + { + id: "ObjectRef", + type: "object", + } + ]; + + var arraySchema = { + type: "array" + }; + + var choicesSchema = { + choices: [ + { type: "object" }, + { type: "function" } + ] + }; + + var objectRefSchema = { + $ref: "ObjectRef" + }; + + var complexSchema = { + choices: [ + { $ref: "ChoicesRef" }, + { type: "function" }, + { $ref: "ObjectRef" } + ] + }; + + var validator = new JSONSchemaValidator(); + validator.addTypes(referencedTypes); + + AssertTrue(!validator.checkSchemaOverlap(arraySchema, choicesSchema)); + AssertTrue(!validator.checkSchemaOverlap(arraySchema, objectRefSchema)); + AssertTrue(!validator.checkSchemaOverlap(arraySchema, complexSchema)); + AssertTrue(validator.checkSchemaOverlap(choicesSchema, objectRefSchema)); + AssertTrue(validator.checkSchemaOverlap(choicesSchema, complexSchema)); + AssertTrue(validator.checkSchemaOverlap(objectRefSchema, complexSchema)); +} + +function testInstanceOf() { + function Animal() {}; + function Cat() {}; + function Dog() {}; + Cat.prototype = new Animal; + Cat.prototype.constructor = Cat; + Dog.prototype = new Animal; + Dog.prototype.constructor = Dog; + var cat = new Cat(); + var dog = new Dog(); + var num = new Number(1); + + // instanceOf should check type by walking up prototype chain. + assertValid("", cat, {type:"object", isInstanceOf:"Cat"}); + assertValid("", cat, {type:"object", isInstanceOf:"Animal"}); + assertValid("", cat, {type:"object", isInstanceOf:"Object"}); + assertValid("", dog, {type:"object", isInstanceOf:"Dog"}); + assertValid("", dog, {type:"object", isInstanceOf:"Animal"}); + assertValid("", dog, {type:"object", isInstanceOf:"Object"}); + assertValid("", num, {type:"object", isInstanceOf:"Number"}); + assertValid("", num, {type:"object", isInstanceOf:"Object"}); + + assertNotValid("", cat, {type:"object", isInstanceOf:"Dog"}, + [formatError("notInstance", ["Dog"])]); + assertNotValid("", dog, {type:"object", isInstanceOf:"Cat"}, + [formatError("notInstance", ["Cat"])]); + assertNotValid("", cat, {type:"object", isInstanceOf:"String"}, + [formatError("notInstance", ["String"])]); + assertNotValid("", dog, {type:"object", isInstanceOf:"String"}, + [formatError("notInstance", ["String"])]); + assertNotValid("", num, {type:"object", isInstanceOf:"Array"}, + [formatError("notInstance", ["Array"])]); + assertNotValid("", num, {type:"object", isInstanceOf:"String"}, + [formatError("notInstance", ["String"])]); +} + +// Tests exposed to schema_unittest.cc. +exports.testFormatError = testFormatError; +exports.testComplex = testComplex; +exports.testEnum = testEnum; +exports.testExtends = testExtends; +exports.testObject = testObject; +exports.testArrayTuple = testArrayTuple; +exports.testArrayNonTuple = testArrayNonTuple; +exports.testString = testString; +exports.testNumber = testNumber; +exports.testIntegerBounds = testIntegerBounds; +exports.testType = testType; +exports.testTypeReference = testTypeReference; +exports.testGetAllTypesForSchema = testGetAllTypesForSchema; +exports.testIsValidSchemaType = testIsValidSchemaType; +exports.testCheckSchemaOverlap = testCheckSchemaOverlap; +exports.testInstanceOf = testInstanceOf; diff --git a/extensions/test/extensions_unittests_main.cc b/extensions/test/extensions_unittests_main.cc index 78b0a8d..bc7afc5 100644 --- a/extensions/test/extensions_unittests_main.cc +++ b/extensions/test/extensions_unittests_main.cc @@ -2,11 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/base_paths.h" #include "base/bind.h" #include "base/macros.h" +#include "base/path_service.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" +#include "content/public/test/unittest_test_suite.h" +#include "extensions/common/extension_paths.h" #include "extensions/test/test_extensions_client.h" +#include "ui/base/resource/resource_bundle.h" namespace { @@ -30,21 +35,29 @@ ExtensionsTestSuite::ExtensionsTestSuite(int argc, char** argv) void ExtensionsTestSuite::Initialize() { base::TestSuite::Initialize(); + extensions::RegisterPathProvider(); + + base::FilePath resources_pack_path; + PathService::Get(base::DIR_MODULE, &resources_pack_path); + ResourceBundle::InitSharedInstanceWithPakPath( + resources_pack_path.AppendASCII("extensions_unittests_resources.pak")); + client_.reset(new extensions::TestExtensionsClient()); extensions::ExtensionsClient::Set(client_.get()); } void ExtensionsTestSuite::Shutdown() { + ResourceBundle::CleanupSharedInstance(); base::TestSuite::Shutdown(); } } // namespace int main(int argc, char** argv) { - ExtensionsTestSuite test_suite(argc, argv); + content::UnitTestTestSuite test_suite(new ExtensionsTestSuite(argc, argv)); return base::LaunchUnitTests(argc, argv, - base::Bind(&ExtensionsTestSuite::Run, + base::Bind(&content::UnitTestTestSuite::Run, base::Unretained(&test_suite))); } |