diff --git a/test/browser_manifest.json b/test/browser_manifest.json
index f11c97c11..a396b01ce 100644
--- a/test/browser_manifest.json
+++ b/test/browser_manifest.json
@@ -3,5 +3,10 @@
"name":"firefox5",
"path":"/Applications/Firefox.app",
"type":"firefox"
+ },
+ {
+ "name":"firefox6",
+ "path":"/Users/sayrer/firefoxen/Aurora.app",
+ "type":"firefox"
}
]
\ No newline at end of file
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest
new file mode 100644
index 000000000..614f31c3a
--- /dev/null
+++ b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest
@@ -0,0 +1,4 @@
+content specialpowers chrome/specialpowers/content/
+component {59a52458-13e0-4d93-9d85-a637344f29a1} components/SpecialPowersObserver.js
+contract @mozilla.org/special-powers-observer;1 {59a52458-13e0-4d93-9d85-a637344f29a1}
+category profile-after-change @mozilla.org/special-powers-observer;1 @mozilla.org/special-powers-observer;1
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js
new file mode 100644
index 000000000..538b104eb
--- /dev/null
+++ b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js
@@ -0,0 +1,372 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Special Powers code
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Clint Talbert cmtalbert@gmail.com
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****/
+/* This code is loaded in every child process that is started by mochitest in
+ * order to be used as a replacement for UniversalXPConnect
+ */
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+function SpecialPowers(window) {
+ this.window = window;
+ bindDOMWindowUtils(this, window);
+ this._encounteredCrashDumpFiles = [];
+ this._unexpectedCrashDumpFiles = { };
+ this._crashDumpDir = null;
+ this._pongHandlers = [];
+ this._messageListener = this._messageReceived.bind(this);
+ addMessageListener("SPPingService", this._messageListener);
+}
+
+function bindDOMWindowUtils(sp, window) {
+ var util = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ // This bit of magic brought to you by the letters
+ // B Z, and E, S and the number 5.
+ //
+ // Take all of the properties on the nsIDOMWindowUtils-implementing
+ // object, and rebind them onto a new object with a stub that uses
+ // apply to call them from this privileged scope. This way we don't
+ // have to explicitly stub out new methods that appear on
+ // nsIDOMWindowUtils.
+ var proto = Object.getPrototypeOf(util);
+ var target = {};
+ function rebind(desc, prop) {
+ if (prop in desc && typeof(desc[prop]) == "function") {
+ var oldval = desc[prop];
+ desc[prop] = function() { return oldval.apply(util, arguments); };
+ }
+ }
+ for (var i in proto) {
+ var desc = Object.getOwnPropertyDescriptor(proto, i);
+ rebind(desc, "get");
+ rebind(desc, "set");
+ rebind(desc, "value");
+ Object.defineProperty(target, i, desc);
+ }
+ sp.DOMWindowUtils = target;
+}
+
+SpecialPowers.prototype = {
+ toString: function() { return "[SpecialPowers]"; },
+ sanityCheck: function() { return "foo"; },
+
+ // This gets filled in in the constructor.
+ DOMWindowUtils: undefined,
+
+ // Mimic the get*Pref API
+ getBoolPref: function(aPrefName) {
+ return (this._getPref(aPrefName, 'BOOL'));
+ },
+ getIntPref: function(aPrefName) {
+ return (this._getPref(aPrefName, 'INT'));
+ },
+ getCharPref: function(aPrefName) {
+ return (this._getPref(aPrefName, 'CHAR'));
+ },
+ getComplexValue: function(aPrefName, aIid) {
+ return (this._getPref(aPrefName, 'COMPLEX', aIid));
+ },
+
+ // Mimic the set*Pref API
+ setBoolPref: function(aPrefName, aValue) {
+ return (this._setPref(aPrefName, 'BOOL', aValue));
+ },
+ setIntPref: function(aPrefName, aValue) {
+ return (this._setPref(aPrefName, 'INT', aValue));
+ },
+ setCharPref: function(aPrefName, aValue) {
+ return (this._setPref(aPrefName, 'CHAR', aValue));
+ },
+ setComplexValue: function(aPrefName, aIid, aValue) {
+ return (this._setPref(aPrefName, 'COMPLEX', aValue, aIid));
+ },
+
+ // Mimic the clearUserPref API
+ clearUserPref: function(aPrefName) {
+ var msg = {'op':'clear', 'prefName': aPrefName, 'prefType': ""};
+ sendSyncMessage('SPPrefService', msg);
+ },
+
+ // Private pref functions to communicate to chrome
+ _getPref: function(aPrefName, aPrefType, aIid) {
+ var msg = {};
+ if (aIid) {
+ // Overloading prefValue to handle complex prefs
+ msg = {'op':'get', 'prefName': aPrefName, 'prefType':aPrefType, 'prefValue':[aIid]};
+ } else {
+ msg = {'op':'get', 'prefName': aPrefName,'prefType': aPrefType};
+ }
+ return(sendSyncMessage('SPPrefService', msg)[0]);
+ },
+ _setPref: function(aPrefName, aPrefType, aValue, aIid) {
+ var msg = {};
+ if (aIid) {
+ msg = {'op':'set','prefName':aPrefName, 'prefType': aPrefType, 'prefValue': [aIid,aValue]};
+ } else {
+ msg = {'op':'set', 'prefName': aPrefName, 'prefType': aPrefType, 'prefValue': aValue};
+ }
+ return(sendSyncMessage('SPPrefService', msg)[0]);
+ },
+
+ //XXX: these APIs really ought to be removed, they're not e10s-safe.
+ // (also they're pretty Firefox-specific)
+ _getTopChromeWindow: function(window) {
+ return window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow)
+ .QueryInterface(Ci.nsIDOMChromeWindow);
+ },
+ _getDocShell: function(window) {
+ return window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell);
+ },
+ _getMUDV: function(window) {
+ return this._getDocShell(window).contentViewer
+ .QueryInterface(Ci.nsIMarkupDocumentViewer);
+ },
+ _getAutoCompletePopup: function(window) {
+ return this._getTopChromeWindow(window).document
+ .getElementById("PopupAutoComplete");
+ },
+ addAutoCompletePopupEventListener: function(window, listener) {
+ this._getAutoCompletePopup(window).addEventListener("popupshowing",
+ listener,
+ false);
+ },
+ removeAutoCompletePopupEventListener: function(window, listener) {
+ this._getAutoCompletePopup(window).removeEventListener("popupshowing",
+ listener,
+ false);
+ },
+ isBackButtonEnabled: function(window) {
+ return !this._getTopChromeWindow(window).document
+ .getElementById("Browser:Back")
+ .hasAttribute("disabled");
+ },
+
+ addChromeEventListener: function(type, listener, capture, allowUntrusted) {
+ addEventListener(type, listener, capture, allowUntrusted);
+ },
+ removeChromeEventListener: function(type, listener, capture) {
+ removeEventListener(type, listener, capture);
+ },
+
+ getFullZoom: function(window) {
+ return this._getMUDV(window).fullZoom;
+ },
+ setFullZoom: function(window, zoom) {
+ this._getMUDV(window).fullZoom = zoom;
+ },
+ getTextZoom: function(window) {
+ return this._getMUDV(window).textZoom;
+ },
+ setTextZoom: function(window, zoom) {
+ this._getMUDV(window).textZoom = zoom;
+ },
+
+ createSystemXHR: function() {
+ return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+ .createInstance(Ci.nsIXMLHttpRequest);
+ },
+
+ gc: function() {
+ this.DOMWindowUtils.garbageCollect();
+ },
+
+ hasContentProcesses: function() {
+ try {
+ var rt = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
+ return rt.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+ } catch (e) {
+ return true;
+ }
+ },
+
+ registerProcessCrashObservers: function() {
+ addMessageListener("SPProcessCrashService", this._messageListener);
+ sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
+ },
+
+ _messageReceived: function(aMessage) {
+ switch (aMessage.name) {
+ case "SPProcessCrashService":
+ if (aMessage.json.type == "crash-observed") {
+ var self = this;
+ aMessage.json.dumpIDs.forEach(function(id) {
+ self._encounteredCrashDumpFiles.push(id + ".dmp");
+ self._encounteredCrashDumpFiles.push(id + ".extra");
+ });
+ }
+ break;
+
+ case "SPPingService":
+ if (aMessage.json.op == "pong") {
+ var handler = this._pongHandlers.shift();
+ if (handler) {
+ handler();
+ }
+ }
+ break;
+ }
+ return true;
+ },
+
+ removeExpectedCrashDumpFiles: function(aExpectingProcessCrash) {
+ var success = true;
+ if (aExpectingProcessCrash) {
+ var message = {
+ op: "delete-crash-dump-files",
+ filenames: this._encounteredCrashDumpFiles
+ };
+ if (!sendSyncMessage("SPProcessCrashService", message)[0]) {
+ success = false;
+ }
+ }
+ this._encounteredCrashDumpFiles.length = 0;
+ return success;
+ },
+
+ findUnexpectedCrashDumpFiles: function() {
+ var self = this;
+ var message = {
+ op: "find-crash-dump-files",
+ crashDumpFilesToIgnore: this._unexpectedCrashDumpFiles
+ };
+ var crashDumpFiles = sendSyncMessage("SPProcessCrashService", message)[0];
+ crashDumpFiles.forEach(function(aFilename) {
+ self._unexpectedCrashDumpFiles[aFilename] = true;
+ });
+ return crashDumpFiles;
+ },
+
+ executeAfterFlushingMessageQueue: function(aCallback) {
+ this._pongHandlers.push(aCallback);
+ sendAsyncMessage("SPPingService", { op: "ping" });
+ },
+
+ executeSoon: function(aFunc) {
+ var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
+ tm.mainThread.dispatch({
+ run: function() {
+ aFunc();
+ }
+ }, Ci.nsIThread.DISPATCH_NORMAL);
+ },
+
+ /* from http://mxr.mozilla.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/quit.js
+ * by Bob Clary, Jeff Walden, and Robert Sayre.
+ */
+ quitApplication: function() {
+ function canQuitApplication()
+ {
+ var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+ if (!os)
+ return true;
+
+ try {
+ var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
+ os.notifyObservers(cancelQuit, "quit-application-requested", null);
+
+ // Something aborted the quit process.
+ if (cancelQuit.data)
+ return false;
+ } catch (ex) {}
+ return true;
+ }
+
+ if (!canQuitApplication())
+ return false;
+
+ var appService = Cc['@mozilla.org/toolkit/app-startup;1'].getService(Ci.nsIAppStartup);
+ appService.quit(Ci.nsIAppStartup.eForceQuit);
+ return true;
+ }
+};
+
+// Expose everything but internal APIs (starting with underscores) to
+// web content.
+SpecialPowers.prototype.__exposedProps__ = {};
+for each (i in Object.keys(SpecialPowers.prototype).filter(function(v) {return v.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;
+
+ // Need to make sure we are called on what we care about -
+ // content windows. DOMWindowCreated is called on *all* HTMLDocuments,
+ // some of which belong to chrome windows or other special content.
+ //
+ var uri = window.document.documentURIObject;
+ if (uri.scheme === "chrome" || uri.spec.split(":")[0] == "about") {
+ return;
+ }
+
+ attachSpecialPowersToWindow(window);
+ }
+};
+
+var specialpowersmanager = new SpecialPowersManager();
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/components/SpecialPowersObserver.js b/test/resources/firefox/extensions/special-powers@mozilla.org/components/SpecialPowersObserver.js
new file mode 120000
index 000000000..6f90832fb
--- /dev/null
+++ b/test/resources/firefox/extensions/special-powers@mozilla.org/components/SpecialPowersObserver.js
@@ -0,0 +1 @@
+/Users/sayrer/dev/mozilla-central/testing/mochitest/specialpowers/components/SpecialPowersObserver.js
\ No newline at end of file
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/install.rdf b/test/resources/firefox/extensions/special-powers@mozilla.org/install.rdf
new file mode 100644
index 000000000..db8de988e
--- /dev/null
+++ b/test/resources/firefox/extensions/special-powers@mozilla.org/install.rdf
@@ -0,0 +1,26 @@
+
+
+