mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 699859 - Create nsIContentPrefService2, an async version of nsIContentPrefService. r=mak, sr=mossop
This commit is contained in:
parent
d75825f8d9
commit
3c55f766f6
@ -27,6 +27,7 @@ XPIDLSRCS = \
|
||||
nsIBrowserDOMWindow.idl \
|
||||
nsIContentPermissionPrompt.idl \
|
||||
nsIContentPrefService.idl \
|
||||
nsIContentPrefService2.idl \
|
||||
nsIContentURIGrouper.idl \
|
||||
nsIDOMClientInformation.idl \
|
||||
nsIDOMConstructor.idl \
|
||||
|
365
dom/interfaces/base/nsIContentPrefService2.idl
Normal file
365
dom/interfaces/base/nsIContentPrefService2.idl
Normal file
@ -0,0 +1,365 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIVariant;
|
||||
interface nsIContentPrefObserver;
|
||||
interface nsIContentPrefCallback2;
|
||||
interface nsILoadContext;
|
||||
interface nsIContentPref;
|
||||
|
||||
/**
|
||||
* Content Preferences
|
||||
*
|
||||
* Content preferences allow the application to associate arbitrary data, or
|
||||
* "preferences", with specific domains, or web "content". Specifically, a
|
||||
* content preference is a structure with three values: a domain with which the
|
||||
* preference is associated, a name that identifies the preference within its
|
||||
* domain, and a value. (See nsIContentPref below.)
|
||||
*
|
||||
* For example, if you want to remember the user's preference for a certain zoom
|
||||
* level on www.mozilla.org pages, you might store a preference whose domain is
|
||||
* "www.mozilla.org", whose name is "zoomLevel", and whose value is the numeric
|
||||
* zoom level.
|
||||
*
|
||||
* A preference need not have a domain, and in that case the preference is
|
||||
* called a "global" preference. This interface doesn't impart any special
|
||||
* significance to global preferences; they're simply name-value pairs that
|
||||
* aren't associated with any particular domain. As a consumer of this
|
||||
* interface, you might choose to let a global preference override all non-
|
||||
* global preferences of the same name, for example, for whatever definition of
|
||||
* "override" is appropriate for your use case.
|
||||
*
|
||||
*
|
||||
* Domain Parameters
|
||||
*
|
||||
* Many methods of this interface accept a "domain" parameter. Domains may be
|
||||
* specified either exactly, like "example.com", or as full URLs, like
|
||||
* "http://example.com/foo/bar". In the latter case the API extracts the full
|
||||
* domain from the URL, so if you specify "http://foo.bar.example.com/baz", the
|
||||
* domain is taken to be "foo.bar.example.com", not "example.com".
|
||||
*
|
||||
*
|
||||
* Private-Browsing Context Parameters
|
||||
*
|
||||
* Many methods also accept a "context" parameter. This parameter relates to
|
||||
* private browsing and determines the kind of storage that a method uses,
|
||||
* either the usual permanent storage or temporary storage set aside for private
|
||||
* browsing sessions.
|
||||
*
|
||||
* Pass null to unconditionally use permanent storage. Pass an nsILoadContext
|
||||
* to use storage appropriate to the context's usePrivateBrowsing attribute: if
|
||||
* usePrivateBrowsing is true, temporary private-browsing storage is used, and
|
||||
* otherwise permanent storage is used. A context can be obtained from the
|
||||
* window or channel whose content pertains to the preferences being modified or
|
||||
* retrieved.
|
||||
*
|
||||
*
|
||||
* Callbacks
|
||||
*
|
||||
* The methods of callback objects are always called asynchronously. See
|
||||
* nsIContentPrefCallback2 below for more information about callbacks.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(51e1d34a-5e9d-4b77-b14c-0f8346e264ca)]
|
||||
interface nsIContentPrefService2 : nsISupports
|
||||
{
|
||||
/**
|
||||
* Gets the preference with the given domain and name.
|
||||
*
|
||||
* @param domain The preference's domain.
|
||||
* @param name The preference's name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleResult is called once unless no such preference
|
||||
* exists, in which case handleResult is not called at all.
|
||||
*/
|
||||
void getByDomainAndName(in AString domain,
|
||||
in AString name,
|
||||
in nsILoadContext context,
|
||||
in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Gets all preferences with the given name whose domains are either the same
|
||||
* as or subdomains of the given domain.
|
||||
*
|
||||
* @param domain The preferences' domain.
|
||||
* @param name The preferences' name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleResult is called once for each preference. If no
|
||||
* such preferences exist, handleResult is not called at all.
|
||||
*/
|
||||
void getBySubdomainAndName(in AString domain,
|
||||
in AString name,
|
||||
in nsILoadContext context,
|
||||
in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Gets the preference with no domain and the given name.
|
||||
*
|
||||
* @param name The preference's name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleResult is called once unless no such preference
|
||||
* exists, in which case handleResult is not called at all.
|
||||
*/
|
||||
void getGlobal(in AString name,
|
||||
in nsILoadContext context,
|
||||
in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Synchronously retrieves from the in-memory cache the preference with the
|
||||
* given domain and name.
|
||||
*
|
||||
* In addition to caching preference values, the cache also keeps track of
|
||||
* preferences that are known not to exist. If the preference is known not to
|
||||
* exist, the value attribute of the returned object will be undefined
|
||||
* (nsIDataType::VTYPE_VOID).
|
||||
*
|
||||
* If the preference is neither cached nor known not to exist, then null is
|
||||
* returned, and get() must be called to determine whether the preference
|
||||
* exists.
|
||||
*
|
||||
* @param domain The preference's domain.
|
||||
* @param name The preference's name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @return The preference, or null if no such preference is known to
|
||||
* exist.
|
||||
*/
|
||||
nsIContentPref getCachedByDomainAndName(in AString domain,
|
||||
in AString name,
|
||||
in nsILoadContext context);
|
||||
|
||||
/**
|
||||
* Synchronously retrieves from the in-memory cache all preferences with the
|
||||
* given name whose domains are either the same as or subdomains of the given
|
||||
* domain.
|
||||
*
|
||||
* The preferences are returned in an array through the out-parameter. If a
|
||||
* preference for a particular subdomain is known not to exist, then an object
|
||||
* corresponding to that preference will be present in the array, and, as with
|
||||
* getCachedByDomainAndName, its value attribute will be undefined.
|
||||
*
|
||||
* @param domain The preferences' domain.
|
||||
* @param name The preferences' name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param len The length of the returned array.
|
||||
* @param prefs The array of preferences.
|
||||
*/
|
||||
void getCachedBySubdomainAndName(in AString domain,
|
||||
in AString name,
|
||||
in nsILoadContext context,
|
||||
out unsigned long len,
|
||||
[retval,array,size_is(len)] out nsIContentPref prefs);
|
||||
|
||||
/**
|
||||
* Synchronously retrieves from the in-memory cache the preference with no
|
||||
* domain and the given name.
|
||||
*
|
||||
* As with getCachedByDomainAndName, if the preference is cached then it is
|
||||
* returned; if the preference is known not to exist, then the value attribute
|
||||
* of the returned object will be undefined; if the preference is neither
|
||||
* cached nor known not to exist, then null is returned.
|
||||
*
|
||||
* @param name The preference's name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @return The preference, or null if no such preference is known to
|
||||
* exist.
|
||||
*/
|
||||
nsIContentPref getCachedGlobal(in AString name,
|
||||
in nsILoadContext context);
|
||||
|
||||
/**
|
||||
* Sets a preference.
|
||||
*
|
||||
* @param domain The preference's domain.
|
||||
* @param name The preference's name.
|
||||
* @param value The preference's value.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the preference has been
|
||||
* stored.
|
||||
*/
|
||||
void set(in AString domain,
|
||||
in AString name,
|
||||
in nsIVariant value,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Sets a preference with no domain.
|
||||
*
|
||||
* @param name The preference's name.
|
||||
* @param value The preference's value.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the preference has been
|
||||
* stored.
|
||||
*/
|
||||
void setGlobal(in AString name,
|
||||
in nsIVariant value,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes the preference with the given domain and name.
|
||||
*
|
||||
* @param domain The preference's domain.
|
||||
* @param name The preference's name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeByDomainAndName(in AString domain,
|
||||
in AString name,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes all the preferences with the given name whose domains are either
|
||||
* the same as or subdomains of the given domain.
|
||||
*
|
||||
* @param domain The preferences' domain.
|
||||
* @param name The preferences' name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeBySubdomainAndName(in AString domain,
|
||||
in AString name,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes the preference with no domain and the given name.
|
||||
*
|
||||
* @param name The preference's name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeGlobal(in AString name,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes all preferences with the given domain.
|
||||
*
|
||||
* @param domain The preferences' domain.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeByDomain(in AString domain,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes all preferences whose domains are either the same as or subdomains
|
||||
* of the given domain.
|
||||
*
|
||||
* @param domain The preferences' domain.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeBySubdomain(in AString domain,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes all preferences with the given name regardless of domain, including
|
||||
* global preferences with the given name.
|
||||
*
|
||||
* @param name The preferences' name.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeByName(in AString name,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes all non-global preferences -- in other words, all preferences that
|
||||
* have a domain.
|
||||
*
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeAllDomains(in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes all global preferences -- in other words, all preferences that have
|
||||
* no domain.
|
||||
*
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeAllGlobals(in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Registers an observer that will be notified whenever a preference with the
|
||||
* given name is set or removed.
|
||||
*
|
||||
* When a set or remove method is called, observers are notified after the set
|
||||
* or removal completes but before method's callback is called.
|
||||
*
|
||||
* The service holds a strong reference to the observer, so the observer must
|
||||
* be removed later to avoid leaking it.
|
||||
*
|
||||
* @param name The name of the preferences to observe. Pass null to
|
||||
* observe all preference changes regardless of name.
|
||||
* @param observer The observer.
|
||||
*/
|
||||
void addObserverForName(in AString name,
|
||||
in nsIContentPrefObserver observer);
|
||||
|
||||
/**
|
||||
* Unregisters an observer for the given name.
|
||||
*
|
||||
* @param name The name for which the observer was registered. Pass null
|
||||
* if the observer was added with a null name.
|
||||
* @param observer The observer.
|
||||
*/
|
||||
void removeObserverForName(in AString name,
|
||||
in nsIContentPrefObserver observer);
|
||||
};
|
||||
|
||||
/**
|
||||
* The callback used by the above methods.
|
||||
*/
|
||||
[scriptable, uuid(1a12cf41-79e8-4d0f-9899-2f7b27c5d9a1)]
|
||||
interface nsIContentPrefCallback2 : nsISupports
|
||||
{
|
||||
/**
|
||||
* For the retrieval methods, this is called once for each retrieved
|
||||
* preference. It is not called for other methods.
|
||||
*
|
||||
* @param pref The retrieved preference.
|
||||
*/
|
||||
void handleResult(in nsIContentPref pref);
|
||||
|
||||
/**
|
||||
* Called when an error occurs. This may be called multiple times before
|
||||
* onComplete is called.
|
||||
*
|
||||
* @param error A number in Components.results describing the error.
|
||||
*/
|
||||
void handleError(in nsresult error);
|
||||
|
||||
/**
|
||||
* Called when the method finishes. This will be called exactly once for
|
||||
* each method invocation, and afterward no other callback methods will be
|
||||
* called.
|
||||
*
|
||||
* @param reason One of the COMPLETE_* values indicating the manner in which
|
||||
* the method completed.
|
||||
*/
|
||||
void handleCompletion(in unsigned short reason);
|
||||
|
||||
const unsigned short COMPLETE_OK = 0;
|
||||
const unsigned short COMPLETE_ERROR = 1;
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(9f24948d-24b5-4b1b-b554-7dbd58c1d792)]
|
||||
interface nsIContentPref : nsISupports
|
||||
{
|
||||
readonly attribute AString domain;
|
||||
readonly attribute AString name;
|
||||
readonly attribute nsIVariant value;
|
||||
};
|
@ -26,6 +26,7 @@
|
||||
[include:embedding/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/components/commandlines/test/unit/xpcshell.ini]
|
||||
[include:toolkit/components/contentprefs/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/components/contentprefs/tests/unit_cps2/xpcshell.ini]
|
||||
[include:toolkit/devtools/debugger/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/devtools/sourcemap/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/components/passwordmgr/test/unit/xpcshell.ini]
|
||||
|
798
toolkit/components/contentprefs/ContentPrefService2.jsm
Normal file
798
toolkit/components/contentprefs/ContentPrefService2.jsm
Normal file
@ -0,0 +1,798 @@
|
||||
/* 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/. */
|
||||
|
||||
// This file is an XPCOM component that implements nsIContentPrefService2.
|
||||
// Although it's a JSM, it's not intended to be imported by consumers like JSMs
|
||||
// are usually imported. It's only a JSM so that nsContentPrefService.js can
|
||||
// easily use it. Consumers should access this component with the usual XPCOM
|
||||
// rigmarole:
|
||||
//
|
||||
// Cc["@mozilla.org/content-pref/service;1"].
|
||||
// getService(Ci.nsIContentPrefService2);
|
||||
//
|
||||
// That contract ID actually belongs to nsContentPrefService.js, which, when
|
||||
// QI'ed to nsIContentPrefService2, returns an instance of this component.
|
||||
//
|
||||
// The plan is to eventually remove nsIContentPrefService and its
|
||||
// implementation, nsContentPrefService.js. At such time this file can stop
|
||||
// being a JSM, and the "_cps" parts that ContentPrefService2 relies on and
|
||||
// NSGetFactory and all the other XPCOM initialization goop in
|
||||
// nsContentPrefService.js can be moved here.
|
||||
//
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=699859
|
||||
|
||||
let EXPORTED_SYMBOLS = [
|
||||
"ContentPrefService2",
|
||||
];
|
||||
|
||||
const { interfaces: Ci, classes: Cc, results: Cr, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/ContentPrefStore.jsm");
|
||||
|
||||
function ContentPrefService2(cps) {
|
||||
this._cps = cps;
|
||||
this._cache = cps._cache;
|
||||
this._pbStore = cps._privModeStorage;
|
||||
}
|
||||
|
||||
ContentPrefService2.prototype = {
|
||||
|
||||
getByDomainAndName: function CPS2_getByDomainAndName(group, name, context,
|
||||
callback) {
|
||||
checkGroupArg(group);
|
||||
this._get(group, name, false, context, callback);
|
||||
},
|
||||
|
||||
getBySubdomainAndName: function CPS2_getBySubdomainAndName(group, name,
|
||||
context,
|
||||
callback) {
|
||||
checkGroupArg(group);
|
||||
this._get(group, name, true, context, callback);
|
||||
},
|
||||
|
||||
getGlobal: function CPS2_getGlobal(name, context, callback) {
|
||||
this._get(null, name, false, context, callback);
|
||||
},
|
||||
|
||||
_get: function CPS2__get(group, name, includeSubdomains, context, callback) {
|
||||
group = this._parseGroup(group);
|
||||
checkNameArg(name);
|
||||
checkCallbackArg(callback, true);
|
||||
|
||||
// Some prefs may be in both the database and the private browsing store.
|
||||
// Notify the caller of such prefs only once, using the values from private
|
||||
// browsing.
|
||||
let pbPrefs = new ContentPrefStore();
|
||||
if (context && context.usePrivateBrowsing) {
|
||||
for (let [sgroup, val] in
|
||||
this._pbStore.match(group, name, includeSubdomains)) {
|
||||
pbPrefs.set(sgroup, name, val);
|
||||
}
|
||||
}
|
||||
|
||||
this._execStmts([this._commonGetStmt(group, name, includeSubdomains)], {
|
||||
onRow: function onRow(row) {
|
||||
let grp = row.getResultByName("grp");
|
||||
let val = row.getResultByName("value");
|
||||
this._cache.set(grp, name, val);
|
||||
if (!pbPrefs.has(group, name))
|
||||
cbHandleResult(callback, new ContentPref(grp, name, val));
|
||||
},
|
||||
onDone: function onDone(reason, ok, gotRow) {
|
||||
if (ok) {
|
||||
if (!gotRow)
|
||||
this._cache.set(group, name, undefined);
|
||||
for (let [pbGroup, pbName, pbVal] in pbPrefs) {
|
||||
cbHandleResult(callback, new ContentPref(pbGroup, pbName, pbVal));
|
||||
}
|
||||
}
|
||||
cbHandleCompletion(callback, reason);
|
||||
},
|
||||
onError: function onError(nsresult) {
|
||||
cbHandleError(callback, nsresult);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_commonGetStmt: function CPS2__commonGetStmt(group, name, includeSubdomains) {
|
||||
let stmt = group ?
|
||||
this._stmtWithGroupClause(group, includeSubdomains,
|
||||
"SELECT groups.name AS grp, prefs.value AS value",
|
||||
"FROM prefs",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"JOIN groups ON groups.id = prefs.groupID",
|
||||
"WHERE settings.name = :name AND prefs.groupID IN ($)"
|
||||
) :
|
||||
this._stmt(
|
||||
"SELECT NULL AS grp, prefs.value AS value",
|
||||
"FROM prefs",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"WHERE settings.name = :name AND prefs.groupID ISNULL"
|
||||
);
|
||||
stmt.params.name = name;
|
||||
return stmt;
|
||||
},
|
||||
|
||||
_stmtWithGroupClause: function CPS2__stmtWithGroupClause(group,
|
||||
includeSubdomains) {
|
||||
let stmt = this._stmt(joinArgs(Array.slice(arguments, 2)).replace("$",
|
||||
"SELECT id " +
|
||||
"FROM groups " +
|
||||
"WHERE name = :group OR " +
|
||||
"(:includeSubdomains AND name LIKE :pattern ESCAPE '/')"
|
||||
));
|
||||
stmt.params.group = group;
|
||||
stmt.params.includeSubdomains = includeSubdomains || false;
|
||||
stmt.params.pattern = "%." + stmt.escapeStringForLIKE(group, "/");
|
||||
return stmt;
|
||||
},
|
||||
|
||||
getCachedByDomainAndName: function CPS2_getCachedByDomainAndName(group,
|
||||
name,
|
||||
context) {
|
||||
checkGroupArg(group);
|
||||
let prefs = this._getCached(group, name, false, context);
|
||||
return prefs[0] || null;
|
||||
},
|
||||
|
||||
getCachedBySubdomainAndName: function CPS2_getCachedBySubdomainAndName(group,
|
||||
name,
|
||||
context,
|
||||
len) {
|
||||
checkGroupArg(group);
|
||||
let prefs = this._getCached(group, name, true, context);
|
||||
if (len)
|
||||
len.value = prefs.length;
|
||||
return prefs;
|
||||
},
|
||||
|
||||
getCachedGlobal: function CPS2_getCachedGlobal(name, context) {
|
||||
let prefs = this._getCached(null, name, false, context);
|
||||
return prefs[0] || null;
|
||||
},
|
||||
|
||||
_getCached: function CPS2__getCached(group, name, includeSubdomains,
|
||||
context) {
|
||||
group = this._parseGroup(group);
|
||||
checkNameArg(name);
|
||||
|
||||
let storesToCheck = [this._cache];
|
||||
if (context && context.usePrivateBrowsing)
|
||||
storesToCheck.push(this._pbStore);
|
||||
|
||||
let outStore = new ContentPrefStore();
|
||||
storesToCheck.forEach(function (store) {
|
||||
for (let [sgroup, val] in store.match(group, name, includeSubdomains)) {
|
||||
outStore.set(sgroup, name, val);
|
||||
}
|
||||
});
|
||||
|
||||
let prefs = [];
|
||||
for (let [sgroup, sname, val] in outStore) {
|
||||
prefs.push(new ContentPref(sgroup, sname, val));
|
||||
}
|
||||
return prefs;
|
||||
},
|
||||
|
||||
set: function CPS2_set(group, name, value, context, callback) {
|
||||
checkGroupArg(group);
|
||||
this._set(group, name, value, context, callback);
|
||||
},
|
||||
|
||||
setGlobal: function CPS2_setGlobal(name, value, context, callback) {
|
||||
this._set(null, name, value, context, callback);
|
||||
},
|
||||
|
||||
_set: function CPS2__set(group, name, value, context, callback) {
|
||||
group = this._parseGroup(group);
|
||||
checkNameArg(name);
|
||||
checkValueArg(value);
|
||||
checkCallbackArg(callback, false);
|
||||
|
||||
if (context && context.usePrivateBrowsing) {
|
||||
this._pbStore.set(group, name, value);
|
||||
this._schedule(function () {
|
||||
this._cps._notifyPrefSet(group, name, value);
|
||||
cbHandleCompletion(callback, Ci.nsIContentPrefCallback2.COMPLETE_OK);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let stmts = [];
|
||||
|
||||
// Create the setting if it doesn't exist.
|
||||
let stmt = this._stmt(
|
||||
"INSERT OR IGNORE INTO settings (id, name)",
|
||||
"VALUES((SELECT id FROM settings WHERE name = :name), :name)"
|
||||
);
|
||||
stmt.params.name = name;
|
||||
stmts.push(stmt);
|
||||
|
||||
// Create the group if it doesn't exist.
|
||||
if (group) {
|
||||
stmt = this._stmt(
|
||||
"INSERT OR IGNORE INTO groups (id, name)",
|
||||
"VALUES((SELECT id FROM groups WHERE name = :group), :group)"
|
||||
);
|
||||
stmt.params.group = group;
|
||||
stmts.push(stmt);
|
||||
}
|
||||
|
||||
// Finally create or update the pref.
|
||||
if (group) {
|
||||
stmt = this._stmt(
|
||||
"INSERT OR REPLACE INTO prefs (id, groupID, settingID, value)",
|
||||
"VALUES(",
|
||||
"(SELECT prefs.id",
|
||||
"FROM prefs",
|
||||
"JOIN groups ON groups.id = prefs.groupID",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"WHERE groups.name = :group AND settings.name = :name),",
|
||||
"(SELECT id FROM groups WHERE name = :group),",
|
||||
"(SELECT id FROM settings WHERE name = :name),",
|
||||
":value",
|
||||
")"
|
||||
);
|
||||
stmt.params.group = group;
|
||||
}
|
||||
else {
|
||||
stmt = this._stmt(
|
||||
"INSERT OR REPLACE INTO prefs (id, groupID, settingID, value)",
|
||||
"VALUES(",
|
||||
"(SELECT prefs.id",
|
||||
"FROM prefs",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"WHERE prefs.groupID IS NULL AND settings.name = :name),",
|
||||
"NULL,",
|
||||
"(SELECT id FROM settings WHERE name = :name),",
|
||||
":value",
|
||||
")"
|
||||
);
|
||||
}
|
||||
stmt.params.name = name;
|
||||
stmt.params.value = value;
|
||||
stmts.push(stmt);
|
||||
|
||||
this._execStmts(stmts, {
|
||||
onDone: function onDone(reason, ok) {
|
||||
if (ok) {
|
||||
this._cache.setWithCast(group, name, value);
|
||||
this._cps._notifyPrefSet(group, name, value);
|
||||
}
|
||||
cbHandleCompletion(callback, reason);
|
||||
},
|
||||
onError: function onError(nsresult) {
|
||||
cbHandleError(callback, nsresult);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeByDomainAndName: function CPS2_removeByDomainAndName(group, name,
|
||||
context,
|
||||
callback) {
|
||||
checkGroupArg(group);
|
||||
this._remove(group, name, false, context, callback);
|
||||
},
|
||||
|
||||
removeBySubdomainAndName: function CPS2_removeBySubdomainAndName(group, name,
|
||||
context,
|
||||
callback) {
|
||||
checkGroupArg(group);
|
||||
this._remove(group, name, true, context, callback);
|
||||
},
|
||||
|
||||
removeGlobal: function CPS2_removeGlobal(name, context,callback) {
|
||||
this._remove(null, name, false, context, callback);
|
||||
},
|
||||
|
||||
_remove: function CPS2__remove(group, name, includeSubdomains, context,
|
||||
callback) {
|
||||
group = this._parseGroup(group);
|
||||
checkNameArg(name);
|
||||
checkCallbackArg(callback, false);
|
||||
|
||||
let stmts = [];
|
||||
|
||||
// First get the matching prefs.
|
||||
stmts.push(this._commonGetStmt(group, name, includeSubdomains));
|
||||
|
||||
// Delete the matching prefs.
|
||||
let stmt = this._stmtWithGroupClause(group, includeSubdomains,
|
||||
"DELETE FROM prefs",
|
||||
"WHERE settingID = (SELECT id FROM settings WHERE name = :name) AND",
|
||||
"CASE typeof(:group)",
|
||||
"WHEN 'null' THEN prefs.groupID IS NULL",
|
||||
"ELSE prefs.groupID IN ($)",
|
||||
"END"
|
||||
);
|
||||
stmt.params.name = name;
|
||||
stmts.push(stmt);
|
||||
|
||||
// Delete settings and groups that are no longer used. The NOTNULL term in
|
||||
// the subquery of the second statment is needed because of SQLite's weird
|
||||
// IN behavior vis-a-vis NULLs. See http://sqlite.org/lang_expr.html.
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM settings",
|
||||
"WHERE id NOT IN (SELECT DISTINCT settingID FROM prefs)"
|
||||
));
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM groups WHERE id NOT IN (",
|
||||
"SELECT DISTINCT groupID FROM prefs WHERE groupID NOTNULL",
|
||||
")"
|
||||
));
|
||||
|
||||
let prefs = new ContentPrefStore();
|
||||
|
||||
this._execStmts(stmts, {
|
||||
onRow: function onRow(row) {
|
||||
let grp = row.getResultByName("grp");
|
||||
prefs.set(grp, name);
|
||||
this._cache.set(grp, name, undefined);
|
||||
},
|
||||
onDone: function onDone(reason, ok) {
|
||||
if (ok) {
|
||||
this._cache.set(group, name, undefined);
|
||||
if (context && context.usePrivateBrowsing) {
|
||||
for (let [sgroup, ] in
|
||||
this._pbStore.match(group, name, includeSubdomains)) {
|
||||
prefs.set(sgroup, name);
|
||||
this._pbStore.remove(sgroup, name);
|
||||
}
|
||||
}
|
||||
for (let [sgroup, , ] in prefs) {
|
||||
this._cps._notifyPrefRemoved(sgroup, name);
|
||||
}
|
||||
}
|
||||
cbHandleCompletion(callback, reason);
|
||||
},
|
||||
onError: function onError(nsresult) {
|
||||
cbHandleError(callback, nsresult);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeByDomain: function CPS2_removeByDomain(group, context, callback) {
|
||||
checkGroupArg(group);
|
||||
this._removeByDomain(group, false, context, callback);
|
||||
},
|
||||
|
||||
removeBySubdomain: function CPS2_removeBySubdomain(group, context, callback) {
|
||||
checkGroupArg(group);
|
||||
this._removeByDomain(group, true, context, callback);
|
||||
},
|
||||
|
||||
removeAllGlobals: function CPS2_removeAllGlobals(context, callback) {
|
||||
this._removeByDomain(null, false, context, callback);
|
||||
},
|
||||
|
||||
_removeByDomain: function CPS2__removeByDomain(group, includeSubdomains,
|
||||
context, callback) {
|
||||
group = this._parseGroup(group);
|
||||
checkCallbackArg(callback, false);
|
||||
|
||||
let stmts = [];
|
||||
|
||||
// First get the matching prefs, then delete groups and prefs that reference
|
||||
// deleted groups.
|
||||
if (group) {
|
||||
stmts.push(this._stmtWithGroupClause(group, includeSubdomains,
|
||||
"SELECT groups.name AS grp, settings.name AS name",
|
||||
"FROM prefs",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"JOIN groups ON groups.id = prefs.groupID",
|
||||
"WHERE prefs.groupID IN ($)"
|
||||
));
|
||||
stmts.push(this._stmtWithGroupClause(group, includeSubdomains,
|
||||
"DELETE FROM groups WHERE id IN ($)"
|
||||
));
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM prefs",
|
||||
"WHERE groupID NOTNULL AND groupID NOT IN (SELECT id FROM groups)"
|
||||
));
|
||||
}
|
||||
else {
|
||||
stmts.push(this._stmt(
|
||||
"SELECT NULL AS grp, settings.name AS name",
|
||||
"FROM prefs",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"WHERE prefs.groupID IS NULL"
|
||||
));
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM prefs WHERE groupID IS NULL"
|
||||
));
|
||||
}
|
||||
|
||||
// Finally delete settings that are no longer referenced.
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM settings",
|
||||
"WHERE id NOT IN (SELECT DISTINCT settingID FROM prefs)"
|
||||
));
|
||||
|
||||
let prefs = new ContentPrefStore();
|
||||
|
||||
this._execStmts(stmts, {
|
||||
onRow: function onRow(row) {
|
||||
let grp = row.getResultByName("grp");
|
||||
let name = row.getResultByName("name");
|
||||
prefs.set(grp, name);
|
||||
this._cache.set(grp, name, undefined);
|
||||
},
|
||||
onDone: function onDone(reason, ok) {
|
||||
if (ok) {
|
||||
if (context && context.usePrivateBrowsing) {
|
||||
for (let [sgroup, sname, ] in this._pbStore) {
|
||||
prefs.set(sgroup, sname);
|
||||
this._pbStore.remove(sgroup, sname);
|
||||
}
|
||||
}
|
||||
for (let [sgroup, sname, ] in prefs) {
|
||||
this._cps._notifyPrefRemoved(sgroup, sname);
|
||||
}
|
||||
}
|
||||
cbHandleCompletion(callback, reason);
|
||||
},
|
||||
onError: function onError(nsresult) {
|
||||
cbHandleError(callback, nsresult);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeAllDomains: function CPS2_removeAllDomains(context, callback) {
|
||||
checkCallbackArg(callback, false);
|
||||
let stmts = [];
|
||||
|
||||
// First get the matching prefs.
|
||||
stmts.push(this._stmt(
|
||||
"SELECT groups.name AS grp, settings.name AS name",
|
||||
"FROM prefs",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"JOIN groups ON groups.id = prefs.groupID"
|
||||
));
|
||||
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM prefs WHERE groupID NOTNULL"
|
||||
));
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM groups"
|
||||
));
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM settings",
|
||||
"WHERE id NOT IN (SELECT DISTINCT settingID FROM prefs)"
|
||||
));
|
||||
|
||||
let prefs = new ContentPrefStore();
|
||||
|
||||
this._execStmts(stmts, {
|
||||
onRow: function onRow(row) {
|
||||
let grp = row.getResultByName("grp");
|
||||
let name = row.getResultByName("name");
|
||||
prefs.set(grp, name);
|
||||
this._cache.set(grp, name, undefined);
|
||||
},
|
||||
onDone: function onDone(reason, ok) {
|
||||
if (ok) {
|
||||
if (context && context.usePrivateBrowsing) {
|
||||
for (let [sgroup, sname, ] in this._pbStore) {
|
||||
prefs.set(sgroup, sname);
|
||||
}
|
||||
this._pbStore.removeGrouped();
|
||||
}
|
||||
for (let [sgroup, sname, ] in prefs) {
|
||||
this._cps._notifyPrefRemoved(sgroup, sname);
|
||||
}
|
||||
}
|
||||
cbHandleCompletion(callback, reason);
|
||||
},
|
||||
onError: function onError(nsresult) {
|
||||
cbHandleError(callback, nsresult);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeByName: function CPS2_removeByName(name, context, callback) {
|
||||
checkNameArg(name);
|
||||
checkCallbackArg(callback, false);
|
||||
|
||||
let stmts = [];
|
||||
|
||||
// First get the matching prefs. Include null if any of those prefs are
|
||||
// global.
|
||||
let stmt = this._stmt(
|
||||
"SELECT groups.name AS grp",
|
||||
"FROM prefs",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"JOIN groups ON groups.id = prefs.groupID",
|
||||
"WHERE settings.name = :name",
|
||||
"UNION",
|
||||
"SELECT NULL AS grp",
|
||||
"WHERE EXISTS (",
|
||||
"SELECT prefs.id",
|
||||
"FROM prefs",
|
||||
"JOIN settings ON settings.id = prefs.settingID",
|
||||
"WHERE settings.name = :name AND prefs.groupID IS NULL",
|
||||
")"
|
||||
);
|
||||
stmt.params.name = name;
|
||||
stmts.push(stmt);
|
||||
|
||||
// Delete the target settings.
|
||||
stmt = this._stmt(
|
||||
"DELETE FROM settings WHERE name = :name"
|
||||
);
|
||||
stmt.params.name = name;
|
||||
stmts.push(stmt);
|
||||
|
||||
// Delete prefs and groups that are no longer used.
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM prefs WHERE settingID NOT IN (SELECT id FROM settings)"
|
||||
));
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM groups WHERE id NOT IN (",
|
||||
"SELECT DISTINCT groupID FROM prefs WHERE groupID NOTNULL",
|
||||
")"
|
||||
));
|
||||
|
||||
let prefs = new ContentPrefStore();
|
||||
|
||||
this._execStmts(stmts, {
|
||||
onRow: function onRow(row) {
|
||||
let grp = row.getResultByName("grp");
|
||||
prefs.set(grp, name);
|
||||
this._cache.set(grp, name, undefined);
|
||||
},
|
||||
onDone: function onDone(reason, ok) {
|
||||
if (ok) {
|
||||
if (context && context.usePrivateBrowsing) {
|
||||
for (let [sgroup, sname, ] in this._pbStore) {
|
||||
if (sname === name) {
|
||||
prefs.set(sgroup, name);
|
||||
this._pbStore.remove(sgroup, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let [sgroup, , ] in prefs) {
|
||||
this._cps._notifyPrefRemoved(sgroup, name);
|
||||
}
|
||||
}
|
||||
cbHandleCompletion(callback, reason);
|
||||
},
|
||||
onError: function onError(nsresult) {
|
||||
cbHandleError(callback, nsresult);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function CPS2_destroy() {
|
||||
for each (let stmt in this._statements) {
|
||||
stmt.finalize();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the cached mozIStorageAsyncStatement for the given SQL. If no such
|
||||
* statement is cached, one is created and cached.
|
||||
*
|
||||
* @param sql The SQL query string. If more than one string is given, then
|
||||
* all are concatenated. The concatenation process inserts
|
||||
* spaces where appropriate and removes unnecessary contiguous
|
||||
* spaces. Call like _stmt("SELECT *", "FROM foo").
|
||||
* @return The cached, possibly new, statement.
|
||||
*/
|
||||
_stmt: function CPS2__stmt(sql /*, sql2, sql3, ... */) {
|
||||
let sql = joinArgs(arguments);
|
||||
if (!this._statements)
|
||||
this._statements = {};
|
||||
if (!this._statements[sql])
|
||||
this._statements[sql] = this._cps._dbConnection.createAsyncStatement(sql);
|
||||
return this._statements[sql];
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes some async statements.
|
||||
*
|
||||
* @param stmts An array of mozIStorageAsyncStatements.
|
||||
* @param callbacks An object with the following methods:
|
||||
* onRow(row) (optional)
|
||||
* Called once for each result row.
|
||||
* row: A mozIStorageRow.
|
||||
* onDone(reason, reasonOK, didGetRow) (required)
|
||||
* Called when done.
|
||||
* reason: A nsIContentPrefService2.COMPLETE_* value.
|
||||
* reasonOK: reason == nsIContentPrefService2.COMPLETE_OK.
|
||||
* didGetRow: True if onRow was ever called.
|
||||
* onError(nsresult) (optional)
|
||||
* Called on error.
|
||||
* nsresult: The error code.
|
||||
*/
|
||||
_execStmts: function CPS2__execStmts(stmts, callbacks) {
|
||||
let self = this;
|
||||
let gotRow = false;
|
||||
this._cps._dbConnection.executeAsync(stmts, stmts.length, {
|
||||
handleResult: function handleResult(results) {
|
||||
try {
|
||||
let row = null;
|
||||
while ((row = results.getNextRow())) {
|
||||
gotRow = true;
|
||||
if (callbacks.onRow)
|
||||
callbacks.onRow.call(self, row);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
},
|
||||
handleCompletion: function handleCompletion(reason) {
|
||||
try {
|
||||
let ok = reason == Ci.mozIStorageStatementCallback.REASON_FINISHED;
|
||||
callbacks.onDone.call(self,
|
||||
ok ? Ci.nsIContentPrefCallback2.COMPLETE_OK :
|
||||
Ci.nsIContentPrefCallback2.COMPLETE_ERROR,
|
||||
ok, gotRow);
|
||||
}
|
||||
catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
},
|
||||
handleError: function handleError(error) {
|
||||
try {
|
||||
if (callbacks.onError)
|
||||
callbacks.onError.call(self, Cr.NS_ERROR_FAILURE);
|
||||
}
|
||||
catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses the domain (the "group", to use the database's term) from the given
|
||||
* string.
|
||||
*
|
||||
* @param groupStr Assumed to be either a string or falsey.
|
||||
* @return If groupStr is a valid URL string, returns the domain of
|
||||
* that URL. If groupStr is some other nonempty string,
|
||||
* returns groupStr itself. Otherwise returns null.
|
||||
*/
|
||||
_parseGroup: function CPS2__parseGroup(groupStr) {
|
||||
if (!groupStr)
|
||||
return null;
|
||||
try {
|
||||
var groupURI = Services.io.newURI(groupStr, null, null);
|
||||
}
|
||||
catch (err) {
|
||||
return groupStr;
|
||||
}
|
||||
return this._cps.grouper.group(groupURI);
|
||||
},
|
||||
|
||||
_schedule: function CPS2__schedule(fn) {
|
||||
Services.tm.mainThread.dispatch(fn.bind(this),
|
||||
Ci.nsIThread.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
addObserverForName: function CPS2_addObserverForName(name, observer) {
|
||||
this._cps.addObserver(name, observer);
|
||||
},
|
||||
|
||||
removeObserverForName: function CPS2_removeObserverForName(name, observer) {
|
||||
this._cps.removeObserver(name, observer);
|
||||
},
|
||||
|
||||
/**
|
||||
* Tests use this as a backchannel by calling it directly.
|
||||
*
|
||||
* @param subj This value depends on topic.
|
||||
* @param topic The backchannel "method" name.
|
||||
* @param data This value depends on topic.
|
||||
*/
|
||||
observe: function CPS2_observe(subj, topic, data) {
|
||||
switch (topic) {
|
||||
case "test:reset":
|
||||
let fn = subj.QueryInterface(Ci.xpcIJSWeakReference).get();
|
||||
this._reset(fn);
|
||||
break;
|
||||
case "test:db":
|
||||
let obj = subj.QueryInterface(Ci.xpcIJSWeakReference).get();
|
||||
obj.value = this._cps._dbConnection;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all state from the service. Used by tests.
|
||||
*
|
||||
* @param callback A function that will be called when done.
|
||||
*/
|
||||
_reset: function CPS2__reset(callback) {
|
||||
this._pbStore.removeAll();
|
||||
this._cache.removeAll();
|
||||
|
||||
let cps = this._cps;
|
||||
cps._observers = {};
|
||||
cps._genericObservers = [];
|
||||
|
||||
let tables = ["prefs", "groups", "settings"];
|
||||
let stmts = tables.map(function (t) this._stmt("DELETE FROM", t), this);
|
||||
this._execStmts(stmts, { onDone: function () callback() });
|
||||
},
|
||||
|
||||
QueryInterface: function CPS2_QueryInterface(iid) {
|
||||
let supportedIIDs = [
|
||||
Ci.nsIContentPrefService,
|
||||
Ci.nsIObserver,
|
||||
Ci.nsISupports,
|
||||
];
|
||||
if (supportedIIDs.some(function (i) iid.equals(i)))
|
||||
return this;
|
||||
if (iid.equals(Ci.nsIContentPrefService))
|
||||
return this._cps;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
};
|
||||
|
||||
function ContentPref(domain, name, value) {
|
||||
this.domain = domain;
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
ContentPref.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPref]),
|
||||
};
|
||||
|
||||
function cbHandleResult(callback, pref) {
|
||||
safeCallback(callback, "handleResult", [pref]);
|
||||
}
|
||||
|
||||
function cbHandleCompletion(callback, reason) {
|
||||
safeCallback(callback, "handleCompletion", [reason]);
|
||||
}
|
||||
|
||||
function cbHandleError(callback, nsresult) {
|
||||
safeCallback(callback, "handleError", [nsresult]);
|
||||
}
|
||||
|
||||
function safeCallback(callbackObj, methodName, args) {
|
||||
if (!callbackObj || typeof(callbackObj[methodName]) != "function")
|
||||
return;
|
||||
try {
|
||||
callbackObj[methodName].apply(callbackObj, args);
|
||||
}
|
||||
catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
}
|
||||
|
||||
function checkGroupArg(group) {
|
||||
if (!group || typeof(group) != "string")
|
||||
throw invalidArg("domain must be nonempty string.");
|
||||
}
|
||||
|
||||
function checkNameArg(name) {
|
||||
if (!name || typeof(name) != "string")
|
||||
throw invalidArg("name must be nonempty string.");
|
||||
}
|
||||
|
||||
function checkValueArg(value) {
|
||||
if (value === undefined)
|
||||
throw invalidArg("value must not be undefined.");
|
||||
}
|
||||
|
||||
function checkCallbackArg(callback, required) {
|
||||
if (callback && !(callback instanceof Ci.nsIContentPrefCallback2))
|
||||
throw invalidArg("callback must be an nsIContentPrefCallback2.");
|
||||
if (!callback && required)
|
||||
throw invalidArg("callback must be given.");
|
||||
}
|
||||
|
||||
function invalidArg(msg) {
|
||||
return Components.Exception(msg, Cr.NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
|
||||
function joinArgs(args) {
|
||||
return Array.join(args, " ").trim().replace(/\s{2,}/g, " ");
|
||||
}
|
115
toolkit/components/contentprefs/ContentPrefStore.jsm
Normal file
115
toolkit/components/contentprefs/ContentPrefStore.jsm
Normal file
@ -0,0 +1,115 @@
|
||||
/* 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 EXPORTED_SYMBOLS = [
|
||||
"ContentPrefStore",
|
||||
];
|
||||
|
||||
function ContentPrefStore() {
|
||||
this._groups = {};
|
||||
this._globalNames = {};
|
||||
}
|
||||
|
||||
ContentPrefStore.prototype = {
|
||||
|
||||
set: function CPS_set(group, name, val) {
|
||||
if (group) {
|
||||
if (!this._groups.hasOwnProperty(group))
|
||||
this._groups[group] = {};
|
||||
this._groups[group][name] = val;
|
||||
}
|
||||
else {
|
||||
this._globalNames[name] = val;
|
||||
}
|
||||
},
|
||||
|
||||
setWithCast: function CPS_setWithCast(group, name, val) {
|
||||
if (typeof(val) == "boolean")
|
||||
val = val ? 1 : 0;
|
||||
else if (val === undefined)
|
||||
val = null;
|
||||
this.set(group, name, val);
|
||||
},
|
||||
|
||||
has: function CPS_has(group, name) {
|
||||
return (group &&
|
||||
this._groups.hasOwnProperty(group) &&
|
||||
this._groups[group].hasOwnProperty(name)) ||
|
||||
(!group &&
|
||||
this._globalNames.hasOwnProperty(name));
|
||||
},
|
||||
|
||||
get: function CPS_get(group, name) {
|
||||
if (group) {
|
||||
if (this._groups.hasOwnProperty(group) &&
|
||||
this._groups[group].hasOwnProperty(name))
|
||||
return this._groups[group][name];
|
||||
}
|
||||
else if (this._globalNames.hasOwnProperty(name)) {
|
||||
return this._globalNames[name];
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
remove: function CPS_remove(group, name) {
|
||||
if (group) {
|
||||
if (this._groups.hasOwnProperty(group)) {
|
||||
delete this._groups[group][name];
|
||||
if (!Object.keys(this._groups[group]).length)
|
||||
delete this._groups[group];
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete this._globalNames[name];
|
||||
}
|
||||
},
|
||||
|
||||
removeGrouped: function CPS_removeGrouped() {
|
||||
this._groups = {};
|
||||
},
|
||||
|
||||
removeAll: function CPS_removeAll() {
|
||||
this.removeGrouped();
|
||||
this._globalNames = {};
|
||||
},
|
||||
|
||||
__iterator__: function CPS___iterator__() {
|
||||
for (let [group, names] in Iterator(this._groups)) {
|
||||
for (let [name, val] in Iterator(names)) {
|
||||
yield [group, name, val];
|
||||
}
|
||||
}
|
||||
for (let [name, val] in Iterator(this._globalNames)) {
|
||||
yield [null, name, val];
|
||||
}
|
||||
},
|
||||
|
||||
match: function CPS_match(group, name, includeSubdomains) {
|
||||
for (let sgroup in this.matchGroups(group, includeSubdomains)) {
|
||||
if (this.has(sgroup, name))
|
||||
yield [sgroup, this.get(sgroup, name)];
|
||||
}
|
||||
},
|
||||
|
||||
matchGroups: function CPS_matchGroups(group, includeSubdomains) {
|
||||
if (group) {
|
||||
if (includeSubdomains) {
|
||||
for (let [sgroup, , ] in this) {
|
||||
if (sgroup) {
|
||||
let idx = sgroup.indexOf(group);
|
||||
if (idx == sgroup.length - group.length &&
|
||||
(idx == 0 || sgroup[idx - 1] == "."))
|
||||
yield sgroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this._groups.hasOwnProperty(group)) {
|
||||
yield group;
|
||||
}
|
||||
}
|
||||
else if (Object.keys(this._globalNames).length) {
|
||||
yield null;
|
||||
}
|
||||
},
|
||||
};
|
@ -11,9 +11,16 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = contentprefs
|
||||
|
||||
EXTRA_COMPONENTS = nsContentPrefService.js nsContentPrefService.manifest
|
||||
EXTRA_COMPONENTS = \
|
||||
nsContentPrefService.js \
|
||||
nsContentPrefService.manifest \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_JS_MODULES = ContentPrefInstance.jsm
|
||||
EXTRA_JS_MODULES = \
|
||||
ContentPrefInstance.jsm \
|
||||
ContentPrefService2.jsm \
|
||||
ContentPrefStore.jsm \
|
||||
$(NULL)
|
||||
|
||||
TEST_DIRS += tests
|
||||
|
||||
|
@ -106,61 +106,48 @@ function ContentPrefService() {
|
||||
this._observerSvc.addObserver(this, "xpcom-shutdown", false);
|
||||
}
|
||||
|
||||
var inMemoryPrefsProto = {
|
||||
getPref: function(aName, aGroup) {
|
||||
aGroup = aGroup || "__GlobalPrefs__";
|
||||
|
||||
if (this._prefCache[aGroup] && this._prefCache[aGroup].has(aName)) {
|
||||
let value = this._prefCache[aGroup].get(aName);
|
||||
return [true, value];
|
||||
}
|
||||
return [false, undefined];
|
||||
},
|
||||
|
||||
setPref: function(aName, aValue, aGroup) {
|
||||
if (typeof aValue == "boolean")
|
||||
aValue = aValue ? 1 : 0;
|
||||
else if (aValue === undefined)
|
||||
aValue = null;
|
||||
|
||||
this.cachePref(aName, aValue, aGroup);
|
||||
},
|
||||
|
||||
removePref: function(aName, aGroup) {
|
||||
aGroup = aGroup || "__GlobalPrefs__";
|
||||
|
||||
if (this._prefCache[aGroup].has(aName)) {
|
||||
this._prefCache[aGroup].delete(aName);
|
||||
if (this._prefCache[aGroup].size == 0) {
|
||||
// remove empty group
|
||||
delete this._prefCache[aGroup];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
invalidate: function(aKeepGlobal) {
|
||||
if (!aKeepGlobal) {
|
||||
this._prefCache = {};
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._prefCache.hasOwnProperty("__GlobalPrefs__")) {
|
||||
let globals = this._prefCache["__GlobalPrefs__"];
|
||||
this._prefCache = {"__GlobalPrefs__": globals};
|
||||
} else {
|
||||
this._prefCache = {};
|
||||
Cu.import("resource://gre/modules/ContentPrefStore.jsm");
|
||||
const cache = new ContentPrefStore();
|
||||
cache.set = function CPS_cache_set(group, name, val) {
|
||||
Object.getPrototypeOf(this).set.apply(this, arguments);
|
||||
let groupCount = Object.keys(this._groups).length;
|
||||
if (groupCount >= CACHE_MAX_GROUP_ENTRIES) {
|
||||
// Clean half of the entries
|
||||
for (let [group, name, ] in this) {
|
||||
this.remove(group, name);
|
||||
groupCount--;
|
||||
if (groupCount < CACHE_MAX_GROUP_ENTRIES / 2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const privModeStorage = new ContentPrefStore();
|
||||
|
||||
ContentPrefService.prototype = {
|
||||
//**************************************************************************//
|
||||
// XPCOM Plumbing
|
||||
|
||||
classID: Components.ID("{e3f772f3-023f-4b32-b074-36cf0fd5d414}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPrefService,
|
||||
Ci.nsIMessageListener]),
|
||||
classID: Components.ID("{e3f772f3-023f-4b32-b074-36cf0fd5d414}"),
|
||||
|
||||
QueryInterface: function CPS_QueryInterface(iid) {
|
||||
let supportedIIDs = [
|
||||
Ci.nsIContentPrefService,
|
||||
Ci.nsIFrameMessageListener,
|
||||
Ci.nsISupports,
|
||||
];
|
||||
if (supportedIIDs.some(function (i) iid.equals(i)))
|
||||
return this;
|
||||
if (iid.equals(Ci.nsIContentPrefService2)) {
|
||||
if (!this._contentPrefService2) {
|
||||
let s = {};
|
||||
Cu.import("resource://gre/modules/ContentPrefService2.jsm", s);
|
||||
this._contentPrefService2 = new s.ContentPrefService2(this);
|
||||
}
|
||||
return this._contentPrefService2;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
//**************************************************************************//
|
||||
// Convenience Getters
|
||||
@ -263,6 +250,9 @@ ContentPrefService.prototype = {
|
||||
this.__stmtUpdatePref = null;
|
||||
}
|
||||
|
||||
if (this._contentPrefService2)
|
||||
this._contentPrefService2.destroy();
|
||||
|
||||
this._dbConnection.asyncClose();
|
||||
|
||||
// Delete references to XPCOM components to make sure we don't leak them
|
||||
@ -286,94 +276,17 @@ ContentPrefService.prototype = {
|
||||
this._destroy();
|
||||
break;
|
||||
case "last-pb-context-exited":
|
||||
this._privModeStorage.invalidate();
|
||||
this._privModeStorage.removeAll();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Prefs cache
|
||||
_cache: Object.create(inMemoryPrefsProto, {
|
||||
_prefCache: {
|
||||
value: {}, configurable: true, writable: true, enumerable: true
|
||||
},
|
||||
// in-memory cache and private-browsing stores
|
||||
|
||||
cachePref: { value:
|
||||
function(aName, aValue, aGroup) {
|
||||
aGroup = aGroup || "__GlobalPrefs__";
|
||||
|
||||
if (!this._prefCache[aGroup]) {
|
||||
this._possiblyCleanCache();
|
||||
this._prefCache[aGroup] = new Map();
|
||||
}
|
||||
|
||||
this._prefCache[aGroup].set(aName, aValue);
|
||||
}
|
||||
},
|
||||
|
||||
_possiblyCleanCache: { value:
|
||||
function() {
|
||||
let groupCount = Object.keys(this._prefCache).length;
|
||||
|
||||
if (groupCount >= CACHE_MAX_GROUP_ENTRIES) {
|
||||
// Clean half of the entries
|
||||
for (let entry in this._prefCache) {
|
||||
delete this._prefCache[entry];
|
||||
groupCount--;
|
||||
|
||||
if (groupCount < CACHE_MAX_GROUP_ENTRIES / 2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
//**************************************************************************//
|
||||
// Private mode storage
|
||||
_privModeStorage: Object.create(inMemoryPrefsProto, {
|
||||
_prefCache: {
|
||||
value: {}, configurable: true, writable: true, enumerable: true
|
||||
},
|
||||
|
||||
cachePref: { value:
|
||||
function(aName, aValue, aGroup) {
|
||||
aGroup = aGroup || "__GlobalPrefs__";
|
||||
|
||||
if (!this._prefCache[aGroup]) {
|
||||
this._prefCache[aGroup] = new Map();
|
||||
}
|
||||
|
||||
this._prefCache[aGroup].set(aName, aValue);
|
||||
}
|
||||
},
|
||||
|
||||
getPrefs: { value:
|
||||
function(aGroup) {
|
||||
aGroup = aGroup || "__GlobalPrefs__";
|
||||
if (this._prefCache[aGroup]) {
|
||||
return [true, this._prefCache[aGroup]];
|
||||
}
|
||||
return [false, undefined];
|
||||
}
|
||||
},
|
||||
|
||||
groupsForName: { value:
|
||||
function(aName) {
|
||||
var res = [];
|
||||
for (let entry in this._prefCache) {
|
||||
if (this._prefCache[entry]) {
|
||||
if (entry === "__GlobalPrefs__") {
|
||||
entry = null;
|
||||
}
|
||||
res.push(entry);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}),
|
||||
_cache: cache,
|
||||
_privModeStorage: privModeStorage,
|
||||
|
||||
//**************************************************************************//
|
||||
// nsIContentPrefService
|
||||
@ -386,8 +299,8 @@ ContentPrefService.prototype = {
|
||||
var group = this._parseGroupParam(aGroup);
|
||||
|
||||
if (aContext && aContext.usePrivateBrowsing) {
|
||||
let [haspref, value] = this._privModeStorage.getPref(aName, group);
|
||||
if (haspref) {
|
||||
if (this._privModeStorage.has(group, aName)) {
|
||||
let value = this._privModeStorage.get(group, aName);
|
||||
if (aCallback) {
|
||||
this._scheduleCallback(function(){aCallback.onResult(value);});
|
||||
return;
|
||||
@ -414,7 +327,7 @@ ContentPrefService.prototype = {
|
||||
var group = this._parseGroupParam(aGroup);
|
||||
|
||||
if (aContext && aContext.usePrivateBrowsing) {
|
||||
this._privModeStorage.setPref(aName, aValue, group);
|
||||
this._privModeStorage.setWithCast(group, aName, aValue);
|
||||
this._notifyPrefSet(group, aName, aValue);
|
||||
return;
|
||||
}
|
||||
@ -436,7 +349,7 @@ ContentPrefService.prototype = {
|
||||
else
|
||||
this._insertPref(groupID, settingID, aValue);
|
||||
|
||||
this._cache.setPref(aName, aValue, group);
|
||||
this._cache.setWithCast(group, aName, aValue);
|
||||
|
||||
this._notifyPrefSet(group, aName, aValue);
|
||||
},
|
||||
@ -454,8 +367,7 @@ ContentPrefService.prototype = {
|
||||
|
||||
let group = this._parseGroupParam(aGroup);
|
||||
let storage = aContext && aContext.usePrivateBrowsing ? this._privModeStorage: this._cache;
|
||||
let [cached,] = storage.getPref(aName, group);
|
||||
return cached;
|
||||
return storage.has(group, aName);
|
||||
},
|
||||
|
||||
removePref: function ContentPrefService_removePref(aGroup, aName, aContext) {
|
||||
@ -466,7 +378,7 @@ ContentPrefService.prototype = {
|
||||
var group = this._parseGroupParam(aGroup);
|
||||
|
||||
if (aContext && aContext.usePrivateBrowsing) {
|
||||
this._privModeStorage.removePref(aName, group);
|
||||
this._privModeStorage.remove(group, aName);
|
||||
this._notifyPrefRemoved(group, aName);
|
||||
return;
|
||||
}
|
||||
@ -489,7 +401,7 @@ ContentPrefService.prototype = {
|
||||
if (groupID)
|
||||
this._deleteGroupIfUnused(groupID);
|
||||
|
||||
this._cache.removePref(aName, group);
|
||||
this._cache.remove(group, aName);
|
||||
this._notifyPrefRemoved(group, aName);
|
||||
},
|
||||
|
||||
@ -497,9 +409,9 @@ ContentPrefService.prototype = {
|
||||
// will not delete global preferences
|
||||
if (aContext && aContext.usePrivateBrowsing) {
|
||||
// keep only global prefs
|
||||
this._privModeStorage.invalidate(true);
|
||||
this._privModeStorage.removeGrouped();
|
||||
}
|
||||
this._cache.invalidate(true);
|
||||
this._cache.removeGrouped();
|
||||
this._dbConnection.beginTransaction();
|
||||
try {
|
||||
this._dbConnection.executeSimpleSQL("DELETE FROM prefs WHERE groupID IS NOT NULL");
|
||||
@ -522,11 +434,11 @@ ContentPrefService.prototype = {
|
||||
Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
if (aContext && aContext.usePrivateBrowsing) {
|
||||
let groupNames = this._privModeStorage.groupsForName(aName);
|
||||
for (var i = 0; i < groupNames.length; i++) {
|
||||
let groupName = groupNames[i];
|
||||
this._privModeStorage.removePref(aName, groupName);
|
||||
this._notifyPrefRemoved(groupName, aName);
|
||||
for (let [group, name, ] in this._privModeStorage) {
|
||||
if (name === aName) {
|
||||
this._privModeStorage.remove(group, aName);
|
||||
this._notifyPrefRemoved(group, aName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,7 +475,7 @@ ContentPrefService.prototype = {
|
||||
this._dbConnection.executeSimpleSQL("DELETE FROM settings WHERE id = " + settingID);
|
||||
|
||||
for (var i = 0; i < groupNames.length; i++) {
|
||||
this._cache.removePref(aName, groupNames[i]);
|
||||
this._cache.remove(groupNames[i], aName);
|
||||
if (groupNames[i]) // ie. not null, which will be last (and i == groupIDs.length)
|
||||
this._deleteGroupIfUnused(groupIDs[i]);
|
||||
if (!aContext || !aContext.usePrivateBrowsing) {
|
||||
@ -577,9 +489,9 @@ ContentPrefService.prototype = {
|
||||
if (aContext && aContext.usePrivateBrowsing) {
|
||||
let prefs = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag);
|
||||
let [hasbranch,properties] = this._privModeStorage.getPrefs(group);
|
||||
for (let [entry, value] of properties) {
|
||||
prefs.setProperty(entry, value);
|
||||
for (let [sgroup, sname, sval] in this._privModeStorage) {
|
||||
if (sgroup === group)
|
||||
prefs.setProperty(sname, sval);
|
||||
}
|
||||
return prefs;
|
||||
}
|
||||
@ -597,11 +509,9 @@ ContentPrefService.prototype = {
|
||||
if (aContext && aContext.usePrivateBrowsing) {
|
||||
let prefs = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag);
|
||||
let groupNames = this._privModeStorage.groupsForName(aName);
|
||||
for (var i = 0; i < groupNames.length; i++) {
|
||||
let groupName = groupNames[i];
|
||||
prefs.setProperty(groupName,
|
||||
this._privModeStorage.getPref(aName, groupName)[1]);
|
||||
for (let [sgroup, sname, sval] in this._privModeStorage) {
|
||||
if (sname === aName)
|
||||
prefs.setProperty(sgroup, sval);
|
||||
}
|
||||
return prefs;
|
||||
}
|
||||
@ -719,8 +629,9 @@ ContentPrefService.prototype = {
|
||||
},
|
||||
|
||||
_selectPref: function ContentPrefService__selectPref(aGroup, aSetting, aCallback) {
|
||||
let [cached, value] = this._cache.getPref(aSetting, aGroup);
|
||||
if (cached) {
|
||||
let value = undefined;
|
||||
if (this._cache.has(aGroup, aSetting)) {
|
||||
value = this._cache.get(aGroup, aSetting);
|
||||
if (aCallback) {
|
||||
this._scheduleCallback(function(){aCallback.onResult(value);});
|
||||
return;
|
||||
@ -735,7 +646,7 @@ ContentPrefService.prototype = {
|
||||
if (aCallback) {
|
||||
let cache = this._cache;
|
||||
new AsyncStatement(this._stmtSelectPref).execute({onResult: function(aResult) {
|
||||
cache.cachePref(aSetting, aResult, aGroup);
|
||||
cache.set(aGroup, aSetting, aResult);
|
||||
aCallback.onResult(aResult);
|
||||
}});
|
||||
}
|
||||
@ -743,7 +654,7 @@ ContentPrefService.prototype = {
|
||||
if (this._stmtSelectPref.executeStep()) {
|
||||
value = this._stmtSelectPref.row["value"];
|
||||
}
|
||||
this._cache.cachePref(aSetting, value, aGroup);
|
||||
this._cache.set(aGroup, aSetting, value);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@ -768,8 +679,9 @@ ContentPrefService.prototype = {
|
||||
},
|
||||
|
||||
_selectGlobalPref: function ContentPrefService__selectGlobalPref(aName, aCallback) {
|
||||
let [cached, value] = this._cache.getPref(aName, null);
|
||||
if (cached) {
|
||||
let value = undefined;
|
||||
if (this._cache.has(null, aName)) {
|
||||
value = this._cache.get(null, aName);
|
||||
if (aCallback) {
|
||||
this._scheduleCallback(function(){aCallback.onResult(value);});
|
||||
return;
|
||||
@ -783,7 +695,7 @@ ContentPrefService.prototype = {
|
||||
if (aCallback) {
|
||||
let cache = this._cache;
|
||||
new AsyncStatement(this._stmtSelectGlobalPref).execute({onResult: function(aResult) {
|
||||
cache.cachePref(aName, aResult);
|
||||
cache.set(null, aName, aResult);
|
||||
aCallback.onResult(aResult);
|
||||
}});
|
||||
}
|
||||
@ -791,7 +703,7 @@ ContentPrefService.prototype = {
|
||||
if (this._stmtSelectGlobalPref.executeStep()) {
|
||||
value = this._stmtSelectGlobalPref.row["value"];
|
||||
}
|
||||
this._cache.cachePref(aName, value);
|
||||
this._cache.set(null, aName, value);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -13,14 +13,11 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = test_toolkit_contentprefs
|
||||
|
||||
ifdef MOZ_PHOENIX
|
||||
XPCSHELL_TESTS = unit
|
||||
XPCSHELL_TESTS = unit unit_cps2
|
||||
|
||||
# FIXME/bug 575918: out-of-process xpcshell is broken on OS X
|
||||
ifneq ($(OS_ARCH),Darwin)
|
||||
XPCSHELL_TESTS += unit_ipc
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -0,0 +1,69 @@
|
||||
/* 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 EXPORTED_SYMBOLS = [
|
||||
"AsyncRunner",
|
||||
];
|
||||
|
||||
const { interfaces: Ci, classes: Cc } = Components;
|
||||
|
||||
function AsyncRunner(callbacks) {
|
||||
this._callbacks = callbacks;
|
||||
this._iteratorQueue = [];
|
||||
|
||||
// This catches errors reported to the console, e.g., via Cu.reportError.
|
||||
Cc["@mozilla.org/consoleservice;1"].
|
||||
getService(Ci.nsIConsoleService).
|
||||
registerListener(this);
|
||||
}
|
||||
|
||||
AsyncRunner.prototype = {
|
||||
|
||||
appendIterator: function AR_appendIterator(iter) {
|
||||
this._iteratorQueue.push(iter);
|
||||
},
|
||||
|
||||
next: function AR_next(/* ... */) {
|
||||
if (!this._iteratorQueue.length) {
|
||||
this.destroy();
|
||||
this._callbacks.done();
|
||||
return;
|
||||
}
|
||||
|
||||
// send() discards all arguments after the first, so there's no choice here
|
||||
// but to send only one argument to the yielder.
|
||||
let args = [arguments.length <= 1 ? arguments[0] : Array.slice(arguments)];
|
||||
try {
|
||||
var val = this._iteratorQueue[0].send.apply(this._iteratorQueue[0], args);
|
||||
}
|
||||
catch (err if err instanceof StopIteration) {
|
||||
this._iteratorQueue.shift();
|
||||
this.next();
|
||||
return;
|
||||
}
|
||||
catch (err) {
|
||||
this._callbacks.error(err);
|
||||
}
|
||||
|
||||
// val is truthy => call next
|
||||
// val is an iterator => prepend it to the queue and start on it
|
||||
if (val) {
|
||||
if (typeof(val) != "boolean")
|
||||
this._iteratorQueue.unshift(val);
|
||||
this.next();
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function AR_destroy() {
|
||||
Cc["@mozilla.org/consoleservice;1"].
|
||||
getService(Ci.nsIConsoleService).
|
||||
unregisterListener(this);
|
||||
this.destroy = function AR_alreadyDestroyed() {};
|
||||
},
|
||||
|
||||
observe: function AR_consoleServiceListener(msg) {
|
||||
if (msg instanceof Ci.nsIScriptError)
|
||||
this._callbacks.consoleError(msg);
|
||||
},
|
||||
};
|
311
toolkit/components/contentprefs/tests/unit_cps2/head.js
Normal file
311
toolkit/components/contentprefs/tests/unit_cps2/head.js
Normal file
@ -0,0 +1,311 @@
|
||||
/* 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/. */
|
||||
|
||||
const { interfaces: Ci, classes: Cc, results: Cr, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var cps;
|
||||
var asyncRunner;
|
||||
var next;
|
||||
|
||||
(function init() {
|
||||
// There has to be a profile directory before the CPS service is gotten.
|
||||
do_get_profile();
|
||||
})();
|
||||
|
||||
function runAsyncTests(tests) {
|
||||
do_test_pending();
|
||||
|
||||
cps = Cc["@mozilla.org/content-pref/service;1"].
|
||||
getService(Ci.nsIContentPrefService2);
|
||||
|
||||
// Without this the private-browsing service tries to open a dialog when you
|
||||
// change its enabled state.
|
||||
Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session",
|
||||
true);
|
||||
|
||||
let s = {};
|
||||
Cu.import("resource://test/AsyncRunner.jsm", s);
|
||||
asyncRunner = new s.AsyncRunner({
|
||||
done: do_test_finished,
|
||||
error: function (err) {
|
||||
// xpcshell test functions like do_check_eq throw NS_ERROR_ABORT on
|
||||
// failure. Ignore those and catch only uncaught exceptions.
|
||||
if (err !== Cr.NS_ERROR_ABORT) {
|
||||
if (err.stack) {
|
||||
err = err + "\n\nTraceback (most recent call first):\n" + err.stack +
|
||||
"\nUseless do_throw stack:";
|
||||
}
|
||||
do_throw(err);
|
||||
}
|
||||
},
|
||||
consoleError: function (scriptErr) {
|
||||
// As much as possible make sure the error is related to the test. On the
|
||||
// other hand if this fails to catch a test-related error, we'll hang.
|
||||
let filename = scriptErr.sourceName || scriptErr.toString() || "";
|
||||
if (/contentpref/i.test(filename))
|
||||
do_throw(scriptErr);
|
||||
}
|
||||
});
|
||||
|
||||
next = asyncRunner.next.bind(asyncRunner);
|
||||
|
||||
do_register_cleanup(function () {
|
||||
asyncRunner.destroy();
|
||||
asyncRunner = null;
|
||||
});
|
||||
|
||||
tests.forEach(function (test) {
|
||||
function gen() {
|
||||
do_print("Running " + test.name);
|
||||
yield test();
|
||||
yield reset();
|
||||
}
|
||||
asyncRunner.appendIterator(gen());
|
||||
});
|
||||
|
||||
// reset() ends up calling asyncRunner.next(), starting the tests.
|
||||
reset();
|
||||
}
|
||||
|
||||
function makeCallback(callbacks) {
|
||||
callbacks = callbacks || {};
|
||||
["handleResult", "handleError"].forEach(function (meth) {
|
||||
if (!callbacks[meth])
|
||||
callbacks[meth] = function () {
|
||||
do_throw(meth + " shouldn't be called.");
|
||||
};
|
||||
});
|
||||
if (!callbacks.handleCompletion)
|
||||
callbacks.handleCompletion = function (reason) {
|
||||
do_check_eq(reason, Ci.nsIContentPrefCallback2.COMPLETE_OK);
|
||||
next();
|
||||
};
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
function do_check_throws(fn) {
|
||||
let threw = false;
|
||||
try {
|
||||
fn();
|
||||
}
|
||||
catch (err) {
|
||||
threw = true;
|
||||
}
|
||||
do_check_true(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() {
|
||||
sendMessage("reset", next);
|
||||
}
|
||||
|
||||
function set(group, name, val, context) {
|
||||
cps.set(group, name, val, context, makeCallback());
|
||||
}
|
||||
|
||||
function setGlobal(name, val, context) {
|
||||
cps.setGlobal(name, val, context, makeCallback());
|
||||
}
|
||||
|
||||
function prefOK(actual, expected, strict) {
|
||||
do_check_true(actual instanceof Ci.nsIContentPref);
|
||||
do_check_eq(actual.domain, expected.domain);
|
||||
do_check_eq(actual.name, expected.name);
|
||||
if (strict)
|
||||
do_check_true(actual.value === expected.value);
|
||||
else
|
||||
do_check_eq(actual.value, expected.value);
|
||||
}
|
||||
|
||||
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 }];
|
||||
yield getOKEx("getByDomainAndName", args, expectedPrefs, strict);
|
||||
}
|
||||
|
||||
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 };
|
||||
});
|
||||
yield getOKEx("getBySubdomainAndName", args, expectedPrefs);
|
||||
}
|
||||
|
||||
function getGlobalOK(args, expectedVal) {
|
||||
if (args.length == 1)
|
||||
args.push(undefined);
|
||||
let expectedPrefs = expectedVal === undefined ? [] :
|
||||
[{ domain: null, name: args[0], value: expectedVal }];
|
||||
yield getOKEx("getGlobal", args, expectedPrefs);
|
||||
}
|
||||
|
||||
function getOKEx(methodName, args, expectedPrefs, strict, context) {
|
||||
let actualPrefs = [];
|
||||
args.push(makeCallback({
|
||||
handleResult: function (pref) actualPrefs.push(pref)
|
||||
}));
|
||||
yield 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 len = {};
|
||||
args.push(len);
|
||||
let actualPrefs = cps.getCachedBySubdomainAndName.apply(cps, args);
|
||||
do_check_eq(actualPrefs.length, len.value);
|
||||
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
|
||||
do_check_true(actualPref === null);
|
||||
}
|
||||
|
||||
function arraysOfArraysOK(actual, expected, cmp) {
|
||||
cmp = cmp || function (a, b) do_check_eq(a, b);
|
||||
do_check_eq(actual.length, expected.length);
|
||||
actual.forEach(function (actualChildArr, i) {
|
||||
let expectedChildArr = expected[i];
|
||||
do_check_eq(actualChildArr.length, expectedChildArr.length);
|
||||
actualChildArr.forEach(function (actualElt, j) {
|
||||
let expectedElt = expectedChildArr[j];
|
||||
cmp(actualElt, expectedElt);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function dbOK(expectedRows) {
|
||||
let db = sendMessage("db");
|
||||
let stmt = db.createAsyncStatement(
|
||||
"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 actualRows = [];
|
||||
let cols = ["grp", "name", "value"];
|
||||
|
||||
db.executeAsync([stmt], 1, {
|
||||
handleCompletion: function (reason) {
|
||||
arraysOfArraysOK(actualRows, expectedRows);
|
||||
next();
|
||||
},
|
||||
handleResult: function (results) {
|
||||
let row = null;
|
||||
while (row = results.getNextRow()) {
|
||||
actualRows.push(cols.map(function (c) row.getResultByName(c)));
|
||||
}
|
||||
},
|
||||
handleError: function (err) {
|
||||
do_throw(err);
|
||||
}
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function on(event, names) {
|
||||
let args = {
|
||||
reset: function () {
|
||||
for (let prop in this) {
|
||||
if (Array.isArray(this[prop]))
|
||||
this[prop].splice(0, this[prop].length);
|
||||
}
|
||||
},
|
||||
destroy: function () {
|
||||
names.forEach(function (n) cps.removeObserverForName(n, observers[n]));
|
||||
},
|
||||
};
|
||||
|
||||
let observers = {};
|
||||
|
||||
names.forEach(function (name) {
|
||||
let obs = {};
|
||||
["onContentPrefSet", "onContentPrefRemoved"].forEach(function (meth) {
|
||||
obs[meth] = function () do_throw(meth + " should not be called");
|
||||
});
|
||||
obs["onContentPref" + event] = function () {
|
||||
args[name].push(Array.slice(arguments));
|
||||
};
|
||||
observers[name] = obs;
|
||||
args[name] = [];
|
||||
args[name].observer = obs;
|
||||
cps.addObserverForName(name, obs);
|
||||
});
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
function observerArgsOK(actualArgs, expectedArgs) {
|
||||
do_check_neq(actualArgs, undefined);
|
||||
arraysOfArraysOK(actualArgs, expectedArgs);
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function nonexistent() {
|
||||
getCachedOK(["a.com", "foo"], false, undefined);
|
||||
getCachedGlobalOK(["foo"], false, undefined);
|
||||
yield true;
|
||||
},
|
||||
|
||||
function isomorphicDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
getCachedOK(["a.com", "foo"], true, 1);
|
||||
getCachedOK(["http://a.com/huh", "foo"], true, 1, "a.com");
|
||||
},
|
||||
|
||||
function names() {
|
||||
yield set("a.com", "foo", 1);
|
||||
getCachedOK(["a.com", "foo"], true, 1);
|
||||
|
||||
yield set("a.com", "bar", 2);
|
||||
getCachedOK(["a.com", "foo"], true, 1);
|
||||
getCachedOK(["a.com", "bar"], true, 2);
|
||||
|
||||
yield setGlobal("foo", 3);
|
||||
getCachedOK(["a.com", "foo"], true, 1);
|
||||
getCachedOK(["a.com", "bar"], true, 2);
|
||||
getCachedGlobalOK(["foo"], true, 3);
|
||||
|
||||
yield setGlobal("bar", 4);
|
||||
getCachedOK(["a.com", "foo"], true, 1);
|
||||
getCachedOK(["a.com", "bar"], true, 2);
|
||||
getCachedGlobalOK(["foo"], true, 3);
|
||||
getCachedGlobalOK(["bar"], true, 4);
|
||||
},
|
||||
|
||||
function subdomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("b.a.com", "foo", 2);
|
||||
getCachedOK(["a.com", "foo"], true, 1);
|
||||
getCachedOK(["b.a.com", "foo"], true, 2);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 6, context);
|
||||
yield setGlobal("foo", 7, context);
|
||||
getCachedOK(["a.com", "foo", context], true, 6);
|
||||
getCachedOK(["a.com", "bar", context], true, 2);
|
||||
getCachedGlobalOK(["foo", context], true, 7);
|
||||
getCachedGlobalOK(["bar", context], true, 4);
|
||||
getCachedOK(["b.com", "foo", context], true, 5);
|
||||
|
||||
getCachedOK(["a.com", "foo"], true, 1);
|
||||
getCachedOK(["a.com", "bar"], true, 2);
|
||||
getCachedGlobalOK(["foo"], true, 3);
|
||||
getCachedGlobalOK(["bar"], true, 4);
|
||||
getCachedOK(["b.com", "foo"], true, 5);
|
||||
},
|
||||
|
||||
function erroneous() {
|
||||
do_check_throws(function ()
|
||||
cps.getCachedByDomainAndName(null, "foo", null));
|
||||
do_check_throws(function ()
|
||||
cps.getCachedByDomainAndName("", "foo", null));
|
||||
do_check_throws(function ()
|
||||
cps.getCachedByDomainAndName("a.com", "", null));
|
||||
do_check_throws(function ()
|
||||
cps.getCachedByDomainAndName("a.com", null, null));
|
||||
do_check_throws(function () cps.getCachedGlobal("", null));
|
||||
do_check_throws(function () cps.getCachedGlobal(null, null));
|
||||
yield true;
|
||||
},
|
||||
|
||||
function casts() {
|
||||
// SQLite casts booleans to integers. This makes sure the values stored in
|
||||
// the cache are the same as the casted values in the database.
|
||||
|
||||
yield set("a.com", "foo", false);
|
||||
yield getOK(["a.com", "foo"], 0, "a.com", true);
|
||||
getCachedOK(["a.com", "foo"], true, 0, "a.com", true);
|
||||
|
||||
yield set("a.com", "bar", true);
|
||||
yield getOK(["a.com", "bar"], 1, "a.com", true);
|
||||
getCachedOK(["a.com", "bar"], true, 1, "a.com", true);
|
||||
},
|
||||
];
|
@ -0,0 +1,190 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function nonexistent() {
|
||||
getCachedSubdomainsOK(["a.com", "foo"], []);
|
||||
yield true;
|
||||
},
|
||||
|
||||
function isomorphicDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
getCachedSubdomainsOK(["http://a.com/huh", "foo"], [["a.com", 1]]);
|
||||
},
|
||||
|
||||
function names() {
|
||||
yield set("a.com", "foo", 1);
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
|
||||
yield set("a.com", "bar", 2);
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"], [["a.com", 2]]);
|
||||
|
||||
yield setGlobal("foo", 3);
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"], [["a.com", 2]]);
|
||||
getCachedGlobalOK(["foo"], true, 3);
|
||||
|
||||
yield setGlobal("bar", 4);
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"], [["a.com", 2]]);
|
||||
getCachedGlobalOK(["foo"], true, 3);
|
||||
getCachedGlobalOK(["bar"], true, 4);
|
||||
},
|
||||
|
||||
function subdomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("b.a.com", "foo", 2);
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", 1], ["b.a.com", 2]]);
|
||||
getCachedSubdomainsOK(["b.a.com", "foo"], [["b.a.com", 2]]);
|
||||
},
|
||||
|
||||
function populateViaGet() {
|
||||
yield cps.getByDomainAndName("a.com", "foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
|
||||
yield cps.getGlobal("foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
getCachedGlobalOK(["foo"], true, undefined);
|
||||
},
|
||||
|
||||
function populateViaGetSubdomains() {
|
||||
yield cps.getBySubdomainAndName("a.com", "foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
},
|
||||
|
||||
function populateViaRemove() {
|
||||
yield cps.removeByDomainAndName("a.com", "foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
|
||||
yield cps.removeBySubdomainAndName("b.com", "foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["b.com", "foo"], [["b.com", undefined]]);
|
||||
|
||||
yield cps.removeGlobal("foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["b.com", "foo"], [["b.com", undefined]]);
|
||||
getCachedGlobalOK(["foo"], true, undefined);
|
||||
|
||||
yield set("a.com", "foo", 1);
|
||||
yield cps.removeByDomainAndName("a.com", "foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["b.com", "foo"], [["b.com", undefined]]);
|
||||
getCachedGlobalOK(["foo"], true, undefined);
|
||||
|
||||
yield set("a.com", "foo", 2);
|
||||
yield set("b.a.com", "foo", 3);
|
||||
yield cps.removeBySubdomainAndName("a.com", "foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"],
|
||||
[["a.com", undefined], ["b.a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["b.com", "foo"], [["b.com", undefined]]);
|
||||
getCachedGlobalOK(["foo"], true, undefined);
|
||||
getCachedSubdomainsOK(["b.a.com", "foo"], [["b.a.com", undefined]]);
|
||||
|
||||
yield setGlobal("foo", 4);
|
||||
yield cps.removeGlobal("foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"],
|
||||
[["a.com", undefined], ["b.a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["b.com", "foo"], [["b.com", undefined]]);
|
||||
getCachedGlobalOK(["foo"], true, undefined);
|
||||
getCachedSubdomainsOK(["b.a.com", "foo"], [["b.a.com", undefined]]);
|
||||
},
|
||||
|
||||
function populateViaRemoveByDomain() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield set("b.a.com", "foo", 3);
|
||||
yield set("b.a.com", "bar", 4);
|
||||
yield cps.removeByDomain("a.com", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"],
|
||||
[["a.com", undefined], ["b.a.com", 3]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"],
|
||||
[["a.com", undefined], ["b.a.com", 4]]);
|
||||
|
||||
yield set("a.com", "foo", 5);
|
||||
yield set("a.com", "bar", 6);
|
||||
yield cps.removeBySubdomain("a.com", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"],
|
||||
[["a.com", undefined], ["b.a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"],
|
||||
[["a.com", undefined], ["b.a.com", undefined]]);
|
||||
|
||||
yield setGlobal("foo", 7);
|
||||
yield setGlobal("bar", 8);
|
||||
yield cps.removeAllGlobals(null, makeCallback());
|
||||
getCachedGlobalOK(["foo"], true, undefined);
|
||||
getCachedGlobalOK(["bar"], true, undefined);
|
||||
},
|
||||
|
||||
function populateViaRemoveAllDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield set("b.com", "foo", 3);
|
||||
yield set("b.com", "bar", 4);
|
||||
yield cps.removeAllDomains(null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"], [["a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["b.com", "foo"], [["b.com", undefined]]);
|
||||
getCachedSubdomainsOK(["b.com", "bar"], [["b.com", undefined]]);
|
||||
},
|
||||
|
||||
function populateViaRemoveByName() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield cps.removeByName("foo", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"], [["a.com", 2]]);
|
||||
getCachedGlobalOK(["foo"], true, undefined);
|
||||
getCachedGlobalOK(["bar"], true, 4);
|
||||
|
||||
yield cps.removeByName("bar", null, makeCallback());
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", undefined]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"], [["a.com", undefined]]);
|
||||
getCachedGlobalOK(["foo"], true, undefined);
|
||||
getCachedGlobalOK(["bar"], true, undefined);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 6, context);
|
||||
yield setGlobal("foo", 7, context);
|
||||
getCachedSubdomainsOK(["a.com", "foo", context], [["a.com", 6]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar", context], [["a.com", 2]]);
|
||||
getCachedGlobalOK(["foo", context], true, 7);
|
||||
getCachedGlobalOK(["bar", context], true, 4);
|
||||
getCachedSubdomainsOK(["b.com", "foo", context], [["b.com", 5]]);
|
||||
|
||||
getCachedSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
getCachedSubdomainsOK(["a.com", "bar"], [["a.com", 2]]);
|
||||
getCachedGlobalOK(["foo"], true, 3);
|
||||
getCachedGlobalOK(["bar"], true, 4);
|
||||
getCachedSubdomainsOK(["b.com", "foo"], [["b.com", 5]]);
|
||||
},
|
||||
|
||||
function erroneous() {
|
||||
do_check_throws(function ()
|
||||
cps.getCachedBySubdomainAndName(null, "foo", null));
|
||||
do_check_throws(function ()
|
||||
cps.getCachedBySubdomainAndName("", "foo", null));
|
||||
do_check_throws(function ()
|
||||
cps.getCachedBySubdomainAndName("a.com", "", null));
|
||||
do_check_throws(function ()
|
||||
cps.getCachedBySubdomainAndName("a.com", null, null));
|
||||
yield true;
|
||||
},
|
||||
];
|
@ -0,0 +1,73 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function get_nonexistent() {
|
||||
yield getSubdomainsOK(["a.com", "foo"], []);
|
||||
},
|
||||
|
||||
function isomorphicDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
yield getSubdomainsOK(["http://a.com/huh", "foo"], [["a.com", 1]]);
|
||||
},
|
||||
|
||||
function names() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
|
||||
yield set("a.com", "bar", 2);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
yield getSubdomainsOK(["a.com", "bar"], [["a.com", 2]]);
|
||||
|
||||
yield setGlobal("foo", 3);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
yield getSubdomainsOK(["a.com", "bar"], [["a.com", 2]]);
|
||||
},
|
||||
|
||||
function subdomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("b.a.com", "foo", 2);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 1], ["b.a.com", 2]]);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], [["b.a.com", 2]]);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 6, context);
|
||||
yield setGlobal("foo", 7, context);
|
||||
yield getSubdomainsOK(["a.com", "foo", context], [["a.com", 6]]);
|
||||
yield getSubdomainsOK(["a.com", "bar", context], [["a.com", 2]]);
|
||||
yield getSubdomainsOK(["b.com", "foo", context], [["b.com", 5]]);
|
||||
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 1]]);
|
||||
yield getSubdomainsOK(["a.com", "bar"], [["a.com", 2]]);
|
||||
yield getSubdomainsOK(["b.com", "foo"], [["b.com", 5]]);
|
||||
},
|
||||
|
||||
function erroneous() {
|
||||
do_check_throws(function ()
|
||||
cps.getBySubdomainAndName(null, "foo", null, {}));
|
||||
do_check_throws(function ()
|
||||
cps.getBySubdomainAndName("", "foo", null, {}));
|
||||
do_check_throws(function ()
|
||||
cps.getBySubdomainAndName("a.com", "", null, {}));
|
||||
do_check_throws(function ()
|
||||
cps.getBySubdomainAndName("a.com", null, null, {}));
|
||||
do_check_throws(function ()
|
||||
cps.getBySubdomainAndName("a.com", "foo", null, null));
|
||||
yield true;
|
||||
},
|
||||
];
|
@ -0,0 +1,125 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function observerForName_set() {
|
||||
let args = on("Set", ["foo", null, "bar"]);
|
||||
|
||||
yield set("a.com", "foo", 1);
|
||||
observerArgsOK(args.foo, [["a.com", "foo", 1]]);
|
||||
observerArgsOK(args.null, [["a.com", "foo", 1]]);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
|
||||
yield setGlobal("foo", 2);
|
||||
observerArgsOK(args.foo, [[null, "foo", 2]]);
|
||||
observerArgsOK(args.null, [[null, "foo", 2]]);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
},
|
||||
|
||||
function observerForName_remove() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield setGlobal("foo", 2);
|
||||
|
||||
let args = on("Removed", ["foo", null, "bar"]);
|
||||
yield cps.removeByDomainAndName("a.com", "bogus", null, makeCallback());
|
||||
observerArgsOK(args.foo, []);
|
||||
observerArgsOK(args.null, []);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
|
||||
yield cps.removeByDomainAndName("a.com", "foo", null, makeCallback());
|
||||
observerArgsOK(args.foo, [["a.com", "foo"]]);
|
||||
observerArgsOK(args.null, [["a.com", "foo"]]);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
|
||||
yield cps.removeGlobal("foo", null, makeCallback());
|
||||
observerArgsOK(args.foo, [[null, "foo"]]);
|
||||
observerArgsOK(args.null, [[null, "foo"]]);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
},
|
||||
|
||||
function observerForName_removeByDomain() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("b.a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
|
||||
let args = on("Removed", ["foo", null, "bar"]);
|
||||
yield cps.removeByDomain("bogus", null, makeCallback());
|
||||
observerArgsOK(args.foo, []);
|
||||
observerArgsOK(args.null, []);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
|
||||
yield cps.removeBySubdomain("a.com", null, makeCallback());
|
||||
observerArgsOK(args.foo, [["a.com", "foo"]]);
|
||||
observerArgsOK(args.null, [["a.com", "foo"], ["b.a.com", "bar"]]);
|
||||
observerArgsOK(args.bar, [["b.a.com", "bar"]]);
|
||||
args.reset();
|
||||
|
||||
yield cps.removeAllGlobals(null, makeCallback());
|
||||
observerArgsOK(args.foo, [[null, "foo"]]);
|
||||
observerArgsOK(args.null, [[null, "foo"]]);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
},
|
||||
|
||||
function observerForName_removeAllDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield setGlobal("foo", 2);
|
||||
yield set("b.com", "bar", 3);
|
||||
|
||||
let args = on("Removed", ["foo", null, "bar"]);
|
||||
yield cps.removeAllDomains(null, makeCallback());
|
||||
observerArgsOK(args.foo, [["a.com", "foo"]]);
|
||||
observerArgsOK(args.null, [["a.com", "foo"], ["b.com", "bar"]]);
|
||||
observerArgsOK(args.bar, [["b.com", "bar"]]);
|
||||
args.reset();
|
||||
},
|
||||
|
||||
function observerForName_removeByName() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
|
||||
let args = on("Removed", ["foo", null, "bar"]);
|
||||
yield cps.removeByName("bogus", null, makeCallback());
|
||||
observerArgsOK(args.foo, []);
|
||||
observerArgsOK(args.null, []);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
|
||||
yield cps.removeByName("foo", null, makeCallback());
|
||||
observerArgsOK(args.foo, [["a.com", "foo"], [null, "foo"]]);
|
||||
observerArgsOK(args.null, [["a.com", "foo"], [null, "foo"]]);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
},
|
||||
|
||||
function removeObserverForName() {
|
||||
let args = on("Set", ["foo", null, "bar"]);
|
||||
|
||||
cps.removeObserverForName("foo", args.foo.observer);
|
||||
yield set("a.com", "foo", 1);
|
||||
observerArgsOK(args.foo, []);
|
||||
observerArgsOK(args.null, [["a.com", "foo", 1]]);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
|
||||
cps.removeObserverForName(null, args.null.observer);
|
||||
yield set("a.com", "foo", 2);
|
||||
observerArgsOK(args.foo, []);
|
||||
observerArgsOK(args.null, []);
|
||||
observerArgsOK(args.bar, []);
|
||||
args.reset();
|
||||
},
|
||||
];
|
194
toolkit/components/contentprefs/tests/unit_cps2/test_remove.js
Normal file
194
toolkit/components/contentprefs/tests/unit_cps2/test_remove.js
Normal file
@ -0,0 +1,194 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function nonexistent() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield setGlobal("foo", 2);
|
||||
|
||||
yield cps.removeByDomainAndName("a.com", "bogus", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getGlobalOK(["foo"], 2);
|
||||
|
||||
yield cps.removeBySubdomainAndName("a.com", "bogus", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getGlobalOK(["foo"], 2);
|
||||
|
||||
yield cps.removeGlobal("bogus", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getGlobalOK(["foo"], 2);
|
||||
|
||||
yield cps.removeByDomainAndName("bogus", "bogus", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getGlobalOK(["foo"], 2);
|
||||
},
|
||||
|
||||
function isomorphicDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield cps.removeByDomainAndName("a.com", "foo", null, makeCallback());
|
||||
yield dbOK([]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
|
||||
yield set("a.com", "foo", 2);
|
||||
yield cps.removeByDomainAndName("http://a.com/huh", "foo", null,
|
||||
makeCallback());
|
||||
yield dbOK([]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
},
|
||||
|
||||
function names() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
|
||||
yield cps.removeByDomainAndName("a.com", "foo", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "bar", 2],
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], 2);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
|
||||
yield cps.removeGlobal("foo", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "bar", 2],
|
||||
[null, "bar", 4],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], 2);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
|
||||
yield cps.removeByDomainAndName("a.com", "bar", null, makeCallback());
|
||||
yield dbOK([
|
||||
[null, "bar", 4],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
|
||||
yield cps.removeGlobal("bar", null, makeCallback());
|
||||
yield dbOK([
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
yield getGlobalOK(["bar"], undefined);
|
||||
},
|
||||
|
||||
function subdomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("b.a.com", "foo", 2);
|
||||
yield cps.removeByDomainAndName("a.com", "foo", null, makeCallback());
|
||||
yield dbOK([
|
||||
["b.a.com", "foo", 2],
|
||||
]);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["b.a.com", 2]]);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], [["b.a.com", 2]]);
|
||||
|
||||
yield set("a.com", "foo", 3);
|
||||
yield cps.removeBySubdomainAndName("a.com", "foo", null, makeCallback());
|
||||
yield dbOK([
|
||||
]);
|
||||
yield getSubdomainsOK(["a.com", "foo"], []);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], []);
|
||||
|
||||
yield set("a.com", "foo", 4);
|
||||
yield set("b.a.com", "foo", 5);
|
||||
yield cps.removeByDomainAndName("b.a.com", "foo", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 4],
|
||||
]);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 4]]);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], []);
|
||||
|
||||
yield set("b.a.com", "foo", 6);
|
||||
yield cps.removeBySubdomainAndName("b.a.com", "foo", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 4],
|
||||
]);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 4]]);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], []);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield setGlobal("qux", 5);
|
||||
yield set("b.com", "foo", 6);
|
||||
yield set("b.com", "bar", 7);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 8, context);
|
||||
yield setGlobal("foo", 9, context);
|
||||
yield cps.removeByDomainAndName("a.com", "foo", context, makeCallback());
|
||||
yield cps.removeGlobal("foo", context, makeCallback());
|
||||
yield cps.removeGlobal("qux", context, makeCallback());
|
||||
yield cps.removeByDomainAndName("b.com", "foo", context, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "bar", 2],
|
||||
[null, "bar", 4],
|
||||
["b.com", "bar", 7],
|
||||
]);
|
||||
yield getOK(["a.com", "foo", context], undefined);
|
||||
yield getOK(["a.com", "bar", context], 2);
|
||||
yield getGlobalOK(["foo", context], undefined);
|
||||
yield getGlobalOK(["bar", context], 4);
|
||||
yield getGlobalOK(["qux", context], undefined);
|
||||
yield getOK(["b.com", "foo", context], undefined);
|
||||
yield getOK(["b.com", "bar", context], 7);
|
||||
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], 2);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
yield getGlobalOK(["qux"], undefined);
|
||||
yield getOK(["b.com", "foo"], undefined);
|
||||
yield getOK(["b.com", "bar"], 7);
|
||||
},
|
||||
|
||||
function erroneous() {
|
||||
do_check_throws(function () cps.removeByDomainAndName(null, "foo", null));
|
||||
do_check_throws(function () cps.removeByDomainAndName("", "foo", null));
|
||||
do_check_throws(function () cps.removeByDomainAndName("a.com", "foo", null,
|
||||
"bogus"));
|
||||
do_check_throws(function () cps.removeBySubdomainAndName(null, "foo",
|
||||
null));
|
||||
do_check_throws(function () cps.removeBySubdomainAndName("", "foo", null));
|
||||
do_check_throws(function () cps.removeBySubdomainAndName("a.com", "foo",
|
||||
null, "bogus"));
|
||||
do_check_throws(function () cps.removeGlobal("", null));
|
||||
do_check_throws(function () cps.removeGlobal(null, null));
|
||||
do_check_throws(function () cps.removeGlobal("foo", null, "bogus"));
|
||||
yield true;
|
||||
},
|
||||
];
|
@ -0,0 +1,73 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function nonexistent() {
|
||||
yield setGlobal("foo", 1);
|
||||
yield cps.removeAllDomains(null, makeCallback());
|
||||
yield dbOK([
|
||||
[null, "foo", 1],
|
||||
]);
|
||||
yield getGlobalOK(["foo"], 1);
|
||||
},
|
||||
|
||||
function domains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
yield set("b.com", "bar", 6);
|
||||
|
||||
yield cps.removeAllDomains(null, makeCallback());
|
||||
yield dbOK([
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
yield getOK(["b.com", "foo"], undefined);
|
||||
yield getOK(["b.com", "bar"], undefined);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 6, context);
|
||||
yield setGlobal("foo", 7, context);
|
||||
yield cps.removeAllDomains(context, makeCallback());
|
||||
yield dbOK([
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
]);
|
||||
yield getOK(["a.com", "foo", context], undefined);
|
||||
yield getOK(["a.com", "bar", context], undefined);
|
||||
yield getGlobalOK(["foo", context], 7);
|
||||
yield getGlobalOK(["bar", context], 4);
|
||||
yield getOK(["b.com", "foo", context], undefined);
|
||||
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
yield getOK(["b.com", "foo"], undefined);
|
||||
},
|
||||
|
||||
function erroneous() {
|
||||
do_check_throws(function () cps.removeAllDomains(null, "bogus"));
|
||||
yield true;
|
||||
},
|
||||
];
|
@ -0,0 +1,162 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function nonexistent() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield setGlobal("foo", 2);
|
||||
|
||||
yield cps.removeByDomain("bogus", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getGlobalOK(["foo"], 2);
|
||||
|
||||
yield cps.removeBySubdomain("bogus", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getGlobalOK(["foo"], 2);
|
||||
},
|
||||
|
||||
function isomorphicDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield cps.removeByDomain("a.com", null, makeCallback());
|
||||
yield dbOK([]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
|
||||
yield set("a.com", "foo", 2);
|
||||
yield cps.removeByDomain("http://a.com/huh", null, makeCallback());
|
||||
yield dbOK([]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
},
|
||||
|
||||
function domains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
yield set("b.com", "bar", 6);
|
||||
|
||||
yield cps.removeByDomain("a.com", null, makeCallback());
|
||||
yield dbOK([
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
["b.com", "foo", 5],
|
||||
["b.com", "bar", 6],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
yield getOK(["b.com", "foo"], 5);
|
||||
yield getOK(["b.com", "bar"], 6);
|
||||
|
||||
yield cps.removeAllGlobals(null, makeCallback());
|
||||
yield dbOK([
|
||||
["b.com", "foo", 5],
|
||||
["b.com", "bar", 6],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
yield getGlobalOK(["bar"], undefined);
|
||||
yield getOK(["b.com", "foo"], 5);
|
||||
yield getOK(["b.com", "bar"], 6);
|
||||
|
||||
yield cps.removeByDomain("b.com", null, makeCallback());
|
||||
yield dbOK([
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
yield getGlobalOK(["bar"], undefined);
|
||||
yield getOK(["b.com", "foo"], undefined);
|
||||
yield getOK(["b.com", "bar"], undefined);
|
||||
},
|
||||
|
||||
function subdomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("b.a.com", "foo", 2);
|
||||
yield cps.removeByDomain("a.com", null, makeCallback());
|
||||
yield dbOK([
|
||||
["b.a.com", "foo", 2],
|
||||
]);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["b.a.com", 2]]);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], [["b.a.com", 2]]);
|
||||
|
||||
yield set("a.com", "foo", 3);
|
||||
yield cps.removeBySubdomain("a.com", null, makeCallback());
|
||||
yield dbOK([
|
||||
]);
|
||||
yield getSubdomainsOK(["a.com", "foo"], []);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], []);
|
||||
|
||||
yield set("a.com", "foo", 4);
|
||||
yield set("b.a.com", "foo", 5);
|
||||
yield cps.removeByDomain("b.a.com", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 4],
|
||||
]);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 4]]);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], []);
|
||||
|
||||
yield set("b.a.com", "foo", 6);
|
||||
yield cps.removeBySubdomain("b.a.com", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 4],
|
||||
]);
|
||||
yield getSubdomainsOK(["a.com", "foo"], [["a.com", 4]]);
|
||||
yield getSubdomainsOK(["b.a.com", "foo"], []);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 6, context);
|
||||
yield setGlobal("foo", 7, context);
|
||||
yield cps.removeByDomain("a.com", context, makeCallback());
|
||||
yield cps.removeAllGlobals(context, makeCallback());
|
||||
yield dbOK([
|
||||
["b.com", "foo", 5],
|
||||
]);
|
||||
yield getOK(["a.com", "foo", context], undefined);
|
||||
yield getOK(["a.com", "bar", context], undefined);
|
||||
yield getGlobalOK(["foo", context], undefined);
|
||||
yield getGlobalOK(["bar", context], undefined);
|
||||
yield getOK(["b.com", "foo", context], 5);
|
||||
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
yield getGlobalOK(["bar"], undefined);
|
||||
yield getOK(["b.com", "foo"], 5);
|
||||
},
|
||||
|
||||
function erroneous() {
|
||||
do_check_throws(function () cps.removeByDomain(null, null));
|
||||
do_check_throws(function () cps.removeByDomain("", null));
|
||||
do_check_throws(function () cps.removeByDomain("a.com", null, "bogus"));
|
||||
do_check_throws(function () cps.removeBySubdomain(null, null));
|
||||
do_check_throws(function () cps.removeBySubdomain("", null));
|
||||
do_check_throws(function () cps.removeBySubdomain("a.com", null, "bogus"));
|
||||
do_check_throws(function () cps.removeAllGlobals(null, "bogus"));
|
||||
yield true;
|
||||
},
|
||||
];
|
@ -0,0 +1,85 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function nonexistent() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield setGlobal("foo", 2);
|
||||
|
||||
yield cps.removeByName("bogus", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getGlobalOK(["foo"], 2);
|
||||
},
|
||||
|
||||
function names() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
yield set("b.com", "bar", 6);
|
||||
|
||||
yield cps.removeByName("foo", null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "bar", 2],
|
||||
[null, "bar", 4],
|
||||
["b.com", "bar", 6],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], 2);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
yield getOK(["b.com", "foo"], undefined);
|
||||
yield getOK(["b.com", "bar"], 6);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
yield set("b.com", "bar", 6);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 7, context);
|
||||
yield setGlobal("foo", 8, context);
|
||||
yield set("b.com", "bar", 9, context);
|
||||
yield cps.removeByName("bar", context, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 3],
|
||||
["b.com", "foo", 5],
|
||||
]);
|
||||
yield getOK(["a.com", "foo", context], 7);
|
||||
yield getOK(["a.com", "bar", context], undefined);
|
||||
yield getGlobalOK(["foo", context], 8);
|
||||
yield getGlobalOK(["bar", context], undefined);
|
||||
yield getOK(["b.com", "foo", context], 5);
|
||||
yield getOK(["b.com", "bar", context], undefined);
|
||||
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], undefined);
|
||||
yield getOK(["b.com", "foo"], 5);
|
||||
yield getOK(["b.com", "bar"], undefined);
|
||||
},
|
||||
|
||||
function erroneous() {
|
||||
do_check_throws(function () cps.removeByName("", null));
|
||||
do_check_throws(function () cps.removeByName(null, null));
|
||||
do_check_throws(function () cps.removeByName("foo", null, "bogus"));
|
||||
yield true;
|
||||
},
|
||||
];
|
@ -0,0 +1,12 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
let serv = Cc["@mozilla.org/content-pref/service;1"].
|
||||
getService(Ci.nsIContentPrefService2);
|
||||
do_check_eq(serv.QueryInterface(Ci.nsIContentPrefService2), serv);
|
||||
do_check_eq(serv.QueryInterface(Ci.nsISupports), serv);
|
||||
let val = serv.QueryInterface(Ci.nsIContentPrefService);
|
||||
do_check_true(val instanceof Ci.nsIContentPrefService);
|
||||
}
|
138
toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js
Normal file
138
toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js
Normal file
@ -0,0 +1,138 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function get_nonexistent() {
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getGlobalOK(["foo"], undefined);
|
||||
},
|
||||
|
||||
function isomorphicDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getOK(["http://a.com/huh", "foo"], 1, "a.com");
|
||||
|
||||
yield set("http://a.com/huh", "foo", 2);
|
||||
yield dbOK([
|
||||
["a.com", "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 2);
|
||||
yield getOK(["http://a.com/yeah", "foo"], 2, "a.com");
|
||||
},
|
||||
|
||||
function names() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
|
||||
yield set("a.com", "bar", 2);
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
["a.com", "bar", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getOK(["a.com", "bar"], 2);
|
||||
|
||||
yield setGlobal("foo", 3);
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
["a.com", "bar", 2],
|
||||
[null, "foo", 3],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getOK(["a.com", "bar"], 2);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
|
||||
yield setGlobal("bar", 4);
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
["a.com", "bar", 2],
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getOK(["a.com", "bar"], 2);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
},
|
||||
|
||||
function subdomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("b.a.com", "foo", 2);
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
["b.a.com", "foo", 2],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getOK(["b.a.com", "foo"], 2);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 6, context);
|
||||
yield setGlobal("foo", 7, context);
|
||||
yield dbOK([
|
||||
["a.com", "foo", 1],
|
||||
["a.com", "bar", 2],
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
["b.com", "foo", 5],
|
||||
]);
|
||||
yield getOK(["a.com", "foo", context], 6, "a.com");
|
||||
yield getOK(["a.com", "bar", context], 2);
|
||||
yield getGlobalOK(["foo", context], 7);
|
||||
yield getGlobalOK(["bar", context], 4);
|
||||
yield getOK(["b.com", "foo", context], 5);
|
||||
|
||||
yield getOK(["a.com", "foo"], 1);
|
||||
yield getOK(["a.com", "bar"], 2);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
yield getOK(["b.com", "foo"], 5);
|
||||
},
|
||||
|
||||
function set_erroneous() {
|
||||
do_check_throws(function () cps.set(null, "foo", 1, null));
|
||||
do_check_throws(function () cps.set("", "foo", 1, null));
|
||||
do_check_throws(function () cps.set("a.com", "", 1, null));
|
||||
do_check_throws(function () cps.set("a.com", null, 1, null));
|
||||
do_check_throws(function () cps.set("a.com", "foo", undefined, null));
|
||||
do_check_throws(function () cps.set("a.com", "foo", 1, null, "bogus"));
|
||||
do_check_throws(function () cps.setGlobal("", 1, null));
|
||||
do_check_throws(function () cps.setGlobal(null, 1, null));
|
||||
do_check_throws(function () cps.setGlobal("foo", undefined, null));
|
||||
do_check_throws(function () cps.setGlobal("foo", 1, null, "bogus"));
|
||||
yield true;
|
||||
},
|
||||
|
||||
function get_erroneous() {
|
||||
do_check_throws(function () cps.getByDomainAndName(null, "foo", null, {}));
|
||||
do_check_throws(function () cps.getByDomainAndName("", "foo", null, {}));
|
||||
do_check_throws(function () cps.getByDomainAndName("a.com", "", null, {}));
|
||||
do_check_throws(function ()
|
||||
cps.getByDomainAndName("a.com", null, null, {}));
|
||||
do_check_throws(function ()
|
||||
cps.getByDomainAndName("a.com", "foo", null, null));
|
||||
do_check_throws(function () cps.getGlobal("", null, {}));
|
||||
do_check_throws(function () cps.getGlobal(null, null, {}));
|
||||
do_check_throws(function () cps.getGlobal("foo", null, null));
|
||||
yield true;
|
||||
},
|
||||
];
|
14
toolkit/components/contentprefs/tests/unit_cps2/xpcshell.ini
Normal file
14
toolkit/components/contentprefs/tests/unit_cps2/xpcshell.ini
Normal file
@ -0,0 +1,14 @@
|
||||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
|
||||
[test_service.js]
|
||||
[test_setGet.js]
|
||||
[test_getSubdomains.js]
|
||||
[test_remove.js]
|
||||
[test_removeByDomain.js]
|
||||
[test_removeAllDomains.js]
|
||||
[test_removeByName.js]
|
||||
[test_getCached.js]
|
||||
[test_getCachedSubdomains.js]
|
||||
[test_observers.js]
|
Loading…
Reference in New Issue
Block a user