michael@0: /** michael@0: * Dispatches |handler| to |element|, as if fired in response to |event|. michael@0: */ michael@0: function send(element, event, handler) { michael@0: function unique_handler() { return handler.apply(this, arguments) } michael@0: element.addEventListener(event, unique_handler, false); michael@0: try { sendMouseEvent({ type: event }, element.id) } michael@0: finally { element.removeEventListener(event, unique_handler, false) } michael@0: } michael@0: michael@0: /** michael@0: * Because it's not nice to leave popup windows open after the tests are michael@0: * finished, we need a foolproof way to close some/all window.opened windows. michael@0: */ michael@0: (function(originalOpen) { michael@0: var wins = []; michael@0: (window.open = function() { michael@0: var win = originalOpen.apply(window, arguments); michael@0: if (win) michael@0: wins[wins.length] = win; michael@0: return win; michael@0: }).close = function(n) { michael@0: if (arguments.length < 1) michael@0: n = wins.length; michael@0: while (n --> 0) { michael@0: var win = wins.pop(); michael@0: if (win) win.close(); michael@0: else break; michael@0: } michael@0: }; michael@0: })(window.open); michael@0: michael@0: function _alter_helper(uri, fn) { michael@0: var hash_splat = uri.split("#"), michael@0: splat = hash_splat.shift().split("/"); michael@0: fn(splat); michael@0: hash_splat.unshift(splat.join("/")); michael@0: return hash_splat.join("#"); michael@0: } michael@0: michael@0: function alter_host(uri, host) { michael@0: return _alter_helper(uri, function(splat) { michael@0: splat.splice(2, 1, host); michael@0: }); michael@0: } michael@0: michael@0: function alter_file(uri, file) { michael@0: return _alter_helper(uri, function(splat) { michael@0: splat[splat.length - 1] = file; michael@0: }); michael@0: } michael@0: michael@0: (function() { michael@0: michael@0: var prefService = SpecialPowers.Cc["@mozilla.org/preferences-service;1"] michael@0: .getService(SpecialPowers.Ci.nsIPrefService), michael@0: pm = SpecialPowers.Cc["@mozilla.org/permissionmanager;1"] michael@0: .getService(SpecialPowers.Ci.nsIPermissionManager), michael@0: ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"] michael@0: .getService(SpecialPowers.Ci.nsIIOService); michael@0: michael@0: ALLOW_ACTION = pm.ALLOW_ACTION; michael@0: DENY_ACTION = pm.DENY_ACTION; michael@0: UNKNOWN_ACTION = pm.UNKNOWN_ACTION; michael@0: michael@0: /** michael@0: * This ridiculously over-engineered function makes an accessor function from michael@0: * any given preference string. Such accessors may be passed as the first michael@0: * parameter to the |hold| function defined below. michael@0: */ michael@0: makePrefAccessor = function(pref) { michael@0: var splat = pref.split('.'), michael@0: basePref = splat.pop(), michael@0: branch, kind; michael@0: michael@0: try { michael@0: branch = prefService.getBranch(splat.join('.') + '.'); michael@0: } catch (x) { michael@0: alert("Calling prefService.getBranch failed: " + michael@0: "did you forget to enable UniversalXPConnect?"); michael@0: throw x; michael@0: } michael@0: michael@0: switch (branch.getPrefType(basePref)) { michael@0: case branch.PREF_STRING: kind = "CharPref"; break; michael@0: case branch.PREF_INT: kind = "IntPref"; break; michael@0: case branch.PREF_BOOL: kind = "BoolPref"; break; michael@0: case branch.PREF_INVALID: kind = "ComplexValue"; michael@0: } michael@0: michael@0: return function(value) { michael@0: var oldValue = branch['get' + kind](basePref); michael@0: if (arguments.length > 0) michael@0: branch['set' + kind](basePref, value); michael@0: return oldValue; michael@0: }; michael@0: }; michael@0: michael@0: makePopupPrivAccessor = function(uri) { michael@0: uri = ioService.newURI(uri, null, null); michael@0: var principal = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"] michael@0: .getService(SpecialPowers.Ci.nsIScriptSecurityManager) michael@0: .getNoAppCodebasePrincipal(uri); michael@0: michael@0: return function(permission) { michael@0: var old = pm.testPermissionFromPrincipal(principal, "popup"); michael@0: if (arguments.length) { michael@0: pm.removeFromPrincipal(principal, "popup"); michael@0: pm.addFromPrincipal(principal, "popup", permission); michael@0: } michael@0: return old; michael@0: }; michael@0: }; michael@0: michael@0: })(); michael@0: michael@0: /** michael@0: * This function takes an accessor function, a new value, and a callback michael@0: * function. It assigns the new value to the accessor, saving the old value, michael@0: * then calls the callback function with the new and old values. Before michael@0: * returning, |hold| sets the accessor back to the old value, even if the michael@0: * callback function misbehaved (i.e., threw). michael@0: * michael@0: * For sanity's sake, |hold| also ensures that the accessor still has the new michael@0: * value at the time the old value is reassigned. The accessor's value might michael@0: * have changed to something entirely different during the execution of the michael@0: * callback function, but it must have changed back. michael@0: * michael@0: * Without such a mechanism it would be very difficult to verify that these michael@0: * tests leave the browser's preferences/privileges as they were originally. michael@0: */ michael@0: function hold(accessor, value, body) { michael@0: var old_value = accessor(value); michael@0: try { return body(value, old_value) } michael@0: finally { michael@0: old_value = accessor(old_value); michael@0: if (old_value !== value) michael@0: throw [accessor, value, old_value]; michael@0: } michael@0: }