1990 lines
41 KiB
JavaScript
1990 lines
41 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const { JsonSchemaValidator } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/components-utils/JsonSchemaValidator.sys.mjs"
|
|
);
|
|
|
|
add_task(async function test_boolean_values() {
|
|
let schema = {
|
|
type: "boolean",
|
|
};
|
|
|
|
// valid values
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: true,
|
|
},
|
|
});
|
|
validate({
|
|
value: false,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: false,
|
|
},
|
|
});
|
|
validate({
|
|
value: 0,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: false,
|
|
},
|
|
});
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: true,
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: "0",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "0",
|
|
error: {
|
|
invalidValue: "0",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '"0"' does not match the expected type 'boolean'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "true",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "true",
|
|
error: {
|
|
invalidValue: "true",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '"true"' does not match the expected type 'boolean'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: 2,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: 2,
|
|
error: {
|
|
invalidValue: 2,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '2' does not match the expected type 'boolean'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: undefined,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: undefined,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'undefined' does not match the expected type 'boolean'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: {},
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'boolean'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: null,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: null,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'null' does not match the expected type 'boolean'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_number_values() {
|
|
let schema = {
|
|
type: "number",
|
|
};
|
|
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: 1,
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: "1",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "1",
|
|
error: {
|
|
invalidValue: "1",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '"1"' does not match the expected type 'number'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: true,
|
|
error: {
|
|
invalidValue: true,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'true' does not match the expected type 'number'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: {},
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'number'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: null,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: null,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'null' does not match the expected type 'number'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_integer_values() {
|
|
// Integer is an alias for number
|
|
let schema = {
|
|
type: "integer",
|
|
};
|
|
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: 1,
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: "1",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "1",
|
|
error: {
|
|
invalidValue: "1",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '"1"' does not match the expected type 'integer'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: true,
|
|
error: {
|
|
invalidValue: true,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'true' does not match the expected type 'integer'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: {},
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'integer'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: null,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: null,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'null' does not match the expected type 'integer'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_null_values() {
|
|
let schema = {
|
|
type: "null",
|
|
};
|
|
|
|
validate({
|
|
value: null,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: null,
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: 1,
|
|
error: {
|
|
invalidValue: 1,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '1' does not match the expected type 'null'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "1",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "1",
|
|
error: {
|
|
invalidValue: "1",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '"1"' does not match the expected type 'null'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: true,
|
|
error: {
|
|
invalidValue: true,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'true' does not match the expected type 'null'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: {},
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'null'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: [],
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: [],
|
|
error: {
|
|
invalidValue: [],
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '[]' does not match the expected type 'null'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_string_values() {
|
|
let schema = {
|
|
type: "string",
|
|
};
|
|
|
|
validate({
|
|
value: "foobar",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: "foobar",
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: 1,
|
|
error: {
|
|
invalidValue: 1,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '1' does not match the expected type 'string'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: true,
|
|
error: {
|
|
invalidValue: true,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'true' does not match the expected type 'string'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: undefined,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: undefined,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'undefined' does not match the expected type 'string'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: {},
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'string'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: null,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: null,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'null' does not match the expected type 'string'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_URL_values() {
|
|
let schema = {
|
|
type: "URL",
|
|
};
|
|
|
|
let result = validate({
|
|
value: "https://www.example.com/foo#bar",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: new URL("https://www.example.com/foo#bar"),
|
|
},
|
|
});
|
|
Assert.ok(URL.isInstance(result.parsedValue), "parsedValue is a URL");
|
|
Assert.equal(
|
|
result.parsedValue.origin,
|
|
"https://www.example.com",
|
|
"origin is correct"
|
|
);
|
|
Assert.equal(
|
|
result.parsedValue.pathname + result.parsedValue.hash,
|
|
"/foo#bar",
|
|
"pathname is correct"
|
|
);
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: "",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "",
|
|
error: {
|
|
invalidValue: "",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '""' does not match the expected type 'URL'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "www.example.com",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "www.example.com",
|
|
error: {
|
|
invalidValue: "www.example.com",
|
|
invalidPropertyNameComponents: [],
|
|
message:
|
|
`The value '"www.example.com"' does not match the expected ` +
|
|
`type 'URL'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "https://:!$%",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "https://:!$%",
|
|
error: {
|
|
invalidValue: "https://:!$%",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '"https://:!$%"' does not match the expected type 'URL'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: {},
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'URL'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_URLorEmpty_values() {
|
|
let schema = {
|
|
type: "URLorEmpty",
|
|
};
|
|
|
|
let result = validate({
|
|
value: "https://www.example.com/foo#bar",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: new URL("https://www.example.com/foo#bar"),
|
|
},
|
|
});
|
|
Assert.ok(URL.isInstance(result.parsedValue), "parsedValue is a URL");
|
|
Assert.equal(
|
|
result.parsedValue.origin,
|
|
"https://www.example.com",
|
|
"origin is correct"
|
|
);
|
|
Assert.equal(
|
|
result.parsedValue.pathname + result.parsedValue.hash,
|
|
"/foo#bar",
|
|
"pathname is correct"
|
|
);
|
|
|
|
// Test that this type also accept empty strings
|
|
result = validate({
|
|
value: "",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: "",
|
|
},
|
|
});
|
|
Assert.equal(typeof result.parsedValue, "string", "parsedValue is a string");
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: " ",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: " ",
|
|
error: {
|
|
invalidValue: " ",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '" "' does not match the expected type 'URLorEmpty'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "www.example.com",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "www.example.com",
|
|
error: {
|
|
invalidValue: "www.example.com",
|
|
invalidPropertyNameComponents: [],
|
|
message:
|
|
`The value '"www.example.com"' does not match the expected ` +
|
|
`type 'URLorEmpty'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "https://:!$%",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "https://:!$%",
|
|
error: {
|
|
invalidValue: "https://:!$%",
|
|
invalidPropertyNameComponents: [],
|
|
message:
|
|
`The value '"https://:!$%"' does not match the expected ` +
|
|
`type 'URLorEmpty'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: {},
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'URLorEmpty'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
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 result = validate({
|
|
value: "https://www.example.com",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: new URL("https://www.example.com/"),
|
|
},
|
|
});
|
|
Assert.ok(URL.isInstance(result.parsedValue), "parsedValue is a URL");
|
|
Assert.equal(
|
|
result.parsedValue.origin,
|
|
"https://www.example.com",
|
|
"origin is correct"
|
|
);
|
|
Assert.equal(
|
|
result.parsedValue.pathname + result.parsedValue.hash,
|
|
"/",
|
|
"pathname is correct"
|
|
);
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: "https://www.example.com/foobar",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: new URL("https://www.example.com/foobar"),
|
|
error: {
|
|
invalidValue: "https://www.example.com/foobar",
|
|
invalidPropertyNameComponents: [],
|
|
message:
|
|
`The value '"https://www.example.com/foobar"' does not match the ` +
|
|
`expected type 'origin'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "https://:!$%",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "https://:!$%",
|
|
error: {
|
|
invalidValue: "https://:!$%",
|
|
invalidPropertyNameComponents: [],
|
|
message:
|
|
`The value '"https://:!$%"' does not match the expected ` +
|
|
`type 'origin'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: {},
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'origin'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_origin_file_values() {
|
|
// File URLs can also be origins
|
|
let schema = {
|
|
type: "origin",
|
|
};
|
|
|
|
let result = validate({
|
|
value: "file:///foo/bar",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: new URL("file:///foo/bar"),
|
|
},
|
|
});
|
|
Assert.ok(URL.isInstance(result.parsedValue), "parsedValue is a URL");
|
|
Assert.equal(
|
|
result.parsedValue.href,
|
|
"file:///foo/bar",
|
|
"Should get what we passed in"
|
|
);
|
|
});
|
|
|
|
add_task(async function test_origin_file_values() {
|
|
// File URLs can also be origins
|
|
let schema = {
|
|
type: "origin",
|
|
};
|
|
|
|
let result = validate({
|
|
value: "file:///foo/bar/foobar.html",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: new URL("file:///foo/bar/foobar.html"),
|
|
},
|
|
});
|
|
Assert.ok(URL.isInstance(result.parsedValue), "parsedValue is a URL");
|
|
Assert.equal(
|
|
result.parsedValue.href,
|
|
"file:///foo/bar/foobar.html",
|
|
"Should get what we passed in"
|
|
);
|
|
});
|
|
|
|
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",
|
|
},
|
|
};
|
|
|
|
validate({
|
|
value: [1, 2, 3],
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: [1, 2, 3],
|
|
},
|
|
});
|
|
|
|
// An empty array is also valid
|
|
validate({
|
|
value: [],
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: [],
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: [1, true, 3],
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: true,
|
|
error: {
|
|
invalidValue: true,
|
|
invalidPropertyNameComponents: [1],
|
|
message:
|
|
`The value 'true' does not match the expected type 'number'. The ` +
|
|
`invalid value is property '1' in [1,true,3]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: 2,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: 2,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '2' does not match the expected type 'array'`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match the expected type 'array'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_non_strict_arrays() {
|
|
// Non-strict 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",
|
|
},
|
|
};
|
|
|
|
validate({
|
|
value: ["valid1", "valid2", false, 3, "valid3"],
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: ["valid1", "valid2", "valid3"],
|
|
},
|
|
});
|
|
|
|
// Checks that strict defaults to true;
|
|
delete schema.strict;
|
|
validate({
|
|
value: ["valid1", "valid2", false, 3, "valid3"],
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: false,
|
|
error: {
|
|
invalidValue: false,
|
|
invalidPropertyNameComponents: [2],
|
|
message:
|
|
`The value 'false' does not match the expected type 'string'. The ` +
|
|
`invalid value is property '2' in ` +
|
|
`["valid1","valid2",false,3,"valid3"]`,
|
|
},
|
|
},
|
|
});
|
|
|
|
// Pass allowArrayNonMatchingItems, should be valid
|
|
validate({
|
|
value: ["valid1", "valid2", false, 3, "valid3"],
|
|
schema,
|
|
options: {
|
|
allowArrayNonMatchingItems: true,
|
|
},
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: ["valid1", "valid2", "valid3"],
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_object_values() {
|
|
// valid values below
|
|
|
|
validate({
|
|
value: {
|
|
foo: "hello",
|
|
bar: 123,
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
bar: {
|
|
type: "number",
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
foo: "hello",
|
|
bar: 123,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
foo: "hello",
|
|
bar: {
|
|
baz: 123,
|
|
},
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
bar: {
|
|
type: "object",
|
|
properties: {
|
|
baz: {
|
|
type: "number",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
foo: "hello",
|
|
bar: {
|
|
baz: 123,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
foo: "hello",
|
|
bar: 123,
|
|
baz: "an additional property",
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
additionalProperties: true,
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
bar: {
|
|
type: "number",
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
foo: "hello",
|
|
bar: 123,
|
|
},
|
|
},
|
|
});
|
|
|
|
// allowAdditionalProperties
|
|
let result = validate({
|
|
value: {
|
|
url: "https://www.example.com/foo#bar",
|
|
title: "Foo",
|
|
alias: "Bar",
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
url: {
|
|
type: "URL",
|
|
},
|
|
title: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
options: {
|
|
allowAdditionalProperties: true,
|
|
},
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
url: new URL("https://www.example.com/foo#bar"),
|
|
title: "Foo",
|
|
},
|
|
},
|
|
});
|
|
Assert.ok(
|
|
URL.isInstance(result.parsedValue.url),
|
|
"types inside the object are also parsed"
|
|
);
|
|
Assert.equal(
|
|
result.parsedValue.url.href,
|
|
"https://www.example.com/foo#bar",
|
|
"URL was correctly parsed"
|
|
);
|
|
|
|
// allowExplicitUndefinedProperties
|
|
validate({
|
|
value: {
|
|
foo: undefined,
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
options: {
|
|
allowExplicitUndefinedProperties: true,
|
|
},
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {},
|
|
},
|
|
});
|
|
|
|
// allowNullAsUndefinedProperties
|
|
validate({
|
|
value: {
|
|
foo: null,
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
options: {
|
|
allowNullAsUndefinedProperties: true,
|
|
},
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {},
|
|
},
|
|
});
|
|
|
|
// invalid values below
|
|
|
|
validate({
|
|
value: null,
|
|
schema: {
|
|
type: "object",
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: null,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'null' does not match the expected type 'object'`,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
url: "not a URL",
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
url: {
|
|
type: "URL",
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "not a URL",
|
|
error: {
|
|
invalidValue: "not a URL",
|
|
invalidPropertyNameComponents: ["url"],
|
|
message:
|
|
`The value '"not a URL"' does not match the expected type 'URL'. ` +
|
|
`The invalid value is property 'url' in {"url":"not a URL"}`,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: "test",
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
error: {
|
|
invalidValue: "test",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '"test"' does not match the expected type 'object'`,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
foo: 123,
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: 123,
|
|
error: {
|
|
invalidValue: 123,
|
|
invalidPropertyNameComponents: ["foo"],
|
|
message:
|
|
`The value '123' does not match the expected type 'string'. ` +
|
|
`The invalid value is property 'foo' in {"foo":123}`,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
foo: {
|
|
bar: 456,
|
|
},
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "object",
|
|
properties: {
|
|
bar: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: 456,
|
|
error: {
|
|
invalidValue: 456,
|
|
invalidPropertyNameComponents: ["foo", "bar"],
|
|
message:
|
|
`The value '456' does not match the expected type 'string'. ` +
|
|
`The invalid value is property 'foo.bar' in {"foo":{"bar":456}}`,
|
|
},
|
|
},
|
|
});
|
|
|
|
// null non-required property with strict=true: invalid
|
|
validate({
|
|
value: {
|
|
foo: null,
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: null,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: ["foo"],
|
|
message:
|
|
`The value 'null' does not match the expected type 'string'. ` +
|
|
`The invalid value is property 'foo' in {"foo":null}`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {
|
|
foo: null,
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
strict: true,
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
options: {
|
|
allowNullAsUndefinedProperties: true,
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: null,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: ["foo"],
|
|
message:
|
|
`The value 'null' does not match the expected type 'string'. ` +
|
|
`The invalid value is property 'foo' in {"foo":null}`,
|
|
},
|
|
},
|
|
});
|
|
|
|
// non-null falsey non-required property with strict=false: invalid
|
|
validate({
|
|
value: {
|
|
foo: false,
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
options: {
|
|
allowExplicitUndefinedProperties: true,
|
|
allowNullAsUndefinedProperties: true,
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: false,
|
|
error: {
|
|
invalidValue: false,
|
|
invalidPropertyNameComponents: ["foo"],
|
|
message:
|
|
`The value 'false' does not match the expected type 'string'. ` +
|
|
`The invalid value is property 'foo' in {"foo":false}`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {
|
|
foo: false,
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
strict: false,
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: false,
|
|
error: {
|
|
invalidValue: false,
|
|
invalidPropertyNameComponents: ["foo"],
|
|
message:
|
|
`The value 'false' does not match the expected type 'string'. ` +
|
|
`The invalid value is property 'foo' in {"foo":false}`,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
bogus: "test",
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: { bogus: "test" },
|
|
invalidPropertyNameComponents: [],
|
|
message: `Object has unexpected property 'bogus'`,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
foo: {
|
|
bogus: "test",
|
|
},
|
|
},
|
|
schema: {
|
|
type: "object",
|
|
properties: {
|
|
foo: {
|
|
type: "object",
|
|
properties: {
|
|
bar: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: { bogus: "test" },
|
|
invalidPropertyNameComponents: ["foo"],
|
|
message:
|
|
`Object has unexpected property 'bogus'. The invalid value is ` +
|
|
`property 'foo' in {"foo":{"bogus":"test"}}`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
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",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
validate({
|
|
value: [
|
|
{
|
|
url: "https://www.example.com/bookmark1",
|
|
title: "Foo",
|
|
},
|
|
{
|
|
url: "https://www.example.com/bookmark2",
|
|
title: "Bar",
|
|
},
|
|
],
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: [
|
|
{
|
|
url: new URL("https://www.example.com/bookmark1"),
|
|
title: "Foo",
|
|
},
|
|
{
|
|
url: new URL("https://www.example.com/bookmark2"),
|
|
title: "Bar",
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
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",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
validate({
|
|
value: {
|
|
allow: [true, true, true],
|
|
},
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
allow: [true, true, true],
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
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"],
|
|
};
|
|
|
|
validate({
|
|
value: {
|
|
"required-property": 5,
|
|
"non-required-property": undefined,
|
|
},
|
|
schema,
|
|
options: {
|
|
allowExplicitUndefinedProperties: true,
|
|
},
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
"required-property": 5,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
"non-required-property": 5,
|
|
},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: {
|
|
"non-required-property": 5,
|
|
},
|
|
invalidPropertyNameComponents: [],
|
|
message: `Object is missing required property 'required-property'`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_number_or_string_values() {
|
|
let schema = {
|
|
type: ["number", "string"],
|
|
};
|
|
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: 1,
|
|
},
|
|
});
|
|
validate({
|
|
value: "foobar",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: "foobar",
|
|
},
|
|
});
|
|
validate({
|
|
value: "1",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: "1",
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: true,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'true' does not match any type in ["number","string"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match any type in ["number","string"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: null,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'null' does not match any type in ["number","string"]`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_number_or_array_values() {
|
|
let schema = {
|
|
type: ["number", "array"],
|
|
items: {
|
|
type: "number",
|
|
},
|
|
};
|
|
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: 1,
|
|
},
|
|
});
|
|
validate({
|
|
value: [1, 2, 3],
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: [1, 2, 3],
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: true,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'true' does not match any type in ["number","array"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match any type in ["number","array"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: null,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: null,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'null' does not match any type in ["number","array"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: ["a", "b"],
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: ["a", "b"],
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '["a","b"]' does not match any type in ["number","array"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: [[]],
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: [[]],
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '[[]]' does not match any type in ["number","array"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: [0, 1, [2, 3]],
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: [0, 1, [2, 3]],
|
|
invalidPropertyNameComponents: [],
|
|
message:
|
|
`The value '[0,1,[2,3]]' does not match any type in ` +
|
|
`["number","array"]`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(function test_number_or_null_Values() {
|
|
let schema = {
|
|
type: ["number", "null"],
|
|
};
|
|
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: 1,
|
|
},
|
|
});
|
|
validate({
|
|
value: null,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: null,
|
|
},
|
|
});
|
|
|
|
// Invalid values:
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: true,
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value 'true' does not match any type in ["number","null"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "string",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: "string",
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '"string"' does not match any type in ["number","null"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: {},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: {},
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '{}' does not match any type in ["number","null"]`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: ["a", "b"],
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: ["a", "b"],
|
|
invalidPropertyNameComponents: [],
|
|
message: `The value '["a","b"]' does not match any type in ["number","null"]`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_patternProperties() {
|
|
let schema = {
|
|
type: "object",
|
|
properties: {
|
|
"S-bool-property": { type: "boolean" },
|
|
},
|
|
patternProperties: {
|
|
"^S-": { type: "string" },
|
|
"^N-": { type: "number" },
|
|
"^B-": { type: "boolean" },
|
|
},
|
|
};
|
|
|
|
validate({
|
|
value: {
|
|
"S-string": "test",
|
|
"N-number": 5,
|
|
"B-boolean": true,
|
|
"S-bool-property": false,
|
|
},
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
"S-string": "test",
|
|
"N-number": 5,
|
|
"B-boolean": true,
|
|
"S-bool-property": false,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
"N-string": "test",
|
|
},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: "test",
|
|
error: {
|
|
invalidValue: "test",
|
|
invalidPropertyNameComponents: ["N-string"],
|
|
message:
|
|
`The value '"test"' does not match the expected type 'number'. ` +
|
|
`The invalid value is property 'N-string' in {"N-string":"test"}`,
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: {
|
|
"S-number": 5,
|
|
},
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: 5,
|
|
error: {
|
|
invalidValue: 5,
|
|
invalidPropertyNameComponents: ["S-number"],
|
|
message:
|
|
`The value '5' does not match the expected type 'string'. ` +
|
|
`The invalid value is property 'S-number' in {"S-number":5}`,
|
|
},
|
|
},
|
|
});
|
|
|
|
schema = {
|
|
type: "object",
|
|
patternProperties: {
|
|
"[": { " type": "string" },
|
|
},
|
|
};
|
|
|
|
Assert.throws(
|
|
() => JsonSchemaValidator.validate({}, schema),
|
|
/Invalid property pattern/,
|
|
"Checking that invalid property patterns throw"
|
|
);
|
|
});
|
|
|
|
add_task(async function test_JSON_type() {
|
|
let schema = {
|
|
type: "JSON",
|
|
};
|
|
|
|
validate({
|
|
value: {
|
|
a: "b",
|
|
},
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
a: "b",
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: '{"a": "b"}',
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: {
|
|
a: "b",
|
|
},
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: "{This{is{not{JSON}}}}",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: "{This{is{not{JSON}}}}",
|
|
invalidPropertyNameComponents: [],
|
|
message: `JSON string could not be parsed: "{This{is{not{JSON}}}}"`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "0",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: "0",
|
|
invalidPropertyNameComponents: [],
|
|
message: `JSON was not an object: "0"`,
|
|
},
|
|
},
|
|
});
|
|
validate({
|
|
value: "true",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: "true",
|
|
invalidPropertyNameComponents: [],
|
|
message: `JSON was not an object: "true"`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_enum() {
|
|
let schema = {
|
|
type: "string",
|
|
enum: ["one", "two"],
|
|
};
|
|
|
|
validate({
|
|
value: "one",
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: "one",
|
|
},
|
|
});
|
|
|
|
validate({
|
|
value: "three",
|
|
schema,
|
|
expectedResult: {
|
|
valid: false,
|
|
parsedValue: undefined,
|
|
error: {
|
|
invalidValue: "three",
|
|
invalidPropertyNameComponents: [],
|
|
message:
|
|
`The value '"three"' is not one of the enumerated values ` +
|
|
`["one","two"]`,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_bool_enum() {
|
|
let schema = {
|
|
type: "boolean",
|
|
enum: ["one", "two"],
|
|
};
|
|
|
|
// `enum` is ignored because `type` is boolean.
|
|
validate({
|
|
value: true,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: true,
|
|
},
|
|
});
|
|
});
|
|
|
|
add_task(async function test_boolint_enum() {
|
|
let schema = {
|
|
type: "boolean",
|
|
enum: ["one", "two"],
|
|
};
|
|
|
|
// `enum` is ignored because `type` is boolean and the integer value was
|
|
// coerced to boolean.
|
|
validate({
|
|
value: 1,
|
|
schema,
|
|
expectedResult: {
|
|
valid: true,
|
|
parsedValue: true,
|
|
},
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Validates a value against a schema and asserts that the result is as
|
|
* expected.
|
|
*
|
|
* @param {*} value
|
|
* The value to validate.
|
|
* @param {object} schema
|
|
* The schema to validate against.
|
|
* @param {object} expectedResult
|
|
* The expected result. See JsonSchemaValidator.validate for what this object
|
|
* should look like. If the expected result is invalid, then this object
|
|
* should have an `error` property with all the properties of validation
|
|
* errors, including `message`, except that `rootValue` and `rootSchema` are
|
|
* unnecessary because this function will add them for you.
|
|
* @param {object} options
|
|
* Options to pass to JsonSchemaValidator.validate.
|
|
* @return {object} The return value of JsonSchemaValidator.validate, which is
|
|
* a result.
|
|
*/
|
|
function validate({ value, schema, expectedResult, options = undefined }) {
|
|
let result = JsonSchemaValidator.validate(value, schema, options);
|
|
|
|
checkObject(
|
|
result,
|
|
expectedResult,
|
|
{
|
|
valid: false,
|
|
parsedValue: true,
|
|
},
|
|
"Checking result property: "
|
|
);
|
|
|
|
Assert.equal("error" in result, "error" in expectedResult, "result.error");
|
|
if (result.error && expectedResult.error) {
|
|
expectedResult.error = Object.assign(expectedResult.error, {
|
|
rootValue: value,
|
|
rootSchema: schema,
|
|
});
|
|
checkObject(
|
|
result.error,
|
|
expectedResult.error,
|
|
{
|
|
rootValue: true,
|
|
rootSchema: false,
|
|
invalidPropertyNameComponents: false,
|
|
invalidValue: true,
|
|
message: false,
|
|
},
|
|
"Checking result.error property: "
|
|
);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Asserts that an object is the same as an expected object.
|
|
*
|
|
* @param {*} actual
|
|
* The actual object.
|
|
* @param {*} expected
|
|
* The expected object.
|
|
* @param {object} properties
|
|
* The properties to compare in the two objects. This value should be an
|
|
* object. The keys are the names of properties in the two objects. The
|
|
* values are booleans: true means that the property should be compared using
|
|
* strict equality and false means deep equality. Deep equality is used if
|
|
* the property is an object.
|
|
*/
|
|
function checkObject(actual, expected, properties, message) {
|
|
for (let [name, strict] of Object.entries(properties)) {
|
|
let assertFunc =
|
|
!strict || typeof expected[name] == "object"
|
|
? "deepEqual"
|
|
: "strictEqual";
|
|
Assert[assertFunc](actual[name], expected[name], message + name);
|
|
}
|
|
}
|