Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test runs only with pattern: os != 'android'
- Manifest: browser/components/enterprisepolicies/tests/xpcshell/xpcshell.toml
/* Any copyright is dedicated to the Public Domain.
"use strict";
const { PolicySchemaValidator } = ChromeUtils.importESModule(
"resource://gre/modules/policies/PolicySchemaValidator.sys.mjs"
);
function assertValid(value, schema, options) {
const result = PolicySchemaValidator.validate(value, schema, options);
Assert.ok(result.valid, `Expected ${JSON.stringify(value)} to validate`);
return result.parsedValue;
}
function assertInvalid(value, schema, options) {
const result = PolicySchemaValidator.validate(value, schema, options);
Assert.ok(!result.valid, `Expected ${JSON.stringify(value)} to be invalid`);
Assert.ok(result.error, "An error is returned for invalid values");
return result.error;
}
add_task(function test_delegates_structural_validation() {
const schema = {
type: "object",
properties: { id: { type: "number" } },
required: ["id"],
};
Assert.deepEqual(assertValid({ id: 5 }, schema), { id: 5 });
assertInvalid({}, schema);
assertInvalid({ id: "nope" }, schema);
});
add_task(function test_boolean_coercion_from_gpo_dword() {
const schema = { type: "boolean" };
Assert.strictEqual(assertValid(1, schema), true, "1 coerces to true");
Assert.strictEqual(assertValid(0, schema), false, "0 coerces to false");
Assert.strictEqual(assertValid(true, schema), true, "true stays true");
assertInvalid(2, schema);
assertInvalid("true", schema);
});
add_task(function test_numeric_field_keeps_its_integer() {
// A Preferences value is number|boolean|string; a 0/1 there is a real integer
// and must NOT be coerced to a boolean.
const schema = { type: ["number", "boolean", "string"] };
Assert.strictEqual(assertValid(1, schema), 1, "1 stays an integer");
Assert.strictEqual(assertValid(0, schema), 0, "0 stays an integer");
});
add_task(function test_uri_format_hydrates_to_url_object() {
const schema = { type: "string", format: "uri" };
Assert.ok(URL.isInstance(parsed), "a uri-formatted string becomes a URL");
// format:uri is permissive (intranet/private/file), unlike the built-in
// "url" format; enterprise policies rely on accepting these.
assertInvalid("not a url", schema);
});
add_task(function test_uri_or_empty() {
const schema = {
type: "string",
anyOf: [{ format: "uri" }, { maxLength: 0 }],
};
Assert.strictEqual(assertValid("", schema), "", "empty string is allowed");
assertInvalid("not a url", schema);
});
add_task(function test_boolean_or_enum_accepts_integer_boolean() {
// DisplayMenuBar/DisplayBookmarksToolbar shape: a boolean or an enumerated
// string. GPO (REG_DWORD) and macOS (NSNumber) deliver booleans as 0/1.
const schema = {
anyOf: [{ type: "boolean" }, { type: "string", enum: ["always", "never"] }],
};
Assert.strictEqual(assertValid(1, schema), true, "integer 1 coerces to true");
Assert.strictEqual(
assertValid(0, schema),
false,
"integer 0 coerces to false"
);
Assert.equal(assertValid("always", schema), "always", "enum string passes");
assertInvalid("bogus", schema);
});
add_task(function test_json_string_parsing() {
const schema = {
type: ["object", "array"],
contentMediaType: "application/json",
properties: { foo: { type: "string" } },
};
Assert.deepEqual(assertValid({ foo: "bar" }, schema), { foo: "bar" });
// A JSON string (as GPO/macOS deliver ExtensionSettings) is parsed.
Assert.deepEqual(assertValid('{"foo":"bar"}', schema), { foo: "bar" });
// Unparseable JSON reports the real cause, not a downstream type mismatch.
const parseError = assertInvalid("not json", schema);
Assert.ok(
parseError.message.includes("not valid JSON"),
"the error names the unparseable JSON"
);
});
add_task(function test_unsupported_value_fails_without_throwing() {
// The validator throws (rather than returning invalid) for values such as
// undefined; validate() must catch that so a single bad value can't abort
// the whole policy engine. Before that guard this call threw instead of
// returning a result.
assertInvalid(undefined, { type: "object", properties: {} });
});
add_task(function test_list_drops_invalid_entries_and_keeps_the_rest() {
// The non-negotiable behavior: one bad entry never discards the whole list.
const schema = { type: "array", items: { type: "string" } };
Assert.deepEqual(
assertValid(["a", 0, "b"], schema),
["a", "b"],
"a wrong-typed entry is dropped, the rest are kept"
);
});
add_task(function test_list_of_uris_drops_invalid_keeps_valid_as_urls() {
const schema = { type: "array", items: { type: "string", format: "uri" } };
const parsed = assertValid(
schema
);
Assert.deepEqual(
parsed.map(u => u.href),
"the invalid entry is dropped and valid ones become URL objects"
);
});
add_task(function test_additional_properties_stripped_when_allowed() {
const schema = {
type: "object",
properties: { known: { type: "string" } },
};
Assert.deepEqual(
assertValid({ known: "value", extra: "dropped" }, schema, {
allowAdditionalProperties: true,
}),
{ known: "value" },
"unknown properties are stripped from the parsed value"
);
});
add_task(function test_additional_properties_rejected_by_default() {
const schema = {
type: "object",
properties: { known: { type: "string" } },
};
assertInvalid({ known: "value", extra: "x" }, schema);
});