forked from mirrors/gecko-dev
Adds a new startup cache info service to expose some of the internal state of the startup cache. Differential Revision: https://phabricator.services.mozilla.com/D69298 --HG-- extra : moz-landing-system : lando
1002 lines
23 KiB
JavaScript
1002 lines
23 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
// Ideally this would be an xpcshell test, but Troubleshoot relies on things
|
|
// that aren't initialized outside of a XUL app environment like AddonManager
|
|
// and the "@mozilla.org/xre/app-info;1" component.
|
|
|
|
const { AppConstants } = ChromeUtils.import(
|
|
"resource://gre/modules/AppConstants.jsm"
|
|
);
|
|
const { Troubleshoot } = ChromeUtils.import(
|
|
"resource://gre/modules/Troubleshoot.jsm"
|
|
);
|
|
|
|
function test() {
|
|
waitForExplicitFinish();
|
|
function doNextTest() {
|
|
if (!tests.length) {
|
|
finish();
|
|
return;
|
|
}
|
|
tests.shift()(doNextTest);
|
|
}
|
|
doNextTest();
|
|
}
|
|
|
|
registerCleanupFunction(function() {
|
|
// Troubleshoot.jsm is imported into the global scope -- the window -- above.
|
|
// If it's not deleted, it outlives the test and is reported as a leak.
|
|
delete window.Troubleshoot;
|
|
});
|
|
|
|
var tests = [
|
|
function snapshotSchema(done) {
|
|
Troubleshoot.snapshot(function(snapshot) {
|
|
try {
|
|
validateObject(snapshot, SNAPSHOT_SCHEMA);
|
|
ok(true, "The snapshot should conform to the schema.");
|
|
} catch (err) {
|
|
ok(false, "Schema mismatch, " + err);
|
|
}
|
|
done();
|
|
});
|
|
},
|
|
|
|
function modifiedPreferences(done) {
|
|
let prefs = [
|
|
"javascript.troubleshoot",
|
|
"troubleshoot.foo",
|
|
"javascript.print_to_filename",
|
|
"network.proxy.troubleshoot",
|
|
];
|
|
prefs.forEach(function(p) {
|
|
Services.prefs.setBoolPref(p, true);
|
|
is(Services.prefs.getBoolPref(p), true, "The pref should be set: " + p);
|
|
});
|
|
Troubleshoot.snapshot(function(snapshot) {
|
|
let p = snapshot.modifiedPreferences;
|
|
is(
|
|
p["javascript.troubleshoot"],
|
|
true,
|
|
"The pref should be present because it's whitelisted " +
|
|
"but not blacklisted."
|
|
);
|
|
ok(
|
|
!("troubleshoot.foo" in p),
|
|
"The pref should be absent because it's not in the whitelist."
|
|
);
|
|
ok(
|
|
!("javascript.print_to_filename" in p),
|
|
"The pref should be absent because it's blacklisted."
|
|
);
|
|
ok(
|
|
!("network.proxy.troubleshoot" in p),
|
|
"The pref should be absent because it's blacklisted."
|
|
);
|
|
prefs.forEach(p => Services.prefs.deleteBranch(p));
|
|
done();
|
|
});
|
|
},
|
|
|
|
function unicodePreferences(done) {
|
|
let name = "font.name.sans-serif.x-western";
|
|
let utf8Value = "\xc4\x8capk\xc5\xafv Krasopis";
|
|
let unicodeValue = "\u010Capk\u016Fv Krasopis";
|
|
|
|
// set/getCharPref work with 8bit strings (utf8)
|
|
Services.prefs.setCharPref(name, utf8Value);
|
|
|
|
Troubleshoot.snapshot(function(snapshot) {
|
|
let p = snapshot.modifiedPreferences;
|
|
is(p[name], unicodeValue, "The pref should have correct Unicode value.");
|
|
Services.prefs.deleteBranch(name);
|
|
done();
|
|
});
|
|
},
|
|
];
|
|
|
|
// This is inspired by JSON Schema, or by the example on its Wikipedia page
|
|
// anyway.
|
|
const SNAPSHOT_SCHEMA = {
|
|
type: "object",
|
|
required: true,
|
|
properties: {
|
|
application: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
name: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
version: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
buildID: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
userAgent: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
osVersion: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
vendor: {
|
|
type: "string",
|
|
},
|
|
updateChannel: {
|
|
type: "string",
|
|
},
|
|
supportURL: {
|
|
type: "string",
|
|
},
|
|
launcherProcessState: {
|
|
type: "number",
|
|
},
|
|
remoteAutoStart: {
|
|
type: "boolean",
|
|
required: true,
|
|
},
|
|
autoStartStatus: {
|
|
type: "number",
|
|
},
|
|
numTotalWindows: {
|
|
type: "number",
|
|
},
|
|
numRemoteWindows: {
|
|
type: "number",
|
|
},
|
|
policiesStatus: {
|
|
type: "number",
|
|
},
|
|
keyLocationServiceGoogleFound: {
|
|
type: "boolean",
|
|
},
|
|
keySafebrowsingGoogleFound: {
|
|
type: "boolean",
|
|
},
|
|
keyMozillaFound: {
|
|
type: "boolean",
|
|
},
|
|
safeMode: {
|
|
type: "boolean",
|
|
},
|
|
},
|
|
},
|
|
crashes: {
|
|
required: false,
|
|
type: "object",
|
|
properties: {
|
|
pending: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
submitted: {
|
|
required: true,
|
|
type: "array",
|
|
items: {
|
|
type: "object",
|
|
properties: {
|
|
id: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
date: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
pending: {
|
|
required: true,
|
|
type: "boolean",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
extensions: {
|
|
required: true,
|
|
type: "array",
|
|
items: {
|
|
type: "object",
|
|
properties: {
|
|
name: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
version: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
id: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
isActive: {
|
|
required: true,
|
|
type: "boolean",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
securitySoftware: {
|
|
required: false,
|
|
type: "object",
|
|
properties: {
|
|
registeredAntiVirus: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
registeredAntiSpyware: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
registeredFirewall: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
features: {
|
|
required: true,
|
|
type: "array",
|
|
items: {
|
|
type: "object",
|
|
properties: {
|
|
name: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
version: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
id: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
processes: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
maxWebContentProcesses: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
remoteTypes: {
|
|
required: true,
|
|
type: "object",
|
|
},
|
|
},
|
|
},
|
|
modifiedPreferences: {
|
|
required: true,
|
|
type: "object",
|
|
},
|
|
lockedPreferences: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
"fission.autostart": {
|
|
required: false,
|
|
type: "boolean",
|
|
},
|
|
"dom.ipc.processCount.webIsolated": {
|
|
required: false,
|
|
type: "number",
|
|
},
|
|
},
|
|
},
|
|
graphics: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
numTotalWindows: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
numAcceleratedWindows: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
windowLayerManagerType: {
|
|
type: "string",
|
|
},
|
|
windowLayerManagerRemote: {
|
|
type: "boolean",
|
|
},
|
|
windowUsingAdvancedLayers: {
|
|
type: "boolean",
|
|
},
|
|
numAcceleratedWindowsMessage: {
|
|
type: "object",
|
|
properties: {
|
|
key: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
args: {
|
|
required: false,
|
|
type: "object",
|
|
},
|
|
},
|
|
},
|
|
adapterDescription: {
|
|
type: "string",
|
|
},
|
|
adapterVendorID: {
|
|
type: "string",
|
|
},
|
|
adapterDeviceID: {
|
|
type: "string",
|
|
},
|
|
adapterSubsysID: {
|
|
type: "string",
|
|
},
|
|
adapterRAM: {
|
|
type: "number",
|
|
},
|
|
adapterDrivers: {
|
|
type: "string",
|
|
},
|
|
driverVendor: {
|
|
type: "string",
|
|
},
|
|
driverVersion: {
|
|
type: "string",
|
|
},
|
|
driverDate: {
|
|
type: "string",
|
|
},
|
|
adapterDescription2: {
|
|
type: "string",
|
|
},
|
|
adapterVendorID2: {
|
|
type: "string",
|
|
},
|
|
adapterDeviceID2: {
|
|
type: "string",
|
|
},
|
|
adapterSubsysID2: {
|
|
type: "string",
|
|
},
|
|
adapterRAM2: {
|
|
type: "number",
|
|
},
|
|
adapterDrivers2: {
|
|
type: "string",
|
|
},
|
|
driverVendor2: {
|
|
type: "string",
|
|
},
|
|
driverVersion2: {
|
|
type: "string",
|
|
},
|
|
driverDate2: {
|
|
type: "string",
|
|
},
|
|
isGPU2Active: {
|
|
type: "boolean",
|
|
},
|
|
direct2DEnabled: {
|
|
type: "boolean",
|
|
},
|
|
directWriteEnabled: {
|
|
type: "boolean",
|
|
},
|
|
directWriteVersion: {
|
|
type: "string",
|
|
},
|
|
usesTiling: {
|
|
type: "boolean",
|
|
},
|
|
contentUsesTiling: {
|
|
type: "boolean",
|
|
},
|
|
offMainThreadPaintEnabled: {
|
|
type: "boolean",
|
|
},
|
|
offMainThreadPaintWorkerCount: {
|
|
type: "number",
|
|
},
|
|
clearTypeParameters: {
|
|
type: "string",
|
|
},
|
|
webgl1Renderer: {
|
|
type: "string",
|
|
},
|
|
webgl1Version: {
|
|
type: "string",
|
|
},
|
|
webgl1DriverExtensions: {
|
|
type: "string",
|
|
},
|
|
webgl1Extensions: {
|
|
type: "string",
|
|
},
|
|
webgl1WSIInfo: {
|
|
type: "string",
|
|
},
|
|
webgl2Renderer: {
|
|
type: "string",
|
|
},
|
|
webgl2Version: {
|
|
type: "string",
|
|
},
|
|
webgl2DriverExtensions: {
|
|
type: "string",
|
|
},
|
|
webgl2Extensions: {
|
|
type: "string",
|
|
},
|
|
webgl2WSIInfo: {
|
|
type: "string",
|
|
},
|
|
info: {
|
|
type: "object",
|
|
},
|
|
failures: {
|
|
type: "object",
|
|
properties: {
|
|
key: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
args: {
|
|
required: false,
|
|
type: "object",
|
|
},
|
|
},
|
|
},
|
|
indices: {
|
|
type: "array",
|
|
items: {
|
|
type: "number",
|
|
},
|
|
},
|
|
featureLog: {
|
|
type: "object",
|
|
},
|
|
crashGuards: {
|
|
type: "array",
|
|
},
|
|
direct2DEnabledMessage: {
|
|
type: "object",
|
|
properties: {
|
|
key: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
args: {
|
|
required: false,
|
|
type: "object",
|
|
},
|
|
},
|
|
},
|
|
targetFrameRate: {
|
|
type: "number",
|
|
},
|
|
windowProtocol: {
|
|
type: "string",
|
|
},
|
|
desktopEnvironment: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
media: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
currentAudioBackend: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
currentMaxAudioChannels: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
currentPreferredSampleRate: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
audioOutputDevices: {
|
|
required: true,
|
|
type: "array",
|
|
items: {
|
|
type: "object",
|
|
properties: {
|
|
name: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
groupId: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
vendor: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
type: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
state: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
preferred: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
supportedFormat: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
defaultFormat: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
maxChannels: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
defaultRate: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
maxRate: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
minRate: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
maxLatency: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
minLatency: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
audioInputDevices: {
|
|
required: true,
|
|
type: "array",
|
|
items: {
|
|
type: "object",
|
|
properties: {
|
|
name: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
groupId: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
vendor: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
type: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
state: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
preferred: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
supportedFormat: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
defaultFormat: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
maxChannels: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
defaultRate: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
maxRate: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
minRate: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
maxLatency: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
minLatency: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
javaScript: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
incrementalGCEnabled: {
|
|
type: "boolean",
|
|
},
|
|
},
|
|
},
|
|
accessibility: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
isActive: {
|
|
required: true,
|
|
type: "boolean",
|
|
},
|
|
forceDisabled: {
|
|
type: "number",
|
|
},
|
|
handlerUsed: {
|
|
type: "boolean",
|
|
},
|
|
instantiator: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
libraryVersions: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
NSPR: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
minVersion: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
version: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
NSS: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
minVersion: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
version: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
NSSUTIL: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
minVersion: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
version: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
NSSSSL: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
minVersion: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
version: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
NSSSMIME: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
minVersion: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
version: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
userJS: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
exists: {
|
|
required: true,
|
|
type: "boolean",
|
|
},
|
|
},
|
|
},
|
|
sandbox: {
|
|
required: false,
|
|
type: "object",
|
|
properties: {
|
|
hasSeccompBPF: {
|
|
required: AppConstants.platform == "linux",
|
|
type: "boolean",
|
|
},
|
|
hasSeccompTSync: {
|
|
required: AppConstants.platform == "linux",
|
|
type: "boolean",
|
|
},
|
|
hasUserNamespaces: {
|
|
required: AppConstants.platform == "linux",
|
|
type: "boolean",
|
|
},
|
|
hasPrivilegedUserNamespaces: {
|
|
required: AppConstants.platform == "linux",
|
|
type: "boolean",
|
|
},
|
|
canSandboxContent: {
|
|
required: false,
|
|
type: "boolean",
|
|
},
|
|
canSandboxMedia: {
|
|
required: false,
|
|
type: "boolean",
|
|
},
|
|
contentSandboxLevel: {
|
|
required: AppConstants.MOZ_SANDBOX,
|
|
type: "number",
|
|
},
|
|
effectiveContentSandboxLevel: {
|
|
required: AppConstants.MOZ_SANDBOX,
|
|
type: "number",
|
|
},
|
|
syscallLog: {
|
|
required: AppConstants.platform == "linux",
|
|
type: "array",
|
|
items: {
|
|
type: "object",
|
|
properties: {
|
|
index: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
pid: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
tid: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
procType: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
syscall: {
|
|
required: true,
|
|
type: "number",
|
|
},
|
|
args: {
|
|
required: true,
|
|
type: "array",
|
|
items: {
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
startupCache: {
|
|
required: false,
|
|
type: "object",
|
|
properties: {
|
|
DiskCachePath: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
IgnoreDiskCache: {
|
|
required: true,
|
|
type: "boolean",
|
|
},
|
|
FoundDiskCacheOnInit: {
|
|
required: true,
|
|
type: "boolean",
|
|
},
|
|
WroteToDiskCache: {
|
|
required: true,
|
|
type: "boolean",
|
|
},
|
|
},
|
|
},
|
|
intl: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
localeService: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
requested: {
|
|
required: true,
|
|
type: "array",
|
|
},
|
|
available: {
|
|
required: true,
|
|
type: "array",
|
|
},
|
|
supported: {
|
|
required: true,
|
|
type: "array",
|
|
},
|
|
regionalPrefs: {
|
|
required: true,
|
|
type: "array",
|
|
},
|
|
defaultLocale: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
osPrefs: {
|
|
required: true,
|
|
type: "object",
|
|
properties: {
|
|
systemLocales: {
|
|
required: true,
|
|
type: "array",
|
|
},
|
|
regionalPrefsLocales: {
|
|
required: true,
|
|
type: "array",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
remoteAgent: {
|
|
type: "object",
|
|
properties: {
|
|
listening: {
|
|
required: true,
|
|
type: "boolean",
|
|
},
|
|
url: {
|
|
required: true,
|
|
type: "string",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Throws an Error if obj doesn't conform to schema. That way you get a nice
|
|
* error message and a stack to help you figure out what went wrong, which you
|
|
* wouldn't get if this just returned true or false instead. There's still
|
|
* room for improvement in communicating validation failures, however.
|
|
*
|
|
* @param obj The object to validate.
|
|
* @param schema The schema that obj should conform to.
|
|
*/
|
|
function validateObject(obj, schema) {
|
|
if (obj === undefined && !schema.required) {
|
|
return;
|
|
}
|
|
if (typeof schema.type != "string") {
|
|
throw schemaErr("'type' must be a string", schema);
|
|
}
|
|
if (objType(obj) != schema.type) {
|
|
throw validationErr("Object is not of the expected type", obj, schema);
|
|
}
|
|
let validatorFnName = "validateObject_" + schema.type;
|
|
if (!(validatorFnName in this)) {
|
|
throw schemaErr("Validator function not defined for type", schema);
|
|
}
|
|
this[validatorFnName](obj, schema);
|
|
}
|
|
|
|
function validateObject_object(obj, schema) {
|
|
if (typeof schema.properties != "object") {
|
|
// Don't care what obj's properties are.
|
|
return;
|
|
}
|
|
// First check that all the schema's properties match the object.
|
|
for (let prop in schema.properties) {
|
|
validateObject(obj[prop], schema.properties[prop]);
|
|
}
|
|
// Now check that the object doesn't have any properties not in the schema.
|
|
for (let prop in obj) {
|
|
if (!(prop in schema.properties)) {
|
|
throw validationErr(
|
|
"Object has property " + prop + " not in schema",
|
|
obj,
|
|
schema
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
function validateObject_array(array, schema) {
|
|
if (typeof schema.items != "object") {
|
|
// Don't care what the array's elements are.
|
|
return;
|
|
}
|
|
array.forEach(elt => validateObject(elt, schema.items));
|
|
}
|
|
|
|
function validateObject_string(str, schema) {}
|
|
function validateObject_boolean(bool, schema) {}
|
|
function validateObject_number(num, schema) {}
|
|
|
|
function validationErr(msg, obj, schema) {
|
|
return new Error(
|
|
"Validation error: " +
|
|
msg +
|
|
": object=" +
|
|
JSON.stringify(obj) +
|
|
", schema=" +
|
|
JSON.stringify(schema)
|
|
);
|
|
}
|
|
|
|
function schemaErr(msg, schema) {
|
|
return new Error("Schema error: " + msg + ": " + JSON.stringify(schema));
|
|
}
|
|
|
|
function objType(obj) {
|
|
let type = typeof obj;
|
|
if (type != "object") {
|
|
return type;
|
|
}
|
|
if (Array.isArray(obj)) {
|
|
return "array";
|
|
}
|
|
if (obj === null) {
|
|
return "null";
|
|
}
|
|
return type;
|
|
}
|