Source code

Revision control

Copy as Markdown

Other Tools

/* 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/. */
let loadContext = Cu.createLoadContext();
let privateLoadContext = Cu.createPrivateLoadContext();
const CURRENT_DB_VERSION = 6;
// There has to be a profile directory before the CPS service is gotten.
do_get_profile();
let cps = Cc["@mozilla.org/content-pref/service;1"].getService(
Ci.nsIContentPrefService2
);
function makeCallback(resolve, callbacks, success = null) {
callbacks = callbacks || {};
if (!callbacks.handleError) {
callbacks.handleError = function (error) {
do_throw("handleError call was not expected, error: " + error);
};
}
if (!callbacks.handleResult) {
callbacks.handleResult = function () {
do_throw("handleResult call was not expected");
};
}
if (!callbacks.handleCompletion) {
callbacks.handleCompletion = function (reason) {
equal(reason, Ci.nsIContentPrefCallback2.COMPLETE_OK);
if (success) {
success();
} else {
resolve();
}
};
}
return callbacks;
}
async function do_check_throws(fn) {
let threw = false;
try {
await fn();
} catch (err) {
threw = true;
}
ok(threw);
}
function sendMessage(msg, callback) {
let obj = callback || {};
let ref = Cu.getWeakReference(obj);
cps.QueryInterface(Ci.nsIObserver).observe(ref, "test:" + msg, null);
return "value" in obj ? obj.value : undefined;
}
function reset() {
return new Promise(resolve => {
sendMessage("reset", resolve);
});
}
function setWithDate(group, name, val, timestamp, context) {
return new Promise(resolve => {
async function updateDate() {
let conn = await sendMessage("db");
await conn.execute(
`
UPDATE prefs SET timestamp = :timestamp
WHERE
settingID = (SELECT id FROM settings WHERE name = :name)
AND groupID = (SELECT id FROM groups WHERE name = :group)
`,
{ name, group, timestamp: timestamp / 1000 }
);
resolve();
}
cps.set(group, name, val, context, makeCallback(null, null, updateDate));
});
}
async function getDate(group, name) {
let conn = await sendMessage("db");
let [result] = await conn.execute(
`
SELECT timestamp FROM prefs
WHERE
settingID = (SELECT id FROM settings WHERE name = :name)
AND groupID = (SELECT id FROM groups WHERE name = :group)
`,
{ name, group }
);
return result.getResultByName("timestamp") * 1000;
}
function set(group, name, val, context) {
return new Promise(resolve => {
cps.set(group, name, val, context, makeCallback(resolve));
});
}
function setGlobal(name, val, context) {
return new Promise(resolve => {
cps.setGlobal(name, val, context, makeCallback(resolve));
});
}
function prefOK(actual, expected, strict) {
ok(actual instanceof Ci.nsIContentPref);
equal(actual.domain, expected.domain);
equal(actual.name, expected.name);
if (strict) {
strictEqual(actual.value, expected.value);
} else {
equal(actual.value, expected.value);
}
}
async function getOK(args, expectedVal, expectedGroup, strict) {
if (args.length == 2) {
args.push(undefined);
}
let expectedPrefs =
expectedVal === undefined
? []
: [
{
domain: expectedGroup || args[0],
name: args[1],
value: expectedVal,
},
];
await getOKEx("getByDomainAndName", args, expectedPrefs, strict);
}
async function getSubdomainsOK(args, expectedGroupValPairs) {
if (args.length == 2) {
args.push(undefined);
}
let expectedPrefs = expectedGroupValPairs.map(function ([group, val]) {
return { domain: group, name: args[1], value: val };
});
await getOKEx("getBySubdomainAndName", args, expectedPrefs);
}
async function getGlobalOK(args, expectedVal) {
if (args.length == 1) {
args.push(undefined);
}
let expectedPrefs =
expectedVal === undefined
? []
: [{ domain: null, name: args[0], value: expectedVal }];
await getOKEx("getGlobal", args, expectedPrefs);
}
async function getOKEx(methodName, args, expectedPrefs, strict) {
let actualPrefs = [];
await new Promise(resolve => {
args.push(
makeCallback(resolve, {
handleResult: pref => actualPrefs.push(pref),
})
);
cps[methodName].apply(cps, args);
});
arraysOfArraysOK([actualPrefs], [expectedPrefs], function (actual, expected) {
prefOK(actual, expected, strict);
});
}
function getCachedOK(
args,
expectedIsCached,
expectedVal,
expectedGroup,
strict
) {
if (args.length == 2) {
args.push(undefined);
}
let expectedPref = !expectedIsCached
? null
: {
domain: expectedGroup || args[0],
name: args[1],
value: expectedVal,
};
getCachedOKEx("getCachedByDomainAndName", args, expectedPref, strict);
}
function getCachedSubdomainsOK(args, expectedGroupValPairs) {
if (args.length == 2) {
args.push(undefined);
}
let actualPrefs = cps.getCachedBySubdomainAndName.apply(cps, args);
actualPrefs = actualPrefs.sort(function (a, b) {
return a.domain.localeCompare(b.domain);
});
let expectedPrefs = expectedGroupValPairs.map(function ([group, val]) {
return { domain: group, name: args[1], value: val };
});
arraysOfArraysOK([actualPrefs], [expectedPrefs], prefOK);
}
function getCachedGlobalOK(args, expectedIsCached, expectedVal) {
if (args.length == 1) {
args.push(undefined);
}
let expectedPref = !expectedIsCached
? null
: {
domain: null,
name: args[0],
value: expectedVal,
};
getCachedOKEx("getCachedGlobal", args, expectedPref);
}
function getCachedOKEx(methodName, args, expectedPref, strict) {
let actualPref = cps[methodName].apply(cps, args);
if (expectedPref) {
prefOK(actualPref, expectedPref, strict);
} else {
strictEqual(actualPref, null);
}
}
function arraysOK(actual, expected, cmp) {
if (actual.length != expected.length) {
do_throw(
"Length is not equal: " +
JSON.stringify(actual) +
"==" +
JSON.stringify(expected)
);
} else {
actual.forEach(function (actualElt, j) {
let expectedElt = expected[j];
cmp(actualElt, expectedElt);
});
}
}
function arraysOfArraysOK(actual, expected, cmp) {
cmp = cmp || equal;
arraysOK(actual, expected, function (act, exp) {
arraysOK(act, exp, cmp);
});
}
async function dbOK(expectedRows) {
let conn = await sendMessage("db");
let stmt = `
SELECT groups.name AS grp, settings.name AS name, prefs.value AS value
FROM prefs
LEFT JOIN groups ON groups.id = prefs.groupID
LEFT JOIN settings ON settings.id = prefs.settingID
UNION
/*
These second two SELECTs get the rows of the groups and settings tables
that aren't referenced by the prefs table. Neither should return any
rows if the component is working properly.
*/
SELECT groups.name AS grp, NULL AS name, NULL AS value
FROM groups
WHERE id NOT IN (
SELECT DISTINCT groupID
FROM prefs
WHERE groupID NOTNULL
)
UNION
SELECT NULL AS grp, settings.name AS name, NULL AS value
FROM settings
WHERE id NOT IN (
SELECT DISTINCT settingID
FROM prefs
WHERE settingID NOTNULL
)
ORDER BY value ASC, grp ASC, name ASC
`;
let cols = ["grp", "name", "value"];
let actualRows = (await conn.execute(stmt)).map(row =>
cols.map(c => row.getResultByName(c))
);
arraysOfArraysOK(actualRows, expectedRows);
}
function on(event, names, dontRemove) {
return onEx(event, names, dontRemove).promise;
}
function onEx(event, names, dontRemove) {
let args = {
reset() {
for (let prop in this) {
if (Array.isArray(this[prop])) {
this[prop].splice(0, this[prop].length);
}
}
},
};
let observers = {};
let deferred = null;
let triggered = false;
names.forEach(function (name) {
let obs = {};
["onContentPrefSet", "onContentPrefRemoved"].forEach(function (meth) {
obs[meth] = () => do_throw(meth + " should not be called for " + name);
});
obs["onContentPref" + event] = function () {
args[name].push(Array.from(arguments));
if (!triggered) {
triggered = true;
executeSoon(function () {
if (!dontRemove) {
names.forEach(n => cps.removeObserverForName(n, observers[n]));
}
deferred.resolve(args);
});
}
};
observers[name] = obs;
args[name] = [];
args[name].observer = obs;
cps.addObserverForName(name, obs);
});
return {
observers,
promise: new Promise(resolve => {
deferred = { resolve };
}),
};
}
async function schemaVersionIs(expectedVersion) {
let db = await sendMessage("db");
equal(await db.getSchemaVersion(), expectedVersion);
}
function wait() {
return new Promise(resolve => executeSoon(resolve));
}
function observerArgsOK(actualArgs, expectedArgs) {
notEqual(actualArgs, undefined);
arraysOfArraysOK(actualArgs, expectedArgs);
}