fune/toolkit/components/utils/test/browser/browser_JsonSchemaValidator.js
Felipe Gomes db8dc29d5f Bug 1467593 - Support non-strict arrays in the JsonSchemaValidator. r=mythmon
An array specified with strict=false will not fail validation if there are invalid values. It simply will ignore those values and not include them in the output.

If strict is missing, it defaults to true.

MozReview-Commit-ID: 7hAs0IsnL9v

--HG--
extra : rebase_source : 1dc1e1a31713396ea20b9b7313a69803fbbb3ca0
2018-06-29 15:50:20 -03:00

398 lines
14 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
ChromeUtils.import("resource://gre/modules/components-utils/JsonSchemaValidator.jsm", this);
add_task(async function test_boolean_values() {
let schema = {
type: "boolean"
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(true, schema);
ok(valid && parsed === true, "Parsed boolean value correctly");
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(false, schema);
ok(valid && parsed === false, "Parsed boolean value correctly");
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(0, schema);
ok(valid && parsed === false, "0 parsed as false correctly");
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(1, schema);
ok(valid && parsed === true, "1 parsed as true correctly");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters("0", schema)[0], "No type coercion");
ok(!JsonSchemaValidator.validateAndParseParameters("true", schema)[0], "No type coercion");
ok(!JsonSchemaValidator.validateAndParseParameters(2, schema)[0], "Other number values are not valid");
ok(!JsonSchemaValidator.validateAndParseParameters(undefined, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters(null, schema)[0], "Invalid value");
});
add_task(async function test_number_values() {
let schema = {
type: "number"
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(1, schema);
ok(valid && parsed === 1, "Parsed number value correctly");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters("1", schema)[0], "No type coercion");
ok(!JsonSchemaValidator.validateAndParseParameters(true, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters(null, schema)[0], "Invalid value");
});
add_task(async function test_integer_values() {
// Integer is an alias for number
let schema = {
type: "integer"
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(1, schema);
ok(valid && parsed == 1, "Parsed integer value correctly");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters("1", schema)[0], "No type coercion");
ok(!JsonSchemaValidator.validateAndParseParameters(true, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters(null, schema)[0], "Invalid value");
});
add_task(async function test_string_values() {
let schema = {
type: "string"
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters("foobar", schema);
ok(valid && parsed == "foobar", "Parsed string value correctly");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters(1, schema)[0], "No type coercion");
ok(!JsonSchemaValidator.validateAndParseParameters(true, schema)[0], "No type coercion");
ok(!JsonSchemaValidator.validateAndParseParameters(undefined, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters(null, schema)[0], "Invalid value");
});
add_task(async function test_URL_values() {
let schema = {
type: "URL"
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters("https://www.example.com/foo#bar", schema);
ok(valid, "URL is valid");
ok(parsed instanceof URL, "parsed is a URL");
is(parsed.origin, "https://www.example.com", "origin is correct");
is(parsed.pathname + parsed.hash, "/foo#bar", "pathname is correct");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters("", schema)[0], "Empty string is not accepted for URL");
ok(!JsonSchemaValidator.validateAndParseParameters("www.example.com", schema)[0], "Scheme is required for URL");
ok(!JsonSchemaValidator.validateAndParseParameters("https://:!$%", schema)[0], "Invalid URL");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
});
add_task(async function test_URLorEmpty_values() {
let schema = {
type: "URLorEmpty"
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters("https://www.example.com/foo#bar", schema);
ok(valid, "URL is valid");
ok(parsed instanceof URL, "parsed is a nsIURI");
is(parsed.origin, "https://www.example.com", "origin is correct");
is(parsed.pathname + parsed.hash, "/foo#bar", "pathname is correct");
// Test that this type also accept empty strings
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters("", schema);
ok(valid, "URLorEmpty is valid");
ok(!parsed, "parsed value is falsy");
is(typeof(parsed), "string", "parsed is a string");
is(parsed, "", "parsed is an empty string");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters(" ", schema)[0], "Non-empty string is not accepted");
ok(!JsonSchemaValidator.validateAndParseParameters("www.example.com", schema)[0], "Scheme is required for URL");
ok(!JsonSchemaValidator.validateAndParseParameters("https://:!$%", schema)[0], "Invalid URL");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
});
add_task(async function test_origin_values() {
// Origin is a URL that doesn't contain a path/query string (i.e., it's only scheme + host + port)
let schema = {
type: "origin"
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters("https://www.example.com", schema);
ok(valid, "Origin is valid");
ok(parsed instanceof URL, "parsed is a nsIURI");
is(parsed.origin, "https://www.example.com", "origin is correct");
is(parsed.pathname + parsed.hash, "/", "pathname is corect");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters("https://www.example.com/foobar", schema)[0], "Origin cannot contain a path part");
ok(!JsonSchemaValidator.validateAndParseParameters("https://:!$%", schema)[0], "Invalid origin");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
});
add_task(async function test_array_values() {
// The types inside an array object must all be the same
let schema = {
type: "array",
items: {
type: "number"
}
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters([1, 2, 3], schema);
ok(valid, "Array is valid");
ok(Array.isArray(parsed), "parsed is an array");
is(parsed.length, 3, "array is correct");
// An empty array is also valid
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters([], schema);
ok(valid, "Array is valid");
ok(Array.isArray(parsed), "parsed is an array");
is(parsed.length, 0, "array is correct");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters([1, true, 3], schema)[0], "Mixed types");
ok(!JsonSchemaValidator.validateAndParseParameters(2, schema)[0], "Type is correct but not in an array");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Object is not an array");
});
add_task(async function test_non_strict_arrays() {
// Non-srict arrays ignores invalid values (don't include
// them in the parsed output), instead of failing the validation.
// Note: invalid values might still report errors to the console.
let schema = {
type: "array",
strict: false,
items: {
type: "string"
}
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(
["valid1", "valid2", false, 3, "valid3"], schema);
ok(valid, "Array is valid");
ok(Array.isArray(parsed, "parsed is an array"));
is(parsed.length, 3, "Only valid values were included in the parsed array");
Assert.deepEqual(parsed, ["valid1", "valid2", "valid3"], "Results were expected");
// Checks that strict defaults to true;
delete schema.strict;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(
["valid1", "valid2", false, 3, "valid3"], schema);
ok(!valid, "Same verification was invalid without strict=false");
});
add_task(async function test_object_values() {
let schema = {
type: "object",
properties: {
url: {
type: "URL"
},
title: {
type: "string"
}
}
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(
{
url: "https://www.example.com/foo#bar",
title: "Foo",
alias: "Bar"
},
schema);
ok(valid, "Object is valid");
ok(typeof(parsed) == "object", "parsed in an object");
ok(parsed.url instanceof URL, "types inside the object are also parsed");
is(parsed.url.href, "https://www.example.com/foo#bar", "URL was correctly parsed");
is(parsed.title, "Foo", "title was correctly parsed");
is(parsed.alias, undefined, "property not described in the schema is not present in the parsed object");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters(
{
url: "https://www.example.com/foo#bar",
title: 3,
},
schema)[0], "Mismatched type for title");
ok(!JsonSchemaValidator.validateAndParseParameters(
{
url: "www.example.com",
title: 3,
},
schema)[0], "Invalid URL inside the object");
});
add_task(async function test_array_of_objects() {
// This schema is used, for example, for bookmarks
let schema = {
type: "array",
items: {
type: "object",
properties: {
url: {
type: "URL",
},
title: {
type: "string"
}
}
}
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(
[{
url: "https://www.example.com/bookmark1",
title: "Foo",
},
{
url: "https://www.example.com/bookmark2",
title: "Bar",
}],
schema);
ok(valid, "Array is valid");
is(parsed.length, 2, "Correct number of items");
ok(typeof(parsed[0]) == "object" && typeof(parsed[1]) == "object", "Correct objects inside array");
is(parsed[0].url.href, "https://www.example.com/bookmark1", "Correct URL for bookmark 1");
is(parsed[1].url.href, "https://www.example.com/bookmark2", "Correct URL for bookmark 2");
is(parsed[0].title, "Foo", "Correct title for bookmark 1");
is(parsed[1].title, "Bar", "Correct title for bookmark 2");
});
add_task(async function test_missing_arrays_inside_objects() {
let schema = {
type: "object",
properties: {
allow: {
type: "array",
items: {
type: "boolean"
}
},
block: {
type: "array",
items: {
type: "boolean"
}
}
}
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters({
allow: [true, true, true]
}, schema);
ok(valid, "Object is valid");
is(parsed.allow.length, 3, "Allow array is correct.");
is(parsed.block, undefined, "Block array is undefined, as expected.");
});
add_task(async function test_required_vs_nonrequired_properties() {
let schema = {
type: "object",
properties: {
"non-required-property": {
type: "number"
},
"required-property": {
type: "number"
}
},
required: ["required-property"]
};
let valid, parsed;
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters({
"required-property": 5
}, schema);
ok(valid, "Object is valid since required property is present");
is(parsed["required-property"], 5, "required property is correct");
is(parsed["non-required-property"], undefined, "non-required property is undefined, as expected");
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters({
"non-required-property": 5
}, schema);
ok(!valid, "Object is not valid since the required property is missing");
is(parsed, null, "Nothing was returned as parsed");
});
add_task(async function test_number_or_string_values() {
let schema = {
type: ["number", "string"],
};
let valid, parsed;
// valid values
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(1, schema);
ok(valid && parsed === 1, "Parsed number value correctly");
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters("foobar", schema);
ok(valid && parsed === "foobar", "Parsed string value correctly");
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters("1", schema);
ok(valid && parsed === "1", "Did not coerce string to number");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters(true, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters(null, schema)[0], "Invalid value");
});
add_task(async function test_number_or_array_values() {
let schema = {
type: ["number", "array"],
items: {
type: "number",
}
};
let valid, parsed;
// valid values
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters(1, schema);
ok(valid, "Number is valid");
is(parsed, 1, "Parsed correctly");
ok(valid && parsed === 1, "Parsed number value correctly");
[valid, parsed] = JsonSchemaValidator.validateAndParseParameters([1, 2, 3], schema);
ok(valid, "Array is valid");
Assert.deepEqual(parsed, [1, 2, 3], "Parsed correctly");
// Invalid values:
ok(!JsonSchemaValidator.validateAndParseParameters(true, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters({}, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters(null, schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters(["a", "b"], schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters([[]], schema)[0], "Invalid value");
ok(!JsonSchemaValidator.validateAndParseParameters([0, 1, [2, 3]], schema)[0], "Invalid value");
});