Remove SpecialPowers addon
This commit is contained in:
parent
32cc021f31
commit
75d8f70d06
@ -14,7 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/* globals PDFJS, combineUrl, StatTimer, SpecialPowers, Promise */
|
/* globals PDFJS, combineUrl, StatTimer, Promise */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -367,11 +367,7 @@ function quitApp() {
|
|||||||
document.body.innerHTML = 'Tests are finished. <h1>CLOSE ME!</h1>' +
|
document.body.innerHTML = 'Tests are finished. <h1>CLOSE ME!</h1>' +
|
||||||
document.body.innerHTML;
|
document.body.innerHTML;
|
||||||
sendQuitRequest(function () {
|
sendQuitRequest(function () {
|
||||||
if (window.SpecialPowers) {
|
window.close();
|
||||||
SpecialPowers.quit();
|
|
||||||
} else {
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
category profile-after-change @mozilla.org/special-powers-observer;1 @mozilla.org/special-powers-observer;1
|
|
||||||
component {59a52458-13e0-4d93-9d85-a637344f29a1} components/SpecialPowersObserver.js
|
|
||||||
content specialpowers chrome/specialpowers/content/
|
|
||||||
contract @mozilla.org/special-powers-observer;1 {59a52458-13e0-4d93-9d85-a637344f29a1}
|
|
||||||
resource specialpowers chrome/specialpowers/modules/
|
|
@ -1,121 +0,0 @@
|
|||||||
/**
|
|
||||||
* MozillaLogger, a base class logger that just logs to stdout.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function MozillaLogger(aPath) {
|
|
||||||
}
|
|
||||||
|
|
||||||
MozillaLogger.prototype = {
|
|
||||||
|
|
||||||
init : function(path) {},
|
|
||||||
|
|
||||||
getLogCallback : function() {
|
|
||||||
return function (msg) {
|
|
||||||
var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n";
|
|
||||||
dump(data);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
log : function(msg) {
|
|
||||||
dump(msg);
|
|
||||||
},
|
|
||||||
|
|
||||||
close : function() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SpecialPowersLogger, inherits from MozillaLogger and utilizes SpecialPowers.
|
|
||||||
* intented to be used in content scripts to write to a file
|
|
||||||
*/
|
|
||||||
function SpecialPowersLogger(aPath) {
|
|
||||||
// Call the base constructor
|
|
||||||
MozillaLogger.call(this);
|
|
||||||
this.prototype = new MozillaLogger(aPath);
|
|
||||||
this.init(aPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecialPowersLogger.prototype = {
|
|
||||||
init : function (path) {
|
|
||||||
SpecialPowers.setLogFile(path);
|
|
||||||
},
|
|
||||||
|
|
||||||
getLogCallback : function () {
|
|
||||||
return function (msg) {
|
|
||||||
var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n";
|
|
||||||
SpecialPowers.log(data);
|
|
||||||
|
|
||||||
if (data.indexOf("SimpleTest FINISH") >= 0) {
|
|
||||||
SpecialPowers.closeLogFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
log : function (msg) {
|
|
||||||
SpecialPowers.log(msg);
|
|
||||||
},
|
|
||||||
|
|
||||||
close : function () {
|
|
||||||
SpecialPowers.closeLogFile();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MozillaFileLogger, a log listener that can write to a local file.
|
|
||||||
* intended to be run from chrome space
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Init the file logger with the absolute path to the file.
|
|
||||||
It will create and append if the file already exists **/
|
|
||||||
function MozillaFileLogger(aPath) {
|
|
||||||
// Call the base constructor
|
|
||||||
MozillaLogger.call(this);
|
|
||||||
this.prototype = new MozillaLogger(aPath);
|
|
||||||
this.init(aPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
MozillaFileLogger.prototype = {
|
|
||||||
|
|
||||||
init : function (path) {
|
|
||||||
var PR_WRITE_ONLY = 0x02; // Open for writing only.
|
|
||||||
var PR_CREATE_FILE = 0x08;
|
|
||||||
var PR_APPEND = 0x10;
|
|
||||||
this._file = Components.classes["@mozilla.org/file/local;1"].
|
|
||||||
createInstance(Components.interfaces.nsILocalFile);
|
|
||||||
this._file.initWithPath(path);
|
|
||||||
this._foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
|
|
||||||
createInstance(Components.interfaces.nsIFileOutputStream);
|
|
||||||
this._foStream.init(this._file, PR_WRITE_ONLY | PR_CREATE_FILE | PR_APPEND,
|
|
||||||
0664, 0);
|
|
||||||
},
|
|
||||||
|
|
||||||
getLogCallback : function() {
|
|
||||||
return function (msg) {
|
|
||||||
var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n";
|
|
||||||
if (MozillaFileLogger._foStream)
|
|
||||||
this._foStream.write(data, data.length);
|
|
||||||
|
|
||||||
if (data.indexOf("SimpleTest FINISH") >= 0) {
|
|
||||||
MozillaFileLogger.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
log : function(msg) {
|
|
||||||
if (this._foStream)
|
|
||||||
this._foStream.write(msg, msg.length);
|
|
||||||
},
|
|
||||||
|
|
||||||
close : function() {
|
|
||||||
if(this._foStream)
|
|
||||||
this._foStream.close();
|
|
||||||
|
|
||||||
this._foStream = null;
|
|
||||||
this._file = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.MozillaLogger = MozillaLogger;
|
|
||||||
this.SpecialPowersLogger = SpecialPowersLogger;
|
|
||||||
this.MozillaFileLogger = MozillaFileLogger;
|
|
@ -1,413 +0,0 @@
|
|||||||
/* 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/. */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
if (typeof(Ci) == 'undefined') {
|
|
||||||
var Ci = Components.interfaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(Cc) == 'undefined') {
|
|
||||||
var Cc = Components.classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Special Powers Exception - used to throw exceptions nicely
|
|
||||||
**/
|
|
||||||
function SpecialPowersException(aMsg) {
|
|
||||||
this.message = aMsg;
|
|
||||||
this.name = "SpecialPowersException";
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecialPowersException.prototype.toString = function() {
|
|
||||||
return this.name + ': "' + this.message + '"';
|
|
||||||
};
|
|
||||||
|
|
||||||
this.SpecialPowersObserverAPI = function SpecialPowersObserverAPI() {
|
|
||||||
this._crashDumpDir = null;
|
|
||||||
this._processCrashObserversRegistered = false;
|
|
||||||
this._chromeScriptListeners = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseKeyValuePairs(text) {
|
|
||||||
var lines = text.split('\n');
|
|
||||||
var data = {};
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
if (lines[i] == '')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// can't just .split() because the value might contain = characters
|
|
||||||
let eq = lines[i].indexOf('=');
|
|
||||||
if (eq != -1) {
|
|
||||||
let [key, value] = [lines[i].substring(0, eq),
|
|
||||||
lines[i].substring(eq + 1)];
|
|
||||||
if (key && value)
|
|
||||||
data[key] = value.replace(/\\n/g, "\n").replace(/\\\\/g, "\\");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseKeyValuePairsFromFile(file) {
|
|
||||||
var fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
|
||||||
createInstance(Ci.nsIFileInputStream);
|
|
||||||
fstream.init(file, -1, 0, 0);
|
|
||||||
var is = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
|
||||||
createInstance(Ci.nsIConverterInputStream);
|
|
||||||
is.init(fstream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
|
||||||
var str = {};
|
|
||||||
var contents = '';
|
|
||||||
while (is.readString(4096, str) != 0) {
|
|
||||||
contents += str.value;
|
|
||||||
}
|
|
||||||
is.close();
|
|
||||||
fstream.close();
|
|
||||||
return parseKeyValuePairs(contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecialPowersObserverAPI.prototype = {
|
|
||||||
|
|
||||||
_observe: function(aSubject, aTopic, aData) {
|
|
||||||
function addDumpIDToMessage(propertyName) {
|
|
||||||
var id = aSubject.getPropertyAsAString(propertyName);
|
|
||||||
if (id) {
|
|
||||||
message.dumpIDs.push({id: id, extension: "dmp"});
|
|
||||||
message.dumpIDs.push({id: id, extension: "extra"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(aTopic) {
|
|
||||||
case "plugin-crashed":
|
|
||||||
case "ipc:content-shutdown":
|
|
||||||
var message = { type: "crash-observed", dumpIDs: [] };
|
|
||||||
aSubject = aSubject.QueryInterface(Ci.nsIPropertyBag2);
|
|
||||||
if (aTopic == "plugin-crashed") {
|
|
||||||
addDumpIDToMessage("pluginDumpID");
|
|
||||||
addDumpIDToMessage("browserDumpID");
|
|
||||||
|
|
||||||
let pluginID = aSubject.getPropertyAsAString("pluginDumpID");
|
|
||||||
let extra = this._getExtraData(pluginID);
|
|
||||||
if (extra && ("additional_minidumps" in extra)) {
|
|
||||||
let dumpNames = extra.additional_minidumps.split(',');
|
|
||||||
for (let name of dumpNames) {
|
|
||||||
message.dumpIDs.push({id: pluginID + "-" + name, extension: "dmp"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // ipc:content-shutdown
|
|
||||||
addDumpIDToMessage("dumpID");
|
|
||||||
}
|
|
||||||
this._sendAsyncMessage("SPProcessCrashService", message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_getCrashDumpDir: function() {
|
|
||||||
if (!this._crashDumpDir) {
|
|
||||||
this._crashDumpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
|
||||||
this._crashDumpDir.append("minidumps");
|
|
||||||
}
|
|
||||||
return this._crashDumpDir;
|
|
||||||
},
|
|
||||||
|
|
||||||
_getExtraData: function(dumpId) {
|
|
||||||
let extraFile = this._getCrashDumpDir().clone();
|
|
||||||
extraFile.append(dumpId + ".extra");
|
|
||||||
if (!extraFile.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return parseKeyValuePairsFromFile(extraFile);
|
|
||||||
},
|
|
||||||
|
|
||||||
_deleteCrashDumpFiles: function(aFilenames) {
|
|
||||||
var crashDumpDir = this._getCrashDumpDir();
|
|
||||||
if (!crashDumpDir.exists()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var success = aFilenames.length != 0;
|
|
||||||
aFilenames.forEach(function(crashFilename) {
|
|
||||||
var file = crashDumpDir.clone();
|
|
||||||
file.append(crashFilename);
|
|
||||||
if (file.exists()) {
|
|
||||||
file.remove(false);
|
|
||||||
} else {
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return success;
|
|
||||||
},
|
|
||||||
|
|
||||||
_findCrashDumpFiles: function(aToIgnore) {
|
|
||||||
var crashDumpDir = this._getCrashDumpDir();
|
|
||||||
var entries = crashDumpDir.exists() && crashDumpDir.directoryEntries;
|
|
||||||
if (!entries) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
var crashDumpFiles = [];
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
var file = entries.getNext().QueryInterface(Ci.nsIFile);
|
|
||||||
var path = String(file.path);
|
|
||||||
if (path.match(/\.(dmp|extra)$/) && !aToIgnore[path]) {
|
|
||||||
crashDumpFiles.push(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return crashDumpFiles.concat();
|
|
||||||
},
|
|
||||||
|
|
||||||
_getURI: function (url) {
|
|
||||||
return Services.io.newURI(url, null, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
_readUrlAsString: function(aUrl) {
|
|
||||||
// Fetch script content as we can't use scriptloader's loadSubScript
|
|
||||||
// to evaluate http:// urls...
|
|
||||||
var scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
|
||||||
.getService(Ci.nsIScriptableInputStream);
|
|
||||||
var channel = Services.io.newChannel(aUrl, null, null);
|
|
||||||
var input = channel.open();
|
|
||||||
scriptableStream.init(input);
|
|
||||||
|
|
||||||
var str;
|
|
||||||
var buffer = [];
|
|
||||||
|
|
||||||
while ((str = scriptableStream.read(4096))) {
|
|
||||||
buffer.push(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
var output = buffer.join("");
|
|
||||||
|
|
||||||
scriptableStream.close();
|
|
||||||
input.close();
|
|
||||||
|
|
||||||
var status;
|
|
||||||
try {
|
|
||||||
channel.QueryInterface(Ci.nsIHttpChannel);
|
|
||||||
status = channel.responseStatus;
|
|
||||||
} catch(e) {
|
|
||||||
/* The channel is not a nsIHttpCHannel, but that's fine */
|
|
||||||
dump("-*- _readUrlAsString: Got an error while fetching " +
|
|
||||||
"chrome script '" + aUrl + "': (" + e.name + ") " + e.message + ". " +
|
|
||||||
"Ignoring.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == 404) {
|
|
||||||
throw new SpecialPowersException(
|
|
||||||
"Error while executing chrome script '" + aUrl + "':\n" +
|
|
||||||
"The script doesn't exists. Ensure you have registered it in " +
|
|
||||||
"'support-files' in your mochitest.ini.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* messageManager callback function
|
|
||||||
* This will get requests from our API in the window and process them in chrome for it
|
|
||||||
**/
|
|
||||||
_receiveMessageAPI: function(aMessage) {
|
|
||||||
// We explicitly return values in the below code so that this function
|
|
||||||
// doesn't trigger a flurry of warnings about "does not always return
|
|
||||||
// a value".
|
|
||||||
switch(aMessage.name) {
|
|
||||||
case "SPPrefService":
|
|
||||||
var prefs = Services.prefs;
|
|
||||||
var prefType = aMessage.json.prefType.toUpperCase();
|
|
||||||
var prefName = aMessage.json.prefName;
|
|
||||||
var prefValue = "prefValue" in aMessage.json ? aMessage.json.prefValue : null;
|
|
||||||
|
|
||||||
if (aMessage.json.op == "get") {
|
|
||||||
if (!prefName || !prefType)
|
|
||||||
throw new SpecialPowersException("Invalid parameters for get in SPPrefService");
|
|
||||||
|
|
||||||
// return null if the pref doesn't exist
|
|
||||||
if (prefs.getPrefType(prefName) == prefs.PREF_INVALID)
|
|
||||||
return null;
|
|
||||||
} else if (aMessage.json.op == "set") {
|
|
||||||
if (!prefName || !prefType || prefValue === null)
|
|
||||||
throw new SpecialPowersException("Invalid parameters for set in SPPrefService");
|
|
||||||
} else if (aMessage.json.op == "clear") {
|
|
||||||
if (!prefName)
|
|
||||||
throw new SpecialPowersException("Invalid parameters for clear in SPPrefService");
|
|
||||||
} else {
|
|
||||||
throw new SpecialPowersException("Invalid operation for SPPrefService");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we make the call
|
|
||||||
switch(prefType) {
|
|
||||||
case "BOOL":
|
|
||||||
if (aMessage.json.op == "get")
|
|
||||||
return(prefs.getBoolPref(prefName));
|
|
||||||
else
|
|
||||||
return(prefs.setBoolPref(prefName, prefValue));
|
|
||||||
case "INT":
|
|
||||||
if (aMessage.json.op == "get")
|
|
||||||
return(prefs.getIntPref(prefName));
|
|
||||||
else
|
|
||||||
return(prefs.setIntPref(prefName, prefValue));
|
|
||||||
case "CHAR":
|
|
||||||
if (aMessage.json.op == "get")
|
|
||||||
return(prefs.getCharPref(prefName));
|
|
||||||
else
|
|
||||||
return(prefs.setCharPref(prefName, prefValue));
|
|
||||||
case "COMPLEX":
|
|
||||||
if (aMessage.json.op == "get")
|
|
||||||
return(prefs.getComplexValue(prefName, prefValue[0]));
|
|
||||||
else
|
|
||||||
return(prefs.setComplexValue(prefName, prefValue[0], prefValue[1]));
|
|
||||||
case "":
|
|
||||||
if (aMessage.json.op == "clear") {
|
|
||||||
prefs.clearUserPref(prefName);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined; // See comment at the beginning of this function.
|
|
||||||
|
|
||||||
case "SPProcessCrashService":
|
|
||||||
switch (aMessage.json.op) {
|
|
||||||
case "register-observer":
|
|
||||||
this._addProcessCrashObservers();
|
|
||||||
break;
|
|
||||||
case "unregister-observer":
|
|
||||||
this._removeProcessCrashObservers();
|
|
||||||
break;
|
|
||||||
case "delete-crash-dump-files":
|
|
||||||
return this._deleteCrashDumpFiles(aMessage.json.filenames);
|
|
||||||
case "find-crash-dump-files":
|
|
||||||
return this._findCrashDumpFiles(aMessage.json.crashDumpFilesToIgnore);
|
|
||||||
default:
|
|
||||||
throw new SpecialPowersException("Invalid operation for SPProcessCrashService");
|
|
||||||
}
|
|
||||||
return undefined; // See comment at the beginning of this function.
|
|
||||||
|
|
||||||
case "SPPermissionManager":
|
|
||||||
let msg = aMessage.json;
|
|
||||||
|
|
||||||
let secMan = Services.scriptSecurityManager;
|
|
||||||
let principal = secMan.getAppCodebasePrincipal(this._getURI(msg.url), msg.appId, msg.isInBrowserElement);
|
|
||||||
|
|
||||||
switch (msg.op) {
|
|
||||||
case "add":
|
|
||||||
Services.perms.addFromPrincipal(principal, msg.type, msg.permission);
|
|
||||||
break;
|
|
||||||
case "remove":
|
|
||||||
Services.perms.removeFromPrincipal(principal, msg.type);
|
|
||||||
break;
|
|
||||||
case "has":
|
|
||||||
let hasPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type);
|
|
||||||
if (hasPerm == Ci.nsIPermissionManager.ALLOW_ACTION)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case "test":
|
|
||||||
let testPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type, msg.value);
|
|
||||||
if (testPerm == msg.value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new SpecialPowersException("Invalid operation for " +
|
|
||||||
"SPPermissionManager");
|
|
||||||
}
|
|
||||||
return undefined; // See comment at the beginning of this function.
|
|
||||||
|
|
||||||
case "SPWebAppService":
|
|
||||||
let Webapps = {};
|
|
||||||
Components.utils.import("resource://gre/modules/Webapps.jsm", Webapps);
|
|
||||||
switch (aMessage.json.op) {
|
|
||||||
case "set-launchable":
|
|
||||||
let val = Webapps.DOMApplicationRegistry.allAppsLaunchable;
|
|
||||||
Webapps.DOMApplicationRegistry.allAppsLaunchable = aMessage.json.launchable;
|
|
||||||
return val;
|
|
||||||
default:
|
|
||||||
throw new SpecialPowersException("Invalid operation for SPWebAppsService");
|
|
||||||
}
|
|
||||||
return undefined; // See comment at the beginning of this function.
|
|
||||||
|
|
||||||
case "SPObserverService":
|
|
||||||
switch (aMessage.json.op) {
|
|
||||||
case "notify":
|
|
||||||
let topic = aMessage.json.observerTopic;
|
|
||||||
let data = aMessage.json.observerData
|
|
||||||
Services.obs.notifyObservers(null, topic, data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new SpecialPowersException("Invalid operation for SPObserverervice");
|
|
||||||
}
|
|
||||||
return undefined; // See comment at the beginning of this function.
|
|
||||||
|
|
||||||
case "SPLoadChromeScript":
|
|
||||||
var url = aMessage.json.url;
|
|
||||||
var id = aMessage.json.id;
|
|
||||||
|
|
||||||
var jsScript = this._readUrlAsString(url);
|
|
||||||
|
|
||||||
// Setup a chrome sandbox that has access to sendAsyncMessage
|
|
||||||
// and addMessageListener in order to communicate with
|
|
||||||
// the mochitest.
|
|
||||||
var systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
|
||||||
var sb = Components.utils.Sandbox(systemPrincipal);
|
|
||||||
var mm = aMessage.target
|
|
||||||
.QueryInterface(Ci.nsIFrameLoaderOwner)
|
|
||||||
.frameLoader
|
|
||||||
.messageManager;
|
|
||||||
sb.sendAsyncMessage = (name, message) => {
|
|
||||||
mm.sendAsyncMessage("SPChromeScriptMessage",
|
|
||||||
{ id: id, name: name, message: message });
|
|
||||||
};
|
|
||||||
sb.addMessageListener = (name, listener) => {
|
|
||||||
this._chromeScriptListeners.push({ id: id, name: name, listener: listener });
|
|
||||||
};
|
|
||||||
|
|
||||||
// Also expose assertion functions
|
|
||||||
let reporter = function (err, message, stack) {
|
|
||||||
// Pipe assertions back to parent process
|
|
||||||
mm.sendAsyncMessage("SPChromeScriptAssert",
|
|
||||||
{ id: id, url: url, err: err, message: message,
|
|
||||||
stack: stack });
|
|
||||||
};
|
|
||||||
Object.defineProperty(sb, "assert", {
|
|
||||||
get: function () {
|
|
||||||
let scope = Components.utils.createObjectIn(sb);
|
|
||||||
Services.scriptloader.loadSubScript("resource://specialpowers/Assert.jsm",
|
|
||||||
scope);
|
|
||||||
|
|
||||||
let assert = new scope.Assert(reporter);
|
|
||||||
delete sb.assert;
|
|
||||||
return sb.assert = assert;
|
|
||||||
},
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// Evaluate the chrome script
|
|
||||||
try {
|
|
||||||
Components.utils.evalInSandbox(jsScript, sb, "1.8", url, 1);
|
|
||||||
} catch(e) {
|
|
||||||
throw new SpecialPowersException("Error while executing chrome " +
|
|
||||||
"script '" + url + "':\n" + e + "\n" +
|
|
||||||
e.fileName + ":" + e.lineNumber);
|
|
||||||
}
|
|
||||||
return undefined; // See comment at the beginning of this function.
|
|
||||||
|
|
||||||
case "SPChromeScriptMessage":
|
|
||||||
var id = aMessage.json.id;
|
|
||||||
var name = aMessage.json.name;
|
|
||||||
var message = aMessage.json.message;
|
|
||||||
this._chromeScriptListeners
|
|
||||||
.filter(o => (o.name == name && o.id == id))
|
|
||||||
.forEach(o => o.listener(message));
|
|
||||||
return undefined; // See comment at the beginning of this function.
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new SpecialPowersException("Unrecognized Special Powers API");
|
|
||||||
}
|
|
||||||
|
|
||||||
// We throw an exception before reaching this explicit return because
|
|
||||||
// we should never be arriving here anyway.
|
|
||||||
throw new SpecialPowersException("Unreached code");
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,134 +0,0 @@
|
|||||||
/* 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 code is loaded in every child process that is started by mochitest in
|
|
||||||
* order to be used as a replacement for UniversalXPConnect
|
|
||||||
*/
|
|
||||||
|
|
||||||
function SpecialPowers(window) {
|
|
||||||
this.window = Components.utils.getWeakReference(window);
|
|
||||||
this._encounteredCrashDumpFiles = [];
|
|
||||||
this._unexpectedCrashDumpFiles = { };
|
|
||||||
this._crashDumpDir = null;
|
|
||||||
this.DOMWindowUtils = bindDOMWindowUtils(window);
|
|
||||||
Object.defineProperty(this, 'Components', {
|
|
||||||
configurable: true, enumerable: true, get: function() {
|
|
||||||
var win = this.window.get();
|
|
||||||
if (!win)
|
|
||||||
return null;
|
|
||||||
return getRawComponents(win);
|
|
||||||
}});
|
|
||||||
this._pongHandlers = [];
|
|
||||||
this._messageListener = this._messageReceived.bind(this);
|
|
||||||
addMessageListener("SPPingService", this._messageListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecialPowers.prototype = new SpecialPowersAPI();
|
|
||||||
|
|
||||||
SpecialPowers.prototype.toString = function() { return "[SpecialPowers]"; };
|
|
||||||
SpecialPowers.prototype.sanityCheck = function() { return "foo"; };
|
|
||||||
|
|
||||||
// This gets filled in in the constructor.
|
|
||||||
SpecialPowers.prototype.DOMWindowUtils = undefined;
|
|
||||||
SpecialPowers.prototype.Components = undefined;
|
|
||||||
|
|
||||||
SpecialPowers.prototype._sendSyncMessage = function(msgname, msg) {
|
|
||||||
return sendSyncMessage(msgname, msg);
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.prototype._sendAsyncMessage = function(msgname, msg) {
|
|
||||||
sendAsyncMessage(msgname, msg);
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.prototype._addMessageListener = function(msgname, listener) {
|
|
||||||
addMessageListener(msgname, listener);
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.prototype._removeMessageListener = function(msgname, listener) {
|
|
||||||
removeMessageListener(msgname, listener);
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.prototype.registerProcessCrashObservers = function() {
|
|
||||||
addMessageListener("SPProcessCrashService", this._messageListener);
|
|
||||||
sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.prototype.unregisterProcessCrashObservers = function() {
|
|
||||||
addMessageListener("SPProcessCrashService", this._messageListener);
|
|
||||||
sendSyncMessage("SPProcessCrashService", { op: "unregister-observer" });
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.prototype._messageReceived = function(aMessage) {
|
|
||||||
switch (aMessage.name) {
|
|
||||||
case "SPProcessCrashService":
|
|
||||||
if (aMessage.json.type == "crash-observed") {
|
|
||||||
for (let e of aMessage.json.dumpIDs) {
|
|
||||||
this._encounteredCrashDumpFiles.push(e.id + "." + e.extension);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "SPPingService":
|
|
||||||
if (aMessage.json.op == "pong") {
|
|
||||||
var handler = this._pongHandlers.shift();
|
|
||||||
if (handler) {
|
|
||||||
handler();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.prototype.quit = function() {
|
|
||||||
sendAsyncMessage("SpecialPowers.Quit", {});
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowers.prototype.executeAfterFlushingMessageQueue = function(aCallback) {
|
|
||||||
this._pongHandlers.push(aCallback);
|
|
||||||
sendAsyncMessage("SPPingService", { op: "ping" });
|
|
||||||
};
|
|
||||||
|
|
||||||
// Expose everything but internal APIs (starting with underscores) to
|
|
||||||
// web content. We cannot use Object.keys to view SpecialPowers.prototype since
|
|
||||||
// we are using the functions from SpecialPowersAPI.prototype
|
|
||||||
SpecialPowers.prototype.__exposedProps__ = {};
|
|
||||||
for (var i in SpecialPowers.prototype) {
|
|
||||||
if (i.charAt(0) != "_")
|
|
||||||
SpecialPowers.prototype.__exposedProps__[i] = "r";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach our API to the window.
|
|
||||||
function attachSpecialPowersToWindow(aWindow) {
|
|
||||||
try {
|
|
||||||
if ((aWindow !== null) &&
|
|
||||||
(aWindow !== undefined) &&
|
|
||||||
(aWindow.wrappedJSObject) &&
|
|
||||||
!(aWindow.wrappedJSObject.SpecialPowers)) {
|
|
||||||
aWindow.wrappedJSObject.SpecialPowers = new SpecialPowers(aWindow);
|
|
||||||
}
|
|
||||||
} catch(ex) {
|
|
||||||
dump("TEST-INFO | specialpowers.js | Failed to attach specialpowers to window exception: " + ex + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a frame script, so it may be running in a content process.
|
|
||||||
// In any event, it is targeted at a specific "tab", so we listen for
|
|
||||||
// the DOMWindowCreated event to be notified about content windows
|
|
||||||
// being created in this context.
|
|
||||||
|
|
||||||
function SpecialPowersManager() {
|
|
||||||
addEventListener("DOMWindowCreated", this, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
SpecialPowersManager.prototype = {
|
|
||||||
handleEvent: function handleEvent(aEvent) {
|
|
||||||
var window = aEvent.target.defaultView;
|
|
||||||
attachSpecialPowersToWindow(window);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var specialpowersmanager = new SpecialPowersManager();
|
|
||||||
|
|
||||||
this.SpecialPowers = SpecialPowers;
|
|
||||||
this.attachSpecialPowersToWindow = attachSpecialPowersToWindow;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,442 +0,0 @@
|
|||||||
/* 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/. */
|
|
||||||
|
|
||||||
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
|
|
||||||
// When you see a javadoc comment that contains a number, it's a reference to a
|
|
||||||
// specific section of the CommonJS spec.
|
|
||||||
//
|
|
||||||
// Originally from narwhal.js (http://narwhaljs.org)
|
|
||||||
// Copyright (c) 2009 Thomas Robinson <280north.com>
|
|
||||||
// MIT license: http://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = [
|
|
||||||
"Assert"
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. The assert module provides functions that throw AssertionError's when
|
|
||||||
* particular conditions are not met.
|
|
||||||
*
|
|
||||||
* To use the module you'll need to instantiate it first, which allows consumers
|
|
||||||
* to override certain behavior on the newly obtained instance. For examples,
|
|
||||||
* see the javadoc comments for the `report` member function.
|
|
||||||
*/
|
|
||||||
let Assert = this.Assert = function(reporterFunc) {
|
|
||||||
if (reporterFunc)
|
|
||||||
this.setReporter(reporterFunc);
|
|
||||||
};
|
|
||||||
|
|
||||||
function instanceOf(object, type) {
|
|
||||||
return Object.prototype.toString.call(object) == "[object " + type + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
function replacer(key, value) {
|
|
||||||
if (value === undefined) {
|
|
||||||
return "" + value;
|
|
||||||
}
|
|
||||||
if (typeof value === "number" && (isNaN(value) || !isFinite(value))) {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
if (typeof value === "function" || instanceOf(value, "RegExp")) {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const kTruncateLength = 128;
|
|
||||||
|
|
||||||
function truncate(text, newLength = kTruncateLength) {
|
|
||||||
if (typeof text == "string") {
|
|
||||||
return text.length < newLength ? text : text.slice(0, newLength);
|
|
||||||
} else {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMessage(error, prefix = "") {
|
|
||||||
let actual, expected;
|
|
||||||
// Wrap calls to JSON.stringify in try...catch blocks, as they may throw. If
|
|
||||||
// so, fall back to toString().
|
|
||||||
try {
|
|
||||||
actual = JSON.stringify(error.actual, replacer);
|
|
||||||
} catch (ex) {
|
|
||||||
actual = Object.prototype.toString.call(error.actual);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
expected = JSON.stringify(error.expected, replacer);
|
|
||||||
} catch (ex) {
|
|
||||||
expected = Object.prototype.toString.call(error.expected);
|
|
||||||
}
|
|
||||||
let message = prefix;
|
|
||||||
if (error.operator) {
|
|
||||||
message += (prefix ? " - " : "") + truncate(actual) + " " + error.operator +
|
|
||||||
" " + truncate(expected);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 2. The AssertionError is defined in assert.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* new assert.AssertionError({
|
|
||||||
* message: message,
|
|
||||||
* actual: actual,
|
|
||||||
* expected: expected,
|
|
||||||
* operator: operator
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* At present only the four keys mentioned above are used and
|
|
||||||
* understood by the spec. Implementations or sub modules can pass
|
|
||||||
* other keys to the AssertionError's constructor - they will be
|
|
||||||
* ignored.
|
|
||||||
*/
|
|
||||||
Assert.AssertionError = function(options) {
|
|
||||||
this.name = "AssertionError";
|
|
||||||
this.actual = options.actual;
|
|
||||||
this.expected = options.expected;
|
|
||||||
this.operator = options.operator;
|
|
||||||
this.message = getMessage(this, options.message);
|
|
||||||
// The part of the stack that comes from this module is not interesting.
|
|
||||||
let stack = Components.stack;
|
|
||||||
do {
|
|
||||||
stack = stack.caller;
|
|
||||||
} while(stack.filename && stack.filename.contains("Assert.jsm"))
|
|
||||||
this.stack = stack;
|
|
||||||
};
|
|
||||||
|
|
||||||
// assert.AssertionError instanceof Error
|
|
||||||
Assert.AssertionError.prototype = Object.create(Error.prototype, {
|
|
||||||
constructor: {
|
|
||||||
value: Assert.AssertionError,
|
|
||||||
enumerable: false,
|
|
||||||
writable: true,
|
|
||||||
configurable: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let proto = Assert.prototype;
|
|
||||||
|
|
||||||
proto._reporter = null;
|
|
||||||
/**
|
|
||||||
* Set a custom assertion report handler function. Arguments passed in to this
|
|
||||||
* function are:
|
|
||||||
* err (AssertionError|null) An error object when the assertion failed or null
|
|
||||||
* when it passed
|
|
||||||
* message (string) Message describing the assertion
|
|
||||||
* stack (stack) Stack trace of the assertion function
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* ```js
|
|
||||||
* Assert.setReporter(function customReporter(err, message, stack) {
|
|
||||||
* if (err) {
|
|
||||||
* do_report_result(false, err.message, err.stack);
|
|
||||||
* } else {
|
|
||||||
* do_report_result(true, message, stack);
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param reporterFunc
|
|
||||||
* (function) Report handler function
|
|
||||||
*/
|
|
||||||
proto.setReporter = function(reporterFunc) {
|
|
||||||
this._reporter = reporterFunc;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 3. All of the following functions must throw an AssertionError when a
|
|
||||||
* corresponding condition is not met, with a message that may be undefined if
|
|
||||||
* not provided. All assertion methods provide both the actual and expected
|
|
||||||
* values to the assertion error for display purposes.
|
|
||||||
*
|
|
||||||
* This report method only throws errors on assertion failures, as per spec,
|
|
||||||
* but consumers of this module (think: xpcshell-test, mochitest) may want to
|
|
||||||
* override this default implementation.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* ```js
|
|
||||||
* // The following will report an assertion failure.
|
|
||||||
* this.report(1 != 2, 1, 2, "testing JS number math!", "==");
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param failed
|
|
||||||
* (boolean) Indicates if the assertion failed or not
|
|
||||||
* @param actual
|
|
||||||
* (mixed) The result of evaluating the assertion
|
|
||||||
* @param expected (optional)
|
|
||||||
* (mixed) Expected result from the test author
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
* @param operator (optional)
|
|
||||||
* (string) Operation qualifier used by the assertion method (ex: '==')
|
|
||||||
*/
|
|
||||||
proto.report = function(failed, actual, expected, message, operator) {
|
|
||||||
let err = new Assert.AssertionError({
|
|
||||||
message: message,
|
|
||||||
actual: actual,
|
|
||||||
expected: expected,
|
|
||||||
operator: operator
|
|
||||||
});
|
|
||||||
if (!this._reporter) {
|
|
||||||
// If no custom reporter is set, throw the error.
|
|
||||||
if (failed) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this._reporter(failed ? err : null, message, err.stack);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 4. Pure assertion tests whether a value is truthy, as determined by !!guard.
|
|
||||||
* assert.ok(guard, message_opt);
|
|
||||||
* This statement is equivalent to assert.equal(true, !!guard, message_opt);.
|
|
||||||
* To test strictly for the value true, use assert.strictEqual(true, guard,
|
|
||||||
* message_opt);.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* (mixed) Test subject to be evaluated as truthy
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
*/
|
|
||||||
proto.ok = function(value, message) {
|
|
||||||
this.report(!value, value, true, message, "==");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 5. The equality assertion tests shallow, coercive equality with ==.
|
|
||||||
* assert.equal(actual, expected, message_opt);
|
|
||||||
*
|
|
||||||
* @param actual
|
|
||||||
* (mixed) Test subject to be evaluated as equivalent to `expected`
|
|
||||||
* @param expected
|
|
||||||
* (mixed) Test reference to evaluate against `actual`
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
*/
|
|
||||||
proto.equal = function equal(actual, expected, message) {
|
|
||||||
this.report(actual != expected, actual, expected, message, "==");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 6. The non-equality assertion tests for whether two objects are not equal
|
|
||||||
* with != assert.notEqual(actual, expected, message_opt);
|
|
||||||
*
|
|
||||||
* @param actual
|
|
||||||
* (mixed) Test subject to be evaluated as NOT equivalent to `expected`
|
|
||||||
* @param expected
|
|
||||||
* (mixed) Test reference to evaluate against `actual`
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
*/
|
|
||||||
proto.notEqual = function notEqual(actual, expected, message) {
|
|
||||||
this.report(actual == expected, actual, expected, message, "!=");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 7. The equivalence assertion tests a deep equality relation.
|
|
||||||
* assert.deepEqual(actual, expected, message_opt);
|
|
||||||
*
|
|
||||||
* We check using the most exact approximation of equality between two objects
|
|
||||||
* to keep the chance of false positives to a minimum.
|
|
||||||
* `JSON.stringify` is not designed to be used for this purpose; objects may
|
|
||||||
* have ambiguous `toJSON()` implementations that would influence the test.
|
|
||||||
*
|
|
||||||
* @param actual
|
|
||||||
* (mixed) Test subject to be evaluated as equivalent to `expected`, including nested properties
|
|
||||||
* @param expected
|
|
||||||
* (mixed) Test reference to evaluate against `actual`
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
*/
|
|
||||||
proto.deepEqual = function deepEqual(actual, expected, message) {
|
|
||||||
this.report(!_deepEqual(actual, expected), actual, expected, message, "deepEqual");
|
|
||||||
};
|
|
||||||
|
|
||||||
function _deepEqual(actual, expected) {
|
|
||||||
// 7.1. All identical values are equivalent, as determined by ===.
|
|
||||||
if (actual === expected) {
|
|
||||||
return true;
|
|
||||||
// 7.2. If the expected value is a Date object, the actual value is
|
|
||||||
// equivalent if it is also a Date object that refers to the same time.
|
|
||||||
} else if (instanceOf(actual, "Date") && instanceOf(expected, "Date")) {
|
|
||||||
return actual.getTime() === expected.getTime();
|
|
||||||
// 7.3 If the expected value is a RegExp object, the actual value is
|
|
||||||
// equivalent if it is also a RegExp object with the same source and
|
|
||||||
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
|
|
||||||
} else if (instanceOf(actual, "RegExp") && instanceOf(expected, "RegExp")) {
|
|
||||||
return actual.source === expected.source &&
|
|
||||||
actual.global === expected.global &&
|
|
||||||
actual.multiline === expected.multiline &&
|
|
||||||
actual.lastIndex === expected.lastIndex &&
|
|
||||||
actual.ignoreCase === expected.ignoreCase;
|
|
||||||
// 7.4. Other pairs that do not both pass typeof value == "object",
|
|
||||||
// equivalence is determined by ==.
|
|
||||||
} else if (typeof actual != "object" && typeof expected != "object") {
|
|
||||||
return actual == expected;
|
|
||||||
// 7.5 For all other Object pairs, including Array objects, equivalence is
|
|
||||||
// determined by having the same number of owned properties (as verified
|
|
||||||
// with Object.prototype.hasOwnProperty.call), the same set of keys
|
|
||||||
// (although not necessarily the same order), equivalent values for every
|
|
||||||
// corresponding key, and an identical 'prototype' property. Note: this
|
|
||||||
// accounts for both named and indexed properties on Arrays.
|
|
||||||
} else {
|
|
||||||
return objEquiv(actual, expected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isUndefinedOrNull(value) {
|
|
||||||
return value === null || value === undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isArguments(object) {
|
|
||||||
return instanceOf(object, "Arguments");
|
|
||||||
}
|
|
||||||
|
|
||||||
function objEquiv(a, b) {
|
|
||||||
if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// An identical 'prototype' property.
|
|
||||||
if (a.prototype !== b.prototype) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Object.keys may be broken through screwy arguments passing. Converting to
|
|
||||||
// an array solves the problem.
|
|
||||||
if (isArguments(a)) {
|
|
||||||
if (!isArguments(b)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
a = pSlice.call(a);
|
|
||||||
b = pSlice.call(b);
|
|
||||||
return _deepEqual(a, b);
|
|
||||||
}
|
|
||||||
let ka, kb, key, i;
|
|
||||||
try {
|
|
||||||
ka = Object.keys(a);
|
|
||||||
kb = Object.keys(b);
|
|
||||||
} catch (e) {
|
|
||||||
// Happens when one is a string literal and the other isn't
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Having the same number of owned properties (keys incorporates
|
|
||||||
// hasOwnProperty)
|
|
||||||
if (ka.length != kb.length)
|
|
||||||
return false;
|
|
||||||
// The same set of keys (although not necessarily the same order),
|
|
||||||
ka.sort();
|
|
||||||
kb.sort();
|
|
||||||
// Equivalent values for every corresponding key, and possibly expensive deep
|
|
||||||
// test
|
|
||||||
for (i = ka.length - 1; i >= 0; i--) {
|
|
||||||
key = ka[i];
|
|
||||||
if (!_deepEqual(a[key], b[key])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 8. The non-equivalence assertion tests for any deep inequality.
|
|
||||||
* assert.notDeepEqual(actual, expected, message_opt);
|
|
||||||
*
|
|
||||||
* @param actual
|
|
||||||
* (mixed) Test subject to be evaluated as NOT equivalent to `expected`, including nested properties
|
|
||||||
* @param expected
|
|
||||||
* (mixed) Test reference to evaluate against `actual`
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
*/
|
|
||||||
proto.notDeepEqual = function notDeepEqual(actual, expected, message) {
|
|
||||||
this.report(_deepEqual(actual, expected), actual, expected, message, "notDeepEqual");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 9. The strict equality assertion tests strict equality, as determined by ===.
|
|
||||||
* assert.strictEqual(actual, expected, message_opt);
|
|
||||||
*
|
|
||||||
* @param actual
|
|
||||||
* (mixed) Test subject to be evaluated as strictly equivalent to `expected`
|
|
||||||
* @param expected
|
|
||||||
* (mixed) Test reference to evaluate against `actual`
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
*/
|
|
||||||
proto.strictEqual = function strictEqual(actual, expected, message) {
|
|
||||||
this.report(actual !== expected, actual, expected, message, "===");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 10. The strict non-equality assertion tests for strict inequality, as
|
|
||||||
* determined by !==. assert.notStrictEqual(actual, expected, message_opt);
|
|
||||||
*
|
|
||||||
* @param actual
|
|
||||||
* (mixed) Test subject to be evaluated as NOT strictly equivalent to `expected`
|
|
||||||
* @param expected
|
|
||||||
* (mixed) Test reference to evaluate against `actual`
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
*/
|
|
||||||
proto.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
|
||||||
this.report(actual === expected, actual, expected, message, "!==");
|
|
||||||
};
|
|
||||||
|
|
||||||
function expectedException(actual, expected) {
|
|
||||||
if (!actual || !expected) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instanceOf(expected, "RegExp")) {
|
|
||||||
return expected.test(actual);
|
|
||||||
} else if (actual instanceof expected) {
|
|
||||||
return true;
|
|
||||||
} else if (expected.call({}, actual) === true) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 11. Expected to throw an error:
|
|
||||||
* assert.throws(block, Error_opt, message_opt);
|
|
||||||
*
|
|
||||||
* @param block
|
|
||||||
* (function) Function block to evaluate and catch eventual thrown errors
|
|
||||||
* @param expected (optional)
|
|
||||||
* (mixed) Test reference to evaluate against the thrown result from `block`
|
|
||||||
* @param message (optional)
|
|
||||||
* (string) Short explanation of the expected result
|
|
||||||
*/
|
|
||||||
proto.throws = function(block, expected, message) {
|
|
||||||
let actual;
|
|
||||||
|
|
||||||
if (typeof expected === "string") {
|
|
||||||
message = expected;
|
|
||||||
expected = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
block();
|
|
||||||
} catch (e) {
|
|
||||||
actual = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
message = (expected && expected.name ? " (" + expected.name + ")." : ".") +
|
|
||||||
(message ? " " + message : ".");
|
|
||||||
|
|
||||||
if (!actual) {
|
|
||||||
this.report(true, actual, expected, "Missing expected exception" + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((actual && expected && !expectedException(actual, expected))) {
|
|
||||||
throw actual;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.report(false, expected, expected, message);
|
|
||||||
};
|
|
@ -1,125 +0,0 @@
|
|||||||
/* 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.EXPORTED_SYMBOLS = ["MockColorPicker"];
|
|
||||||
|
|
||||||
const Cc = Components.classes;
|
|
||||||
const Ci = Components.interfaces;
|
|
||||||
const Cm = Components.manager;
|
|
||||||
const Cu = Components.utils;
|
|
||||||
|
|
||||||
const CONTRACT_ID = "@mozilla.org/colorpicker;1";
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
|
|
||||||
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
|
||||||
var oldClassID = "", oldFactory = null;
|
|
||||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
|
|
||||||
var newFactory = function (window) {
|
|
||||||
return {
|
|
||||||
createInstance: function(aOuter, aIID) {
|
|
||||||
if (aOuter)
|
|
||||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
|
||||||
return new MockColorPickerInstance(window).QueryInterface(aIID);
|
|
||||||
},
|
|
||||||
lockFactory: function(aLock) {
|
|
||||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
},
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.MockColorPicker = {
|
|
||||||
init: function(window) {
|
|
||||||
this.reset();
|
|
||||||
this.factory = newFactory(window);
|
|
||||||
if (!registrar.isCIDRegistered(newClassID)) {
|
|
||||||
try {
|
|
||||||
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
|
|
||||||
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
|
|
||||||
} catch(ex) {
|
|
||||||
oldClassID = "";
|
|
||||||
oldFactory = null;
|
|
||||||
dump("TEST-INFO | can't get colorpicker registered component, " +
|
|
||||||
"assuming there is none");
|
|
||||||
}
|
|
||||||
if (oldClassID != "" && oldFactory != null) {
|
|
||||||
registrar.unregisterFactory(oldClassID, oldFactory);
|
|
||||||
}
|
|
||||||
registrar.registerFactory(newClassID, "", CONTRACT_ID, this.factory);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reset: function() {
|
|
||||||
this.returnColor = "";
|
|
||||||
this.showCallback = null;
|
|
||||||
this.shown = false;
|
|
||||||
this.showing = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
cleanup: function() {
|
|
||||||
var previousFactory = this.factory;
|
|
||||||
this.reset();
|
|
||||||
this.factory = null;
|
|
||||||
|
|
||||||
registrar.unregisterFactory(newClassID, previousFactory);
|
|
||||||
if (oldClassID != "" && oldFactory != null) {
|
|
||||||
registrar.registerFactory(oldClassID, "", CONTRACT_ID, oldFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function MockColorPickerInstance(window) {
|
|
||||||
this.window = window;
|
|
||||||
};
|
|
||||||
MockColorPickerInstance.prototype = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIColorPicker]),
|
|
||||||
init: function(aParent, aTitle, aInitialColor) {
|
|
||||||
this.parent = aParent;
|
|
||||||
this.initialColor = aInitialColor;
|
|
||||||
},
|
|
||||||
initialColor: "",
|
|
||||||
parent: null,
|
|
||||||
open: function(aColorPickerShownCallback) {
|
|
||||||
MockColorPicker.showing = true;
|
|
||||||
MockColorPicker.shown = true;
|
|
||||||
|
|
||||||
this.window.setTimeout(function() {
|
|
||||||
let result = "";
|
|
||||||
try {
|
|
||||||
if (typeof MockColorPicker.showCallback == "function") {
|
|
||||||
var updateCb = function(color) {
|
|
||||||
result = color;
|
|
||||||
aColorPickerShownCallback.update(color);
|
|
||||||
};
|
|
||||||
let returnColor = MockColorPicker.showCallback(this, updateCb);
|
|
||||||
if (typeof returnColor === "string") {
|
|
||||||
result = returnColor;
|
|
||||||
}
|
|
||||||
} else if (typeof MockColorPicker.returnColor === "string") {
|
|
||||||
result = MockColorPicker.returnColor;
|
|
||||||
}
|
|
||||||
} catch(ex) {
|
|
||||||
dump("TEST-UNEXPECTED-FAIL | Exception in MockColorPicker.jsm open() " +
|
|
||||||
"method: " + ex + "\n");
|
|
||||||
}
|
|
||||||
if (aColorPickerShownCallback) {
|
|
||||||
aColorPickerShownCallback.done(result);
|
|
||||||
}
|
|
||||||
}.bind(this), 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Expose everything to content. We call reset() here so that all of the
|
|
||||||
// relevant lazy expandos get added.
|
|
||||||
MockColorPicker.reset();
|
|
||||||
function exposeAll(obj) {
|
|
||||||
var props = {};
|
|
||||||
for (var prop in obj)
|
|
||||||
props[prop] = 'rw';
|
|
||||||
obj.__exposedProps__ = props;
|
|
||||||
}
|
|
||||||
exposeAll(MockColorPicker);
|
|
||||||
exposeAll(MockColorPickerInstance.prototype);
|
|
@ -1,236 +0,0 @@
|
|||||||
/* 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.EXPORTED_SYMBOLS = ["MockFilePicker"];
|
|
||||||
|
|
||||||
const Cc = Components.classes;
|
|
||||||
const Ci = Components.interfaces;
|
|
||||||
const Cm = Components.manager;
|
|
||||||
const Cu = Components.utils;
|
|
||||||
|
|
||||||
const CONTRACT_ID = "@mozilla.org/filepicker;1";
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
|
|
||||||
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
|
||||||
var oldClassID, oldFactory;
|
|
||||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
|
|
||||||
var newFactory = function (window) {
|
|
||||||
return {
|
|
||||||
createInstance: function(aOuter, aIID) {
|
|
||||||
if (aOuter)
|
|
||||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
|
||||||
return new MockFilePickerInstance(window).QueryInterface(aIID);
|
|
||||||
},
|
|
||||||
lockFactory: function(aLock) {
|
|
||||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
},
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.MockFilePicker = {
|
|
||||||
returnOK: Ci.nsIFilePicker.returnOK,
|
|
||||||
returnCancel: Ci.nsIFilePicker.returnCancel,
|
|
||||||
returnReplace: Ci.nsIFilePicker.returnReplace,
|
|
||||||
|
|
||||||
filterAll: Ci.nsIFilePicker.filterAll,
|
|
||||||
filterHTML: Ci.nsIFilePicker.filterHTML,
|
|
||||||
filterText: Ci.nsIFilePicker.filterText,
|
|
||||||
filterImages: Ci.nsIFilePicker.filterImages,
|
|
||||||
filterXML: Ci.nsIFilePicker.filterXML,
|
|
||||||
filterXUL: Ci.nsIFilePicker.filterXUL,
|
|
||||||
filterApps: Ci.nsIFilePicker.filterApps,
|
|
||||||
filterAllowURLs: Ci.nsIFilePicker.filterAllowURLs,
|
|
||||||
filterAudio: Ci.nsIFilePicker.filterAudio,
|
|
||||||
filterVideo: Ci.nsIFilePicker.filterVideo,
|
|
||||||
|
|
||||||
window: null,
|
|
||||||
|
|
||||||
init: function(window) {
|
|
||||||
this.window = window;
|
|
||||||
|
|
||||||
this.reset();
|
|
||||||
this.factory = newFactory(window);
|
|
||||||
if (!registrar.isCIDRegistered(newClassID)) {
|
|
||||||
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
|
|
||||||
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
|
|
||||||
registrar.unregisterFactory(oldClassID, oldFactory);
|
|
||||||
registrar.registerFactory(newClassID, "", CONTRACT_ID, this.factory);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reset: function() {
|
|
||||||
this.appendFilterCallback = null;
|
|
||||||
this.appendFiltersCallback = null;
|
|
||||||
this.displayDirectory = null;
|
|
||||||
this.filterIndex = 0;
|
|
||||||
this.mode = null;
|
|
||||||
this.returnFiles = [];
|
|
||||||
this.returnValue = null;
|
|
||||||
this.showCallback = null;
|
|
||||||
this.shown = false;
|
|
||||||
this.showing = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
cleanup: function() {
|
|
||||||
var previousFactory = this.factory;
|
|
||||||
this.reset();
|
|
||||||
this.factory = null;
|
|
||||||
if (oldFactory) {
|
|
||||||
registrar.unregisterFactory(newClassID, previousFactory);
|
|
||||||
registrar.registerFactory(oldClassID, "", CONTRACT_ID, oldFactory);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
useAnyFile: function() {
|
|
||||||
var file = FileUtils.getDir("TmpD", [], false);
|
|
||||||
file.append("testfile");
|
|
||||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
|
|
||||||
this.returnFiles = [file];
|
|
||||||
},
|
|
||||||
|
|
||||||
useBlobFile: function() {
|
|
||||||
var blob = new this.window.Blob([]);
|
|
||||||
var file = new this.window.File(blob, { name: 'helloworld.txt', type: 'plain/text' });
|
|
||||||
this.returnFiles = [file];
|
|
||||||
},
|
|
||||||
|
|
||||||
isNsIFile: function(aFile) {
|
|
||||||
let ret = false;
|
|
||||||
try {
|
|
||||||
if (aFile.QueryInterface(Ci.nsIFile))
|
|
||||||
ret = true;
|
|
||||||
} catch(e) {}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function MockFilePickerInstance(window) {
|
|
||||||
this.window = window;
|
|
||||||
};
|
|
||||||
MockFilePickerInstance.prototype = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
|
|
||||||
init: function(aParent, aTitle, aMode) {
|
|
||||||
MockFilePicker.mode = aMode;
|
|
||||||
this.filterIndex = MockFilePicker.filterIndex;
|
|
||||||
this.parent = aParent;
|
|
||||||
},
|
|
||||||
appendFilter: function(aTitle, aFilter) {
|
|
||||||
if (typeof MockFilePicker.appendFilterCallback == "function")
|
|
||||||
MockFilePicker.appendFilterCallback(this, aTitle, aFilter);
|
|
||||||
},
|
|
||||||
appendFilters: function(aFilterMask) {
|
|
||||||
if (typeof MockFilePicker.appendFiltersCallback == "function")
|
|
||||||
MockFilePicker.appendFiltersCallback(this, aFilterMask);
|
|
||||||
},
|
|
||||||
defaultString: "",
|
|
||||||
defaultExtension: "",
|
|
||||||
parent: null,
|
|
||||||
filterIndex: 0,
|
|
||||||
displayDirectory: null,
|
|
||||||
get file() {
|
|
||||||
if (MockFilePicker.returnFiles.length >= 1 &&
|
|
||||||
// window.File does not implement nsIFile
|
|
||||||
MockFilePicker.isNsIFile(MockFilePicker.returnFiles[0])) {
|
|
||||||
return MockFilePicker.returnFiles[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
get domfile() {
|
|
||||||
if (MockFilePicker.returnFiles.length >= 1) {
|
|
||||||
// window.File does not implement nsIFile
|
|
||||||
if (!MockFilePicker.isNsIFile(MockFilePicker.returnFiles[0])) {
|
|
||||||
return MockFilePicker.returnFiles[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
let utils = this.parent.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindowUtils);
|
|
||||||
return utils.wrapDOMFile(MockFilePicker.returnFiles[0]);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
get fileURL() {
|
|
||||||
if (MockFilePicker.returnFiles.length >= 1 &&
|
|
||||||
// window.File does not implement nsIFile
|
|
||||||
MockFilePicker.isNsIFile(MockFilePicker.returnFiles[0])) {
|
|
||||||
return Services.io.newFileURI(MockFilePicker.returnFiles[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
get files() {
|
|
||||||
return {
|
|
||||||
index: 0,
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
|
|
||||||
hasMoreElements: function() {
|
|
||||||
return this.index < MockFilePicker.returnFiles.length;
|
|
||||||
},
|
|
||||||
getNext: function() {
|
|
||||||
// window.File does not implement nsIFile
|
|
||||||
if (!MockFilePicker.isNsIFile(MockFilePicker.returnFiles[this.index])) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return MockFilePicker.returnFiles[this.index++];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
get domfiles() {
|
|
||||||
let utils = this.parent.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindowUtils);
|
|
||||||
return {
|
|
||||||
index: 0,
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
|
|
||||||
hasMoreElements: function() {
|
|
||||||
return this.index < MockFilePicker.returnFiles.length;
|
|
||||||
},
|
|
||||||
getNext: function() {
|
|
||||||
// window.File does not implement nsIFile
|
|
||||||
if (!MockFilePicker.isNsIFile(MockFilePicker.returnFiles[this.index])) {
|
|
||||||
return MockFilePicker.returnFiles[this.index++];
|
|
||||||
}
|
|
||||||
return utils.wrapDOMFile(MockFilePicker.returnFiles[this.index++]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
show: function() {
|
|
||||||
MockFilePicker.displayDirectory = this.displayDirectory;
|
|
||||||
MockFilePicker.shown = true;
|
|
||||||
if (typeof MockFilePicker.showCallback == "function") {
|
|
||||||
var returnValue = MockFilePicker.showCallback(this);
|
|
||||||
if (typeof returnValue != "undefined")
|
|
||||||
return returnValue;
|
|
||||||
}
|
|
||||||
return MockFilePicker.returnValue;
|
|
||||||
},
|
|
||||||
open: function(aFilePickerShownCallback) {
|
|
||||||
MockFilePicker.showing = true;
|
|
||||||
this.window.setTimeout(function() {
|
|
||||||
let result = Components.interfaces.nsIFilePicker.returnCancel;
|
|
||||||
try {
|
|
||||||
result = this.show();
|
|
||||||
} catch(ex) {
|
|
||||||
}
|
|
||||||
if (aFilePickerShownCallback) {
|
|
||||||
aFilePickerShownCallback.done(result);
|
|
||||||
}
|
|
||||||
}.bind(this), 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Expose everything to content. We call reset() here so that all of the relevant
|
|
||||||
// lazy expandos get added.
|
|
||||||
MockFilePicker.reset();
|
|
||||||
function exposeAll(obj) {
|
|
||||||
var props = {};
|
|
||||||
for (var prop in obj)
|
|
||||||
props[prop] = 'rw';
|
|
||||||
obj.__exposedProps__ = props;
|
|
||||||
}
|
|
||||||
exposeAll(MockFilePicker);
|
|
||||||
exposeAll(MockFilePickerInstance.prototype);
|
|
@ -1,97 +0,0 @@
|
|||||||
/* 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.EXPORTED_SYMBOLS = ["MockPermissionPrompt"];
|
|
||||||
|
|
||||||
const Cc = Components.classes;
|
|
||||||
const Ci = Components.interfaces;
|
|
||||||
const Cm = Components.manager;
|
|
||||||
const Cu = Components.utils;
|
|
||||||
|
|
||||||
const CONTRACT_ID = "@mozilla.org/content-permission/prompt;1";
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
|
|
||||||
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
|
||||||
var oldClassID, oldFactory;
|
|
||||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
|
|
||||||
var newFactory = {
|
|
||||||
createInstance: function(aOuter, aIID) {
|
|
||||||
if (aOuter)
|
|
||||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
|
||||||
return new MockPermissionPromptInstance().QueryInterface(aIID);
|
|
||||||
},
|
|
||||||
lockFactory: function(aLock) {
|
|
||||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
},
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
|
|
||||||
};
|
|
||||||
|
|
||||||
this.MockPermissionPrompt = {
|
|
||||||
init: function() {
|
|
||||||
this.reset();
|
|
||||||
if (!registrar.isCIDRegistered(newClassID)) {
|
|
||||||
try {
|
|
||||||
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
|
|
||||||
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
|
|
||||||
} catch (ex) {
|
|
||||||
oldClassID = "";
|
|
||||||
oldFactory = null;
|
|
||||||
dump("TEST-INFO | can't get permission prompt registered component, " +
|
|
||||||
"assuming there is none");
|
|
||||||
}
|
|
||||||
if (oldFactory) {
|
|
||||||
registrar.unregisterFactory(oldClassID, oldFactory);
|
|
||||||
}
|
|
||||||
registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reset: function() {
|
|
||||||
},
|
|
||||||
|
|
||||||
cleanup: function() {
|
|
||||||
this.reset();
|
|
||||||
if (oldFactory) {
|
|
||||||
registrar.unregisterFactory(newClassID, newFactory);
|
|
||||||
registrar.registerFactory(oldClassID, "", CONTRACT_ID, oldFactory);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function MockPermissionPromptInstance() { };
|
|
||||||
MockPermissionPromptInstance.prototype = {
|
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
|
|
||||||
|
|
||||||
promptResult: Ci.nsIPermissionManager.UNKNOWN_ACTION,
|
|
||||||
|
|
||||||
prompt: function(request) {
|
|
||||||
|
|
||||||
let perms = request.types.QueryInterface(Ci.nsIArray);
|
|
||||||
for (let idx = 0; idx < perms.length; idx++) {
|
|
||||||
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
|
|
||||||
if (Services.perms.testExactPermissionFromPrincipal(
|
|
||||||
request.principal, perm.type) != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
|
||||||
request.cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
request.allow();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Expose everything to content. We call reset() here so that all of the relevant
|
|
||||||
// lazy expandos get added.
|
|
||||||
MockPermissionPrompt.reset();
|
|
||||||
function exposeAll(obj) {
|
|
||||||
var props = {};
|
|
||||||
for (var prop in obj)
|
|
||||||
props[prop] = 'rw';
|
|
||||||
obj.__exposedProps__ = props;
|
|
||||||
}
|
|
||||||
exposeAll(MockPermissionPrompt);
|
|
||||||
exposeAll(MockPermissionPromptInstance.prototype);
|
|
@ -1,178 +0,0 @@
|
|||||||
/* 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/. */
|
|
||||||
|
|
||||||
// Based on:
|
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=549539
|
|
||||||
// https://bug549539.bugzilla.mozilla.org/attachment.cgi?id=429661
|
|
||||||
// https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_1.9.3
|
|
||||||
// http://mxr.mozilla.org/mozilla-central/source/toolkit/components/console/hudservice/HUDService.jsm#3240
|
|
||||||
// https://developer.mozilla.org/en/how_to_build_an_xpcom_component_in_javascript
|
|
||||||
|
|
||||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
|
|
||||||
const Cc = Components.classes;
|
|
||||||
const Ci = Components.interfaces;
|
|
||||||
|
|
||||||
const CHILD_SCRIPT = "chrome://specialpowers/content/specialpowers.js"
|
|
||||||
const CHILD_SCRIPT_API = "chrome://specialpowers/content/specialpowersAPI.js"
|
|
||||||
const CHILD_LOGGER_SCRIPT = "chrome://specialpowers/content/MozillaLogger.js"
|
|
||||||
|
|
||||||
|
|
||||||
// Glue to add in the observer API to this object. This allows us to share code with chrome tests
|
|
||||||
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
|
|
||||||
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
|
||||||
loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserverAPI.js");
|
|
||||||
|
|
||||||
/* XPCOM gunk */
|
|
||||||
this.SpecialPowersObserver = function SpecialPowersObserver() {
|
|
||||||
this._isFrameScriptLoaded = false;
|
|
||||||
this._mmIsGlobal = true;
|
|
||||||
this._messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
|
|
||||||
getService(Ci.nsIMessageBroadcaster);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype.classDescription = "Special powers Observer for use in testing.";
|
|
||||||
SpecialPowersObserver.prototype.classID = Components.ID("{59a52458-13e0-4d93-9d85-a637344f29a1}");
|
|
||||||
SpecialPowersObserver.prototype.contractID = "@mozilla.org/special-powers-observer;1";
|
|
||||||
SpecialPowersObserver.prototype.QueryInterface = XPCOMUtils.generateQI([Components.interfaces.nsIObserver]);
|
|
||||||
SpecialPowersObserver.prototype._xpcom_categories = [{category: "profile-after-change", service: true }];
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype.observe = function(aSubject, aTopic, aData)
|
|
||||||
{
|
|
||||||
switch (aTopic) {
|
|
||||||
case "profile-after-change":
|
|
||||||
this.init();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "chrome-document-global-created":
|
|
||||||
if (!this._isFrameScriptLoaded) {
|
|
||||||
// Register for any messages our API needs us to handle
|
|
||||||
this._messageManager.addMessageListener("SPPrefService", this);
|
|
||||||
this._messageManager.addMessageListener("SPProcessCrashService", this);
|
|
||||||
this._messageManager.addMessageListener("SPPingService", this);
|
|
||||||
this._messageManager.addMessageListener("SpecialPowers.Quit", this);
|
|
||||||
this._messageManager.addMessageListener("SpecialPowers.Focus", this);
|
|
||||||
this._messageManager.addMessageListener("SPPermissionManager", this);
|
|
||||||
this._messageManager.addMessageListener("SPWebAppService", this);
|
|
||||||
this._messageManager.addMessageListener("SPObserverService", this);
|
|
||||||
this._messageManager.addMessageListener("SPLoadChromeScript", this);
|
|
||||||
this._messageManager.addMessageListener("SPChromeScriptMessage", this);
|
|
||||||
|
|
||||||
this._messageManager.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
|
|
||||||
this._messageManager.loadFrameScript(CHILD_SCRIPT_API, true);
|
|
||||||
this._messageManager.loadFrameScript(CHILD_SCRIPT, true);
|
|
||||||
this._isFrameScriptLoaded = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "http-on-modify-request":
|
|
||||||
if (aSubject instanceof Ci.nsIChannel) {
|
|
||||||
let uri = aSubject.URI.spec;
|
|
||||||
this._sendAsyncMessage("specialpowers-http-notify-request", { uri: uri });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "xpcom-shutdown":
|
|
||||||
this.uninit();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
this._observe(aSubject, aTopic, aData);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype._sendAsyncMessage = function(msgname, msg)
|
|
||||||
{
|
|
||||||
if (this._mmIsGlobal) {
|
|
||||||
this._messageManager.broadcastAsyncMessage(msgname, msg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._messageManager.sendAsyncMessage(msgname, msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype._receiveMessage = function(aMessage) {
|
|
||||||
return this._receiveMessageAPI(aMessage);
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype.init = function(messageManager)
|
|
||||||
{
|
|
||||||
var obs = Services.obs;
|
|
||||||
obs.addObserver(this, "xpcom-shutdown", false);
|
|
||||||
obs.addObserver(this, "chrome-document-global-created", false);
|
|
||||||
obs.addObserver(this, "http-on-modify-request", false);
|
|
||||||
|
|
||||||
if (messageManager) {
|
|
||||||
this._messageManager = messageManager;
|
|
||||||
this._mmIsGlobal = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype.uninit = function()
|
|
||||||
{
|
|
||||||
var obs = Services.obs;
|
|
||||||
obs.removeObserver(this, "chrome-document-global-created");
|
|
||||||
obs.removeObserver(this, "http-on-modify-request");
|
|
||||||
this._removeProcessCrashObservers();
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype._addProcessCrashObservers = function() {
|
|
||||||
if (this._processCrashObserversRegistered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var obs = Components.classes["@mozilla.org/observer-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIObserverService);
|
|
||||||
|
|
||||||
obs.addObserver(this, "plugin-crashed", false);
|
|
||||||
obs.addObserver(this, "ipc:content-shutdown", false);
|
|
||||||
this._processCrashObserversRegistered = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersObserver.prototype._removeProcessCrashObservers = function() {
|
|
||||||
if (!this._processCrashObserversRegistered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var obs = Components.classes["@mozilla.org/observer-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIObserverService);
|
|
||||||
|
|
||||||
obs.removeObserver(this, "plugin-crashed");
|
|
||||||
obs.removeObserver(this, "ipc:content-shutdown");
|
|
||||||
this._processCrashObserversRegistered = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* messageManager callback function
|
|
||||||
* This will get requests from our API in the window and process them in chrome for it
|
|
||||||
**/
|
|
||||||
SpecialPowersObserver.prototype.receiveMessage = function(aMessage) {
|
|
||||||
switch(aMessage.name) {
|
|
||||||
case "SPPingService":
|
|
||||||
if (aMessage.json.op == "ping") {
|
|
||||||
aMessage.target
|
|
||||||
.QueryInterface(Ci.nsIFrameLoaderOwner)
|
|
||||||
.frameLoader
|
|
||||||
.messageManager
|
|
||||||
.sendAsyncMessage("SPPingService", { op: "pong" });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "SpecialPowers.Quit":
|
|
||||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
|
|
||||||
appStartup.quit(Ci.nsIAppStartup.eForceQuit);
|
|
||||||
break;
|
|
||||||
case "SpecialPowers.Focus":
|
|
||||||
aMessage.target.focus();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return this._receiveMessage(aMessage);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SpecialPowersObserver]);
|
|
@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
|
|
||||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
|
||||||
|
|
||||||
<Description about="urn:mozilla:install-manifest">
|
|
||||||
<em:id>special-powers@mozilla.org</em:id>
|
|
||||||
<em:version>2010.07.23</em:version>
|
|
||||||
<em:type>2</em:type>
|
|
||||||
|
|
||||||
<!-- Target Application this extension can install into,
|
|
||||||
with minimum and maximum supported versions. -->
|
|
||||||
<em:targetApplication>
|
|
||||||
<Description>
|
|
||||||
<em:id>toolkit@mozilla.org</em:id>
|
|
||||||
<em:minVersion>3.0</em:minVersion>
|
|
||||||
<em:maxVersion>13.0a1</em:maxVersion>
|
|
||||||
</Description>
|
|
||||||
</em:targetApplication>
|
|
||||||
|
|
||||||
<!-- Front End MetaData -->
|
|
||||||
<em:name>Special Powers</em:name>
|
|
||||||
<em:description>Special powers for use in testing.</em:description>
|
|
||||||
<em:creator>Mozilla</em:creator>
|
|
||||||
</Description>
|
|
||||||
</RDF>
|
|
@ -1,6 +1,5 @@
|
|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||||
/* globals SpecialPowers */
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -42,11 +41,7 @@ var TestReporter = function(browser, appPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendQuitRequest() {
|
function sendQuitRequest() {
|
||||||
send('/tellMeToQuit?path=' + escape(appPath), {}, function () {
|
send('/tellMeToQuit?path=' + escape(appPath), {});
|
||||||
if (window.SpecialPowers) {
|
|
||||||
SpecialPowers.quit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.now = function() {
|
this.now = function() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user