mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1001074 - Uplift Add-on SDK to Firefox r=me
This commit is contained in:
parent
b4f08e51ba
commit
a0ae90c65d
@ -81,8 +81,11 @@ exports.set = function(aData, aDataType) {
|
||||
options.datatype = dataURL.mimeType;
|
||||
options.data = dataURL.data;
|
||||
}
|
||||
catch (e if e.name === "URIError") {
|
||||
// Not a valid Data URL
|
||||
catch (e) {
|
||||
// Ignore invalid URIs
|
||||
if (e.name !== "URIError") {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
const self = require("../self");
|
||||
const prefs = require("../preferences/service");
|
||||
const { merge } = require("../util/object");
|
||||
const { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm");
|
||||
const { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||
|
||||
const DEFAULT_LOG_LEVEL = "error";
|
||||
const ADDON_LOG_LEVEL_PREF = "extensions." + self.id + ".sdk.console.logLevel";
|
||||
@ -44,12 +44,13 @@ let branch = Cc["@mozilla.org/preferences-service;1"].
|
||||
branch.addObserver(ADDON_LOG_LEVEL_PREF, logLevelObserver, true);
|
||||
branch.addObserver(SDK_LOG_LEVEL_PREF, logLevelObserver, true);
|
||||
|
||||
function PlainTextConsole(print) {
|
||||
function PlainTextConsole(print, innerID) {
|
||||
|
||||
let consoleOptions = {
|
||||
prefix: self.name + ": ",
|
||||
maxLogLevel: logLevel,
|
||||
dump: print
|
||||
dump: print,
|
||||
innerID: innerID
|
||||
};
|
||||
let console = new ConsoleAPI(consoleOptions);
|
||||
|
||||
|
@ -19,6 +19,7 @@ const { sandbox, evaluate, load } = require('../loader/sandbox');
|
||||
const { merge } = require('../util/object');
|
||||
const { getTabForContentWindow } = require('../tabs/utils');
|
||||
const { getInnerId } = require('../window/utils');
|
||||
const { PlainTextConsole } = require('../console/plain-text');
|
||||
|
||||
// WeakMap of sandboxes so we can access private values
|
||||
const sandboxes = new WeakMap();
|
||||
@ -197,8 +198,10 @@ const WorkerSandbox = Class({
|
||||
// script
|
||||
merge(model, result);
|
||||
|
||||
let console = new PlainTextConsole(null, getInnerId(window));
|
||||
|
||||
// Handle messages send by this script:
|
||||
setListeners(this);
|
||||
setListeners(this, console);
|
||||
|
||||
// Inject `addon` global into target document if document is trusted,
|
||||
// `addon` in document is equivalent to `self` in content script.
|
||||
@ -304,7 +307,7 @@ function importScripts (workerSandbox, ...urls) {
|
||||
}
|
||||
}
|
||||
|
||||
function setListeners (workerSandbox) {
|
||||
function setListeners (workerSandbox, console) {
|
||||
let { worker } = modelFor(workerSandbox);
|
||||
// console.xxx calls
|
||||
workerSandbox.on('console', function consoleListener (kind, ...args) {
|
||||
|
@ -1,243 +1,29 @@
|
||||
;(function(id, factory) { // Module boilerplate :(
|
||||
if (typeof(define) === 'function') { // RequireJS
|
||||
define(factory);
|
||||
} else if (typeof(require) === 'function') { // CommonJS
|
||||
factory.call(this, require, exports, module);
|
||||
} else if (String(this).indexOf('BackstagePass') >= 0) { // JSM
|
||||
this[factory.name] = {};
|
||||
try {
|
||||
this.console = this['Components'].utils
|
||||
.import('resource://gre/modules/devtools/Console.jsm', {}).console;
|
||||
}
|
||||
catch (ex) {
|
||||
// Avoid failures on different toolkit configurations.
|
||||
}
|
||||
factory(function require(uri) {
|
||||
var imports = {};
|
||||
this['Components'].utils.import(uri, imports);
|
||||
return imports;
|
||||
}, this[factory.name], { uri: __URI__, id: id });
|
||||
this.EXPORTED_SYMBOLS = [factory.name];
|
||||
} else if (~String(this).indexOf('Sandbox')) { // Sandbox
|
||||
factory(function require(uri) {}, this, { id: id });
|
||||
} else { // Browser or alike
|
||||
var globals = this;
|
||||
factory(function require(id) {
|
||||
return globals[id];
|
||||
}, (globals[id] = {}), { uri: document.location.href + '#' + id, id: id });
|
||||
}
|
||||
}).call(this, 'promise/core', function Promise(require, exports, module) {
|
||||
/* 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';
|
||||
|
||||
/*
|
||||
* Uses `Promise.jsm` as a core implementation, with additional sugar
|
||||
* from previous implementation, with inspiration from `Q` and `when`
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm
|
||||
* https://github.com/cujojs/when
|
||||
* https://github.com/kriskowal/q
|
||||
*/
|
||||
const PROMISE_URI = 'resource://gre/modules/Promise.jsm';
|
||||
|
||||
getEnvironment.call(this, function ({ require, exports, module, Cu }) {
|
||||
|
||||
const { defer, resolve, all, reject, race } = Cu.import(PROMISE_URI, {}).Promise;
|
||||
|
||||
module.metadata = {
|
||||
"stability": "unstable"
|
||||
'stability': 'unstable'
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal utility: Wraps given `value` into simplified promise, successfully
|
||||
* fulfilled to a given `value`. Note the result is not a complete promise
|
||||
* implementation, as its method `then` does not returns anything.
|
||||
*/
|
||||
function fulfilled(value) {
|
||||
return { then: function then(fulfill) { fulfill(value); } };
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal utility: Wraps given input into simplified promise, pre-rejected
|
||||
* with a given `reason`. Note the result is not a complete promise
|
||||
* implementation, as its method `then` does not returns anything.
|
||||
*/
|
||||
function rejected(reason) {
|
||||
return { then: function then(fulfill, reject) { reject(reason); } };
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal utility: Returns `true` if given `value` is a promise. Value is
|
||||
* assumed to be a promise if it implements method `then`.
|
||||
*/
|
||||
function isPromise(value) {
|
||||
return value && typeof(value.then) === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates deferred object containing fresh promise & methods to either resolve
|
||||
* or reject it. The result is an object with the following properties:
|
||||
* - `promise` Eventual value representation implementing CommonJS [Promises/A]
|
||||
* (http://wiki.commonjs.org/wiki/Promises/A) API.
|
||||
* - `resolve` Single shot function that resolves enclosed `promise` with a
|
||||
* given `value`.
|
||||
* - `reject` Single shot function that rejects enclosed `promise` with a given
|
||||
* `reason`.
|
||||
*
|
||||
* An optional `prototype` argument is used as a prototype of the returned
|
||||
* `promise` allowing one to implement additional API. If prototype is not
|
||||
* passed then it falls back to `Object.prototype`.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* function fetchURI(uri, type) {
|
||||
* var deferred = defer();
|
||||
* var request = new XMLHttpRequest();
|
||||
* request.open("GET", uri, true);
|
||||
* request.responseType = type;
|
||||
* request.onload = function onload() {
|
||||
* deferred.resolve(request.response);
|
||||
* }
|
||||
* request.onerror = function(event) {
|
||||
* deferred.reject(event);
|
||||
* }
|
||||
* request.send();
|
||||
*
|
||||
* return deferred.promise;
|
||||
* }
|
||||
*/
|
||||
function defer(prototype) {
|
||||
// Define FIFO queue of observer pairs. Once promise is resolved & all queued
|
||||
// observers are forwarded to `result` and variable is set to `null`.
|
||||
var observers = [];
|
||||
|
||||
// Promise `result`, which will be assigned a resolution value once promise
|
||||
// is resolved. Note that result will always be assigned promise (or alike)
|
||||
// object to take care of propagation through promise chains. If result is
|
||||
// `null` promise is not resolved yet.
|
||||
var result = null;
|
||||
|
||||
prototype = (prototype || prototype === null) ? prototype : Object.prototype;
|
||||
|
||||
// Create an object implementing promise API.
|
||||
var promise = Object.create(prototype, {
|
||||
then: { value: function then(onFulfill, onError) {
|
||||
var deferred = defer(prototype);
|
||||
|
||||
function resolve(value) {
|
||||
// If `onFulfill` handler is provided resolve `deferred.promise` with
|
||||
// result of invoking it with a resolution value. If handler is not
|
||||
// provided propagate value through.
|
||||
try {
|
||||
deferred.resolve(onFulfill ? onFulfill(value) : value);
|
||||
}
|
||||
// `onFulfill` may throw exception in which case resulting promise
|
||||
// is rejected with thrown exception.
|
||||
catch(error) {
|
||||
if (exports._reportErrors && typeof(console) === 'object')
|
||||
console.error(error);
|
||||
// Note: Following is equivalent of `deferred.reject(error)`,
|
||||
// we use this shortcut to reduce a stack.
|
||||
deferred.resolve(rejected(error));
|
||||
}
|
||||
}
|
||||
|
||||
function reject(reason) {
|
||||
try {
|
||||
if (onError) deferred.resolve(onError(reason));
|
||||
else deferred.resolve(rejected(reason));
|
||||
}
|
||||
catch(error) {
|
||||
if (exports._reportErrors && typeof(console) === 'object')
|
||||
console.error(error);
|
||||
deferred.resolve(rejected(error));
|
||||
}
|
||||
}
|
||||
|
||||
// If enclosed promise (`this.promise`) observers queue is still alive
|
||||
// enqueue a new observer pair into it. Note that this does not
|
||||
// necessary means that promise is pending, it may already be resolved,
|
||||
// but we still have to queue observers to guarantee an order of
|
||||
// propagation.
|
||||
if (observers) {
|
||||
observers.push({ resolve: resolve, reject: reject });
|
||||
}
|
||||
// Otherwise just forward observer pair right to a `result` promise.
|
||||
else {
|
||||
result.then(resolve, reject);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}}
|
||||
})
|
||||
|
||||
var deferred = {
|
||||
promise: promise,
|
||||
/**
|
||||
* Resolves associated `promise` to a given `value`, unless it's already
|
||||
* resolved or rejected. Note that resolved promise is not necessary a
|
||||
* successfully fulfilled. Promise may be resolved with a promise `value`
|
||||
* in which case `value` promise's fulfillment / rejection will propagate
|
||||
* up to a promise resolved with `value`.
|
||||
*/
|
||||
resolve: function resolve(value) {
|
||||
if (!result) {
|
||||
// Store resolution `value` in a `result` as a promise, so that all
|
||||
// the subsequent handlers can be simply forwarded to it. Since
|
||||
// `result` will be a promise all the value / error propagation will
|
||||
// be uniformly taken care of.
|
||||
result = isPromise(value) ? value : fulfilled(value);
|
||||
|
||||
// Forward already registered observers to a `result` promise in the
|
||||
// order they were registered. Note that we intentionally dequeue
|
||||
// observer at a time until queue is exhausted. This makes sure that
|
||||
// handlers registered as side effect of observer forwarding are
|
||||
// queued instead of being invoked immediately, guaranteeing FIFO
|
||||
// order.
|
||||
while (observers.length) {
|
||||
var observer = observers.shift();
|
||||
result.then(observer.resolve, observer.reject);
|
||||
}
|
||||
|
||||
// Once `observers` queue is exhausted we `null`-ify it, so that
|
||||
// new handlers are forwarded straight to the `result`.
|
||||
observers = null;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Rejects associated `promise` with a given `reason`, unless it's already
|
||||
* resolved / rejected. This is just a (better performing) convenience
|
||||
* shortcut for `deferred.resolve(reject(reason))`.
|
||||
*/
|
||||
reject: function reject(reason) {
|
||||
// Note that if promise is resolved that does not necessary means that it
|
||||
// is successfully fulfilled. Resolution value may be a promise in which
|
||||
// case its result propagates. In other words if promise `a` is resolved
|
||||
// with promise `b`, `a` is either fulfilled or rejected depending
|
||||
// on weather `b` is fulfilled or rejected. Here `deferred.promise` is
|
||||
// resolved with a promise pre-rejected with a given `reason`, there for
|
||||
// `deferred.promise` is rejected with a given `reason`. This may feel
|
||||
// little awkward first, but doing it this way greatly simplifies
|
||||
// propagation through promise chains.
|
||||
deferred.resolve(rejected(reason));
|
||||
}
|
||||
};
|
||||
|
||||
return deferred;
|
||||
}
|
||||
exports.defer = defer;
|
||||
|
||||
/**
|
||||
* Returns a promise resolved to a given `value`. Optionally a second
|
||||
* `prototype` argument may be provided to be used as a prototype for the
|
||||
* returned promise.
|
||||
*/
|
||||
function resolve(value, prototype) {
|
||||
var deferred = defer(prototype);
|
||||
deferred.resolve(value);
|
||||
return deferred.promise;
|
||||
}
|
||||
exports.resolve = resolve;
|
||||
|
||||
/**
|
||||
* Returns a promise rejected with a given `reason`. Optionally a second
|
||||
* `prototype` argument may be provided to be used as a prototype for the
|
||||
* returned promise.
|
||||
*/
|
||||
function reject(reason, prototype) {
|
||||
var deferred = defer(prototype);
|
||||
deferred.reject(reason);
|
||||
return deferred.promise;
|
||||
}
|
||||
exports.reject = reject;
|
||||
|
||||
var promised = (function() {
|
||||
let promised = (function() {
|
||||
// Note: Define shortcuts and utility functions here in order to avoid
|
||||
// slower property accesses and unnecessary closure creations on each
|
||||
// call of this popular function.
|
||||
@ -247,15 +33,14 @@ var promised = (function() {
|
||||
|
||||
// Utility function that does following:
|
||||
// execute([ f, self, args...]) => f.apply(self, args)
|
||||
function execute(args) { return call.apply(call, args) }
|
||||
function execute (args) call.apply(call, args)
|
||||
|
||||
// Utility function that takes promise of `a` array and maybe promise `b`
|
||||
// as arguments and returns promise for `a.concat(b)`.
|
||||
function promisedConcat(promises, unknown) {
|
||||
return promises.then(function(values) {
|
||||
return resolve(unknown).then(function(value) {
|
||||
return values.concat([ value ]);
|
||||
});
|
||||
return promises.then(function (values) {
|
||||
return resolve(unknown)
|
||||
.then(function (value) values.concat([value]));
|
||||
});
|
||||
}
|
||||
|
||||
@ -280,11 +65,53 @@ var promised = (function() {
|
||||
// finally map that to promise of `f.apply(this, args...)`
|
||||
then(execute);
|
||||
};
|
||||
}
|
||||
};
|
||||
})();
|
||||
exports.promised = promised;
|
||||
|
||||
var all = promised(Array);
|
||||
exports.promised = promised;
|
||||
exports.all = all;
|
||||
exports.defer = defer;
|
||||
exports.resolve = resolve;
|
||||
exports.reject = reject;
|
||||
exports.race = race;
|
||||
exports.Promise = Promise;
|
||||
|
||||
});
|
||||
|
||||
function getEnvironment (callback) {
|
||||
let Cu, _exports, _module, _require;
|
||||
|
||||
// CommonJS / SDK
|
||||
if (typeof(require) === 'function') {
|
||||
Cu = require('chrome').Cu;
|
||||
_exports = exports;
|
||||
_module = module;
|
||||
_require = require;
|
||||
}
|
||||
// JSM
|
||||
else if (String(this).indexOf('BackstagePass') >= 0) {
|
||||
Cu = this['Components'].utils;
|
||||
_exports = this.Promise = {};
|
||||
_module = { uri: __URI__, id: 'promise/core' };
|
||||
_require = uri => {
|
||||
let imports = {};
|
||||
Cu.import(uri, imports);
|
||||
return imports;
|
||||
};
|
||||
this.EXPORTED_SYMBOLS = ['Promise'];
|
||||
// mozIJSSubScriptLoader.loadSubscript
|
||||
} else if (~String(this).indexOf('Sandbox')) {
|
||||
Cu = this['Components'].utils;
|
||||
_exports = this;
|
||||
_module = { id: 'promise/core' };
|
||||
_require = uri => {};
|
||||
}
|
||||
|
||||
callback({
|
||||
Cu: Cu,
|
||||
exports: _exports,
|
||||
module: _module,
|
||||
require: _require
|
||||
});
|
||||
}
|
||||
|
||||
|
25
addon-sdk/source/lib/sdk/model/core.js
Normal file
25
addon-sdk/source/lib/sdk/model/core.js
Normal file
@ -0,0 +1,25 @@
|
||||
/* 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";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "unstable"
|
||||
};
|
||||
|
||||
const { dispatcher } = require("../util/dispatcher");
|
||||
|
||||
|
||||
// Define `modelFor` accessor function that can be implemented
|
||||
// for different types of views. Since view's we'll be dealing
|
||||
// with types that don't really play well with `instanceof`
|
||||
// operator we're gonig to use `dispatcher` that is slight
|
||||
// extension over polymorphic dispatch provided by method.
|
||||
// This allows models to extend implementations of this by
|
||||
// providing predicates:
|
||||
//
|
||||
// modelFor.when($ => $ && $.nodeName === "tab", findTabById($.id))
|
||||
const modelFor = dispatcher("modelFor");
|
||||
exports.modelFor = modelFor;
|
@ -15,27 +15,24 @@ const { merge } = require("../util/object");
|
||||
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||
|
||||
/**
|
||||
* Open a channel synchronously for the URI given, with an optional charset, and
|
||||
* returns a resolved promise if succeed; rejected promise otherwise.
|
||||
* Reads a URI and returns a promise.
|
||||
*
|
||||
* @param uri {string} The URI to read
|
||||
* @param [options] {object} This parameter can have any or all of the following
|
||||
* fields: `charset`. By default the `charset` is set to 'UTF-8'.
|
||||
*
|
||||
* @returns {promise} The promise that will be resolved with the content of the
|
||||
* URL given.
|
||||
*
|
||||
* @example
|
||||
* let promise = readURI('resource://gre/modules/NetUtil.jsm', {
|
||||
* charset: 'US-ASCII'
|
||||
* });
|
||||
*/
|
||||
function readSync(uri, charset) {
|
||||
let { promise, resolve, reject } = defer();
|
||||
function readURI(uri, options) {
|
||||
options = options || {};
|
||||
let charset = options.charset || 'UTF-8';
|
||||
|
||||
try {
|
||||
resolve(readURISync(uri, charset));
|
||||
}
|
||||
catch (e) {
|
||||
reject("Failed to read: '" + uri + "' (Error Code: " + e.result + ")");
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a channel synchronously for the URI given, with an optional charset, and
|
||||
* returns a promise.
|
||||
*/
|
||||
function readAsync(uri, charset) {
|
||||
let channel = NetUtil.newChannel(uri, charset, null);
|
||||
|
||||
let { promise, resolve, reject } = defer();
|
||||
@ -59,34 +56,6 @@ function readAsync(uri, charset) {
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a URI and returns a promise. If the `sync` option is set to `true`, the
|
||||
* promise will be resolved synchronously.
|
||||
*
|
||||
* @param uri {string} The URI to read
|
||||
* @param [options] {object} This parameter can have any or all of the following
|
||||
* fields: `sync`, `charset`. By default the `charset` is set to 'UTF-8'.
|
||||
*
|
||||
* @returns {promise} The promise that will be resolved with the content of the
|
||||
* URL given.
|
||||
*
|
||||
* @example
|
||||
* let promise = readURI('resource://gre/modules/NetUtil.jsm', {
|
||||
* sync: true,
|
||||
* charset: 'US-ASCII'
|
||||
});
|
||||
*/
|
||||
function readURI(uri, options) {
|
||||
options = merge({
|
||||
charset: "UTF-8",
|
||||
sync: false
|
||||
}, options);
|
||||
|
||||
return options.sync
|
||||
? readSync(uri, options.charset)
|
||||
: readAsync(uri, options.charset);
|
||||
}
|
||||
|
||||
exports.readURI = readURI;
|
||||
|
||||
/**
|
||||
|
@ -45,15 +45,16 @@ exports.notify = function notifications_notify(options) {
|
||||
try {
|
||||
notifyWithOpts(notify);
|
||||
}
|
||||
catch (err if err instanceof Ci.nsIException &&
|
||||
err.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
|
||||
console.warn("The notification icon named by " + valOpts.iconURL +
|
||||
" does not exist. A default icon will be used instead.");
|
||||
delete valOpts.iconURL;
|
||||
notifyWithOpts(notify);
|
||||
}
|
||||
catch (err) {
|
||||
notifyWithOpts(notifyUsingConsole);
|
||||
if (err instanceof Ci.nsIException && err.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
|
||||
console.warn("The notification icon named by " + valOpts.iconURL +
|
||||
" does not exist. A default icon will be used instead.");
|
||||
delete valOpts.iconURL;
|
||||
notifyWithOpts(notify);
|
||||
}
|
||||
else {
|
||||
notifyWithOpts(notifyUsingConsole);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -367,11 +367,16 @@ function style(panel) {
|
||||
document.getAnonymousElementByAttribute(panel, "class",
|
||||
"panel-inner-arrowcontent");
|
||||
|
||||
let color = window.getComputedStyle(node).getPropertyValue("color");
|
||||
let { color, fontFamily, fontSize, fontWeight } = window.getComputedStyle(node);
|
||||
|
||||
let style = contentDocument.createElement("style");
|
||||
style.id = "sdk-panel-style";
|
||||
style.textContent = "body { color: " + color + "; }";
|
||||
style.textContent = "body { " +
|
||||
"color: " + color + ";" +
|
||||
"font-family: " + fontFamily + ";" +
|
||||
"font-weight: " + fontWeight + ";" +
|
||||
"font-size: " + fontSize + ";" +
|
||||
"}";
|
||||
|
||||
let container = contentDocument.head ? contentDocument.head :
|
||||
contentDocument.documentElement;
|
||||
|
@ -49,8 +49,9 @@ exports.TreeNode = TreeNode;
|
||||
|
||||
/*
|
||||
* Descends down from `node` applying `fn` to each in order.
|
||||
* Can be asynchronous if `fn` returns a promise. `fn` is passed
|
||||
* one argument, the current node, `curr`
|
||||
* `fn` can return values or promises -- if promise returned,
|
||||
* children are not processed until resolved. `fn` is passed
|
||||
* one argument, the current node, `curr`.
|
||||
*/
|
||||
function walk (curr, fn) {
|
||||
return promised(fn)(curr).then(val => {
|
||||
|
@ -137,7 +137,8 @@ exports.isSet = isSet;
|
||||
function reset(name) {
|
||||
try {
|
||||
prefSvc.clearUserPref(name);
|
||||
} catch (e if e.result == Cr.NS_ERROR_UNEXPECTED) {
|
||||
}
|
||||
catch (e) {
|
||||
// The pref service throws NS_ERROR_UNEXPECTED when the caller tries
|
||||
// to reset a pref that doesn't exist or is already set to its default
|
||||
// value. This interface fails silently in those cases, so callers
|
||||
@ -145,6 +146,9 @@ function reset(name) {
|
||||
// resetting first or trap exceptions after the fact. It passes through
|
||||
// other exceptions, however, so callers know about them, since we don't
|
||||
// know what other exceptions might be thrown and what they might mean.
|
||||
if (e.result != Cr.NS_ERROR_UNEXPECTED) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.reset = reset;
|
||||
|
@ -8,13 +8,16 @@ module.metadata = {
|
||||
"stability": "stable"
|
||||
};
|
||||
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const file = require("./io/file");
|
||||
const prefs = require("./preferences/service");
|
||||
const jpSelf = require("./self");
|
||||
const timer = require("./timers");
|
||||
const unload = require("./system/unload");
|
||||
const { emit, on, off } = require("./event/core");
|
||||
const { defer } = require('./core/promise');
|
||||
|
||||
const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
|
||||
const WRITE_PERIOD_PREF = "extensions.addon-sdk.simple-storage.writePeriod";
|
||||
const WRITE_PERIOD_DEFAULT = 300000; // 5 minutes
|
||||
@ -35,6 +38,57 @@ Object.defineProperties(exports, {
|
||||
}
|
||||
});
|
||||
|
||||
function getHash(data) {
|
||||
let { promise, resolve } = defer();
|
||||
|
||||
let crypto = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
crypto.init(crypto.MD5);
|
||||
|
||||
let listener = {
|
||||
onStartRequest: function() { },
|
||||
|
||||
onDataAvailable: function(request, context, inputStream, offset, count) {
|
||||
crypto.updateFromStream(inputStream, count);
|
||||
},
|
||||
|
||||
onStopRequest: function(request, context, status) {
|
||||
resolve(crypto.finish(false));
|
||||
}
|
||||
};
|
||||
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
let stream = converter.convertToInputStream(data);
|
||||
let pump = Cc["@mozilla.org/network/input-stream-pump;1"].
|
||||
createInstance(Ci.nsIInputStreamPump);
|
||||
pump.init(stream, -1, -1, 0, 0, true);
|
||||
pump.asyncRead(listener, null);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function writeData(filename, data) {
|
||||
let { promise, resolve, reject } = defer();
|
||||
|
||||
let stream = file.open(filename, "w");
|
||||
try {
|
||||
stream.writeAsync(data, err => {
|
||||
if (err)
|
||||
reject(err);
|
||||
else
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
// writeAsync closes the stream after it's done, so only close on error.
|
||||
stream.close();
|
||||
reject(err);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
// A generic JSON store backed by a file on disk. This should be isolated
|
||||
// enough to move to its own module if need be...
|
||||
function JsonStore(options) {
|
||||
@ -43,11 +97,9 @@ function JsonStore(options) {
|
||||
this.writePeriod = options.writePeriod;
|
||||
this.onOverQuota = options.onOverQuota;
|
||||
this.onWrite = options.onWrite;
|
||||
|
||||
this.hash = null;
|
||||
unload.ensure(this);
|
||||
|
||||
this.writeTimer = timer.setInterval(this.write.bind(this),
|
||||
this.writePeriod);
|
||||
this.startTimer();
|
||||
}
|
||||
|
||||
JsonStore.prototype = {
|
||||
@ -81,11 +133,18 @@ JsonStore.prototype = {
|
||||
undefined;
|
||||
},
|
||||
|
||||
startTimer: function JsonStore_startTimer() {
|
||||
timer.setTimeout(() => {
|
||||
this.write().then(this.startTimer.bind(this));
|
||||
}, this.writePeriod);
|
||||
},
|
||||
|
||||
// Removes the backing file and all empty subdirectories.
|
||||
purge: function JsonStore_purge() {
|
||||
try {
|
||||
// This'll throw if the file doesn't exist.
|
||||
file.remove(this.filename);
|
||||
this.hash = null;
|
||||
let parentPath = this.filename;
|
||||
do {
|
||||
parentPath = file.dirname(parentPath);
|
||||
@ -105,31 +164,25 @@ JsonStore.prototype = {
|
||||
// errors cause tests to fail. Supporting "known" errors in the test
|
||||
// harness appears to be non-trivial. Maybe later.
|
||||
this.root = JSON.parse(str);
|
||||
let self = this;
|
||||
getHash(str).then(hash => this.hash = hash);
|
||||
}
|
||||
catch (err) {
|
||||
this.root = {};
|
||||
this.hash = null;
|
||||
}
|
||||
},
|
||||
|
||||
// If the store is under quota, writes the root to the backing file.
|
||||
// Otherwise quota observers are notified and nothing is written.
|
||||
write: function JsonStore_write() {
|
||||
if (this.quotaUsage > 1)
|
||||
this.onOverQuota(this);
|
||||
else
|
||||
this._write();
|
||||
},
|
||||
|
||||
// Cleans up on unload. If unloading because of uninstall, the store is
|
||||
// purged; otherwise it's written.
|
||||
unload: function JsonStore_unload(reason) {
|
||||
timer.clearInterval(this.writeTimer);
|
||||
timer.clearTimeout(this.writeTimer);
|
||||
this.writeTimer = null;
|
||||
|
||||
if (reason === "uninstall")
|
||||
this.purge();
|
||||
else
|
||||
this._write();
|
||||
this.write();
|
||||
},
|
||||
|
||||
// True if the root is an empty object.
|
||||
@ -148,32 +201,40 @@ JsonStore.prototype = {
|
||||
// Writes the root to the backing file, notifying write observers when
|
||||
// complete. If the store is over quota or if it's empty and the store has
|
||||
// never been written, nothing is written and write observers aren't notified.
|
||||
_write: function JsonStore__write() {
|
||||
write: Task.async(function JsonStore_write() {
|
||||
// Don't write if the root is uninitialized or if the store is empty and the
|
||||
// backing file doesn't yet exist.
|
||||
if (!this.isRootInited || (this._isEmpty && !file.exists(this.filename)))
|
||||
return;
|
||||
|
||||
let data = JSON.stringify(this.root);
|
||||
|
||||
// If the store is over quota, don't write. The current under-quota state
|
||||
// should persist.
|
||||
if (this.quotaUsage > 1)
|
||||
if ((this.quota > 0) && (data.length > this.quota)) {
|
||||
this.onOverQuota(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Hash the data to compare it to any previously written data
|
||||
let hash = yield getHash(data);
|
||||
|
||||
if (hash == this.hash)
|
||||
return;
|
||||
|
||||
// Finally, write.
|
||||
let stream = file.open(this.filename, "w");
|
||||
try {
|
||||
stream.writeAsync(JSON.stringify(this.root), function writeAsync(err) {
|
||||
if (err)
|
||||
console.error("Error writing simple storage file: " + this.filename);
|
||||
else if (this.onWrite)
|
||||
this.onWrite(this);
|
||||
}.bind(this));
|
||||
yield writeData(this.filename, data);
|
||||
|
||||
this.hash = hash;
|
||||
if (this.onWrite)
|
||||
this.onWrite(this);
|
||||
}
|
||||
catch (err) {
|
||||
// writeAsync closes the stream after it's done, so only close on error.
|
||||
stream.close();
|
||||
console.error("Error writing simple storage file: " + this.filename);
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,10 +1,37 @@
|
||||
/* 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';
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
'stability': 'stable'
|
||||
"stability": "unstable",
|
||||
"engines": {
|
||||
"Firefox": "*",
|
||||
"Fennec": "*"
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = require('./tabs/tabs');
|
||||
const { modelFor } = require("./model/core");
|
||||
const { viewFor } = require("./view/core");
|
||||
const { isTab } = require("./tabs/utils");
|
||||
|
||||
|
||||
if (require("./system/xul-app").is("Fennec")) {
|
||||
module.exports = require("./windows/tabs-fennec").tabs;
|
||||
}
|
||||
else {
|
||||
module.exports = require("./tabs/tabs-firefox");
|
||||
}
|
||||
|
||||
const tabs = module.exports;
|
||||
|
||||
// Implement `modelFor` function for the Tab instances.
|
||||
// Finds a right model by iterating over all tab models
|
||||
// and finding one that wraps given `view`.
|
||||
modelFor.when(isTab, view => {
|
||||
for (let model of tabs) {
|
||||
if (viewFor(model) === view)
|
||||
return model;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
@ -1,19 +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';
|
||||
|
||||
module.metadata = {
|
||||
'stability': 'unstable',
|
||||
'engines': {
|
||||
'Firefox': '*',
|
||||
'Fennec': '*'
|
||||
}
|
||||
};
|
||||
|
||||
if (require('../system/xul-app').name == 'Fennec') {
|
||||
module.exports = require('../windows/tabs-fennec').tabs;
|
||||
}
|
||||
else {
|
||||
module.exports = require('./tabs-firefox');
|
||||
}
|
@ -20,6 +20,31 @@ const { isGlobalPBSupported } = require('../private-browsing/utils');
|
||||
// Bug 834961: ignore private windows when they are not supported
|
||||
function getWindows() windows(null, { includePrivate: isPrivateBrowsingSupported || isGlobalPBSupported });
|
||||
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
// Define predicate functions that can be used to detech weather
|
||||
// we deal with fennec tabs or firefox tabs.
|
||||
|
||||
// Predicate to detect whether tab is XUL "Tab" node.
|
||||
const isXULTab = tab =>
|
||||
tab instanceof Ci.nsIDOMNode &&
|
||||
tab.nodeName === "tab" &&
|
||||
tab.namespaceURI === XUL_NS;
|
||||
exports.isXULTab = isXULTab;
|
||||
|
||||
// Predicate to detecet whether given tab is a fettec tab.
|
||||
// Unfortunately we have to guess via duck typinng of:
|
||||
// http://mxr.mozilla.org/mozilla-central/source/mobile/android/chrome/content/browser.js#2583
|
||||
const isFennecTab = tab =>
|
||||
tab &&
|
||||
tab.QueryInterface &&
|
||||
Ci.nsIBrowserTab &&
|
||||
tab.QueryInterface(Ci.nsIBrowserTab) === tab;
|
||||
exports.isFennecTab = isFennecTab;
|
||||
|
||||
const isTab = x => isXULTab(x) || isFennecTab(x);
|
||||
exports.isTab = isTab;
|
||||
|
||||
function activateTab(tab, window) {
|
||||
let gBrowser = getTabBrowserForTab(tab);
|
||||
|
||||
|
@ -8,7 +8,7 @@ const { resolveURI, Require,
|
||||
unload, override, descriptor } = require('../../toolkit/loader');
|
||||
const { ensure } = require('../system/unload');
|
||||
const addonWindow = require('../addon/window');
|
||||
const { PlainTextConsole } = require("sdk/console/plain-text");
|
||||
const { PlainTextConsole } = require('sdk/console/plain-text');
|
||||
|
||||
let defaultGlobals = override(require('../system/globals'), {
|
||||
console: console
|
||||
@ -43,33 +43,43 @@ function CustomLoader(module, globals, packaging, overrides={}) {
|
||||
};
|
||||
exports.Loader = CustomLoader;
|
||||
|
||||
function HookedPlainTextConsole(hook, print, innerID) {
|
||||
this.log = hook.bind(null, "log", innerID);
|
||||
this.info = hook.bind(null, "info", innerID);
|
||||
this.warn = hook.bind(null, "warn", innerID);
|
||||
this.error = hook.bind(null, "error", innerID);
|
||||
this.debug = hook.bind(null, "debug", innerID);
|
||||
this.exception = hook.bind(null, "exception", innerID);
|
||||
this.time = hook.bind(null, "time", innerID);
|
||||
this.timeEnd = hook.bind(null, "timeEnd", innerID);
|
||||
|
||||
this.__exposedProps__ = {
|
||||
log: "rw", info: "rw", warn: "rw", error: "rw", debug: "rw",
|
||||
exception: "rw", time: "rw", timeEnd: "rw"
|
||||
};
|
||||
}
|
||||
|
||||
// Creates a custom loader instance whose console module is hooked in order
|
||||
// to avoid printing messages to the console, and instead, expose them in the
|
||||
// returned `messages` array attribute
|
||||
exports.LoaderWithHookedConsole = function (module, callback) {
|
||||
let messages = [];
|
||||
function hook(msg) {
|
||||
messages.push({type: this, msg: msg});
|
||||
function hook(type, innerID, msg) {
|
||||
messages.push({ type: type, msg: msg, innerID: innerID });
|
||||
if (callback)
|
||||
callback(this, msg);
|
||||
callback(type, msg, innerID);
|
||||
}
|
||||
|
||||
return {
|
||||
loader: CustomLoader(module, {
|
||||
console: {
|
||||
log: hook.bind("log"),
|
||||
info: hook.bind("info"),
|
||||
warn: hook.bind("warn"),
|
||||
error: hook.bind("error"),
|
||||
debug: hook.bind("debug"),
|
||||
exception: hook.bind("exception"),
|
||||
time: hook.bind("time"),
|
||||
timeEnd: hook.bind("timeEnd"),
|
||||
__exposedProps__: {
|
||||
log: "rw", info: "rw", warn: "rw", error: "rw", debug: "rw",
|
||||
exception: "rw", time: "rw", timeEnd: "rw"
|
||||
console: new HookedPlainTextConsole(hook, null, null)
|
||||
}, override(require("@loader/options"), {
|
||||
modules: {
|
||||
'sdk/console/plain-text': {
|
||||
PlainTextConsole: HookedPlainTextConsole.bind(null, hook)
|
||||
}
|
||||
}
|
||||
}),
|
||||
})),
|
||||
messages: messages
|
||||
};
|
||||
}
|
||||
@ -94,25 +104,19 @@ exports.LoaderWithHookedConsole2 = function (module, callback) {
|
||||
// console message type and message and if it returns false the message will
|
||||
// not be logged normally
|
||||
exports.LoaderWithFilteredConsole = function (module, callback) {
|
||||
function hook(msg) {
|
||||
if (callback && callback(this, msg) == false)
|
||||
function hook(type, innerID, msg) {
|
||||
if (callback && callback(type, msg, innerID) == false)
|
||||
return;
|
||||
console[this](msg);
|
||||
console[type](msg);
|
||||
}
|
||||
|
||||
return CustomLoader(module, {
|
||||
console: {
|
||||
log: hook.bind("log"),
|
||||
info: hook.bind("info"),
|
||||
warn: hook.bind("warn"),
|
||||
error: hook.bind("error"),
|
||||
debug: hook.bind("debug"),
|
||||
exception: hook.bind("exception"),
|
||||
time: hook.bind("time"),
|
||||
timeEnd: hook.bind("timeEnd"),
|
||||
__exposedProps__: {
|
||||
log: "rw", info: "rw", warn: "rw", error: "rw", debug: "rw",
|
||||
exception: "rw", time: "rw", timeEnd: "rw"
|
||||
console: new HookedPlainTextConsole(hook, null, null)
|
||||
}, override(require("@loader/options"), {
|
||||
modules: {
|
||||
'sdk/console/plain-text': {
|
||||
PlainTextConsole: HookedPlainTextConsole.bind(null, hook)
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
@ -28,12 +28,14 @@ function newURI(uriStr, base) {
|
||||
let baseURI = base ? ios.newURI(base, null, null) : null;
|
||||
return ios.newURI(uriStr, null, baseURI);
|
||||
}
|
||||
catch (e if e.result == Cr.NS_ERROR_MALFORMED_URI) {
|
||||
throw new Error("malformed URI: " + uriStr);
|
||||
}
|
||||
catch (e if (e.result == Cr.NS_ERROR_FAILURE ||
|
||||
e.result == Cr.NS_ERROR_ILLEGAL_VALUE)) {
|
||||
throw new Error("invalid URI: " + uriStr);
|
||||
catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_MALFORMED_URI) {
|
||||
throw new Error("malformed URI: " + uriStr);
|
||||
}
|
||||
if (e.result == Cr.NS_ERROR_FAILURE ||
|
||||
e.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
|
||||
throw new Error("invalid URI: " + uriStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,9 +43,12 @@ function resolveResourceURI(uri) {
|
||||
var resolved;
|
||||
try {
|
||||
resolved = resProt.resolveURI(uri);
|
||||
} catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
|
||||
throw new Error("resource does not exist: " + uri.spec);
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
|
||||
throw new Error("resource does not exist: " + uri.spec);
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
@ -63,8 +68,11 @@ let toFilename = exports.toFilename = function toFilename(url) {
|
||||
try {
|
||||
channel = channel.QueryInterface(Ci.nsIFileChannel);
|
||||
return channel.file.path;
|
||||
} catch (e if e.result == Cr.NS_NOINTERFACE) {
|
||||
throw new Error("chrome url isn't on filesystem: " + url);
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result == Cr.NS_NOINTERFACE) {
|
||||
throw new Error("chrome url isn't on filesystem: " + url);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uri.scheme == "file") {
|
||||
@ -84,17 +92,32 @@ function URL(url, base) {
|
||||
var userPass = null;
|
||||
try {
|
||||
userPass = uri.userPass ? uri.userPass : null;
|
||||
} catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result != Cr.NS_ERROR_FAILURE) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var host = null;
|
||||
try {
|
||||
host = uri.host;
|
||||
} catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result != Cr.NS_ERROR_FAILURE) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var port = null;
|
||||
try {
|
||||
port = uri.port == -1 ? null : uri.port;
|
||||
} catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result != Cr.NS_ERROR_FAILURE) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
let uriData = [uri.path, uri.path.length, {}, {}, {}, {}, {}, {}];
|
||||
URLParser.parsePath.apply(URLParser, uriData);
|
||||
@ -262,16 +285,21 @@ let getTLD = exports.getTLD = function getTLD (url) {
|
||||
let tld = null;
|
||||
try {
|
||||
tld = tlds.getPublicSuffix(uri);
|
||||
} catch (e if
|
||||
e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS ||
|
||||
e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {}
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result != Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS &&
|
||||
e.result != Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return tld;
|
||||
};
|
||||
|
||||
let isValidURI = exports.isValidURI = function (uri) {
|
||||
try {
|
||||
newURI(uri);
|
||||
} catch(e) {
|
||||
}
|
||||
catch(e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
55
addon-sdk/source/lib/sdk/util/dispatcher.js
Normal file
55
addon-sdk/source/lib/sdk/util/dispatcher.js
Normal file
@ -0,0 +1,55 @@
|
||||
/* 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";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const method = require("method/core");
|
||||
|
||||
// Utility function that is just an enhancement over `method` to
|
||||
// allow predicate based dispatch in addition to polymorphic
|
||||
// dispatch. Unfortunately polymorphic dispatch does not quite
|
||||
// cuts it in the world of XPCOM where no types / classes exist
|
||||
// and all the XUL nodes share same type / prototype.
|
||||
// Probably this is more generic and belongs some place else, but
|
||||
// we can move it later once this will be relevant.
|
||||
let dispatcher = hint => {
|
||||
const base = method(hint);
|
||||
// Make a map for storing predicate, implementation mappings.
|
||||
let implementations = new Map();
|
||||
|
||||
// Dispatcher function goes through `predicate, implementation`
|
||||
// pairs to find predicate that matches first argument and
|
||||
// returns application of arguments on the associated
|
||||
// `implementation`. If no matching predicate is found delegates
|
||||
// to a `base` polymorphic function.
|
||||
let dispatch = (value, ...rest) => {
|
||||
for (let [predicate, implementation] of implementations) {
|
||||
if (predicate(value))
|
||||
return implementation(value, ...rest);
|
||||
}
|
||||
|
||||
return base(value, ...rest);
|
||||
};
|
||||
|
||||
// Expose base API.
|
||||
dispatch.define = base.define;
|
||||
dispatch.implement = base.implement;
|
||||
dispatch.toString = base.toString;
|
||||
|
||||
// Add a `when` function to allow extending function via
|
||||
// predicates.
|
||||
dispatch.when = (predicate, implementation) => {
|
||||
if (implementations.has(predicate))
|
||||
throw TypeError("Already implemented for the given predicate");
|
||||
implementations.set(predicate, implementation);
|
||||
};
|
||||
|
||||
return dispatch;
|
||||
};
|
||||
|
||||
exports.dispatcher = dispatcher;
|
@ -11,9 +11,26 @@ module.metadata = {
|
||||
}
|
||||
};
|
||||
|
||||
const { isBrowser } = require('./window/utils');
|
||||
const { modelFor } = require('./model/core');
|
||||
const { viewFor } = require('./view/core');
|
||||
|
||||
|
||||
if (require('./system/xul-app').is('Fennec')) {
|
||||
module.exports = require('./windows/fennec');
|
||||
}
|
||||
else {
|
||||
module.exports = require('./windows/firefox');
|
||||
}
|
||||
|
||||
|
||||
const browsers = module.exports.browserWindows;
|
||||
|
||||
//
|
||||
modelFor.when(isBrowser, view => {
|
||||
for (let model of browsers) {
|
||||
if (viewFor(model) === view)
|
||||
return model;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
@ -147,13 +147,13 @@ exports.testTabsGetFaviconPromiseFailure = function (assert, done) {
|
||||
exports.testRejects = function (assert, done) {
|
||||
getFavicon({})
|
||||
.then(invalidResolve(assert), validReject(assert, 'Object'))
|
||||
.then(getFavicon(null))
|
||||
.then(() => getFavicon(null))
|
||||
.then(invalidResolve(assert), validReject(assert, 'null'))
|
||||
.then(getFavicon(undefined))
|
||||
.then(() => getFavicon(undefined))
|
||||
.then(invalidResolve(assert), validReject(assert, 'undefined'))
|
||||
.then(getFavicon([]))
|
||||
.then(() => getFavicon([]))
|
||||
.then(invalidResolve(assert), validReject(assert, 'Array'))
|
||||
.then(done);
|
||||
.catch(assert.fail).then(done);
|
||||
};
|
||||
|
||||
function invalidResolve (assert) {
|
||||
|
@ -31,26 +31,25 @@ exports['test construct tree'] = function (assert) {
|
||||
assert.equal(tree.get(4).get(2), null, 'node.get descends from itself fails if not descendant');
|
||||
};
|
||||
|
||||
exports['test walk'] = function (assert) {
|
||||
exports['test walk'] = function (assert, done) {
|
||||
let resultsAll = [];
|
||||
let resultsNode = [];
|
||||
let tree = TreeNode(1);
|
||||
tree.add([2, 3, 4]);
|
||||
tree.get(2).add([2.1, 2.2]);
|
||||
|
||||
tree.walk(function (node) {
|
||||
resultsAll.push(node.value);
|
||||
});
|
||||
|
||||
[1, 2, 2.1, 2.2, 3, 4].forEach(function (num) {
|
||||
assert.ok(~resultsAll.indexOf(num), 'function applied to each node from root');
|
||||
});
|
||||
|
||||
let resultsNode = [];
|
||||
tree.get(2).walk(function (node) resultsNode.push(node.value));
|
||||
|
||||
[2, 2.1, 2.2].forEach(function (num) {
|
||||
assert.ok(~resultsNode.indexOf(num), 'function applied to each node from node');
|
||||
});
|
||||
}).then(() => {
|
||||
[1, 2, 2.1, 2.2, 3, 4].forEach(num => {
|
||||
assert.ok(~resultsAll.indexOf(num), 'function applied to each node from root');
|
||||
});
|
||||
return tree.get(2).walk(node => resultsNode.push(node.value));
|
||||
}).then(() => {
|
||||
[2, 2.1, 2.2].forEach(function (num) {
|
||||
assert.ok(~resultsNode.indexOf(num), 'function applied to each node from node');
|
||||
});
|
||||
}).catch(assert.fail).then(done);
|
||||
};
|
||||
|
||||
exports['test async walk'] = function (assert, done) {
|
||||
|
77
addon-sdk/source/test/test-dispatcher.js
Normal file
77
addon-sdk/source/test/test-dispatcher.js
Normal file
@ -0,0 +1,77 @@
|
||||
/* 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";
|
||||
|
||||
const { dispatcher } = require("sdk/util/dispatcher");
|
||||
|
||||
exports["test dispatcher API"] = assert => {
|
||||
const dispatch = dispatcher();
|
||||
|
||||
assert.equal(typeof(dispatch), "function",
|
||||
"dispatch is a function");
|
||||
|
||||
assert.equal(typeof(dispatch.define), "function",
|
||||
"dispatch.define is a function");
|
||||
|
||||
assert.equal(typeof(dispatch.implement), "function",
|
||||
"dispatch.implement is a function");
|
||||
|
||||
assert.equal(typeof(dispatch.when), "function",
|
||||
"dispatch.when is a function");
|
||||
};
|
||||
|
||||
exports["test dispatcher"] = assert => {
|
||||
const isDuck = dispatcher();
|
||||
|
||||
const quacks = x => x && typeof(x.quack) === "function";
|
||||
|
||||
const Duck = function() {};
|
||||
const Goose = function() {};
|
||||
|
||||
const True = _ => true;
|
||||
const False = _ => false;
|
||||
|
||||
|
||||
|
||||
isDuck.define(Goose, False);
|
||||
isDuck.define(Duck, True);
|
||||
isDuck.when(quacks, True);
|
||||
|
||||
assert.equal(isDuck(new Goose()), false,
|
||||
"Goose ain't duck");
|
||||
|
||||
assert.equal(isDuck(new Duck()), true,
|
||||
"Ducks are ducks");
|
||||
|
||||
assert.equal(isDuck({ quack: () => "Quaaaaaack!" }), true,
|
||||
"It's a duck if it quacks");
|
||||
|
||||
|
||||
assert.throws(() => isDuck({}), /Type does not implements method/, "not implemneted");
|
||||
|
||||
isDuck.define(Object, False);
|
||||
|
||||
assert.equal(isDuck({}), false,
|
||||
"Ain't duck if it does not quacks!");
|
||||
};
|
||||
|
||||
exports["test redefining fails"] = assert => {
|
||||
const isPM = dispatcher();
|
||||
const isAfternoon = time => time.getHours() > 12;
|
||||
|
||||
isPM.when(isAfternoon, _ => true);
|
||||
|
||||
assert.equal(isPM(new Date(Date.parse("Jan 23, 1985, 13:20:00"))), true,
|
||||
"yeap afternoon");
|
||||
assert.equal(isPM({ getHours: _ => 17 }), true,
|
||||
"seems like afternoon");
|
||||
|
||||
assert.throws(() => isPM.when(isAfternoon, x => x > 12 && x < 24),
|
||||
/Already implemented for the given predicate/,
|
||||
"can't redefine on same predicate");
|
||||
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
@ -29,18 +29,6 @@ exports["test async readURI"] = function(assert, done) {
|
||||
assert.equal(content, "", "The URL content is not load yet");
|
||||
}
|
||||
|
||||
exports["test sync readURI"] = function(assert) {
|
||||
let content = "";
|
||||
|
||||
readURI(data.url("test-net-url.txt"), { sync: true }).then(function(data) {
|
||||
content = data;
|
||||
}, function() {
|
||||
assert.fail("should not reject");
|
||||
})
|
||||
|
||||
assert.equal(content, utf8text, "The URL content is loaded properly");
|
||||
}
|
||||
|
||||
exports["test readURISync"] = function(assert) {
|
||||
let content = readURISync(data.url("test-net-url.txt"));
|
||||
|
||||
@ -62,21 +50,6 @@ exports["test async readURI with ISO-8859-1 charset"] = function(assert, done) {
|
||||
assert.equal(content, "", "The URL content is not load yet");
|
||||
}
|
||||
|
||||
exports["test sync readURI with ISO-8859-1 charset"] = function(assert) {
|
||||
let content = "";
|
||||
|
||||
readURI(data.url("test-net-url.txt"), {
|
||||
sync: true,
|
||||
charset: "ISO-8859-1"
|
||||
}).then(function(data) {
|
||||
content = data;
|
||||
}, function() {
|
||||
assert.fail("should not reject");
|
||||
})
|
||||
|
||||
assert.equal(content, latin1text, "The URL content is loaded properly");
|
||||
}
|
||||
|
||||
exports["test readURISync with ISO-8859-1 charset"] = function(assert) {
|
||||
let content = readURISync(data.url("test-net-url.txt"), "ISO-8859-1");
|
||||
|
||||
@ -93,14 +66,6 @@ exports["test async readURI with not existing file"] = function(assert, done) {
|
||||
})
|
||||
}
|
||||
|
||||
exports["test sync readURI with not existing file"] = function(assert) {
|
||||
readURI(data.url("test-net-url-fake.txt"), { sync: true }).then(function(data) {
|
||||
assert.fail("should not resolve");
|
||||
}, function(reason) {
|
||||
assert.ok(reason.indexOf("Failed to read:") === 0);
|
||||
})
|
||||
}
|
||||
|
||||
exports["test readURISync with not existing file"] = function(assert) {
|
||||
assert.throws(function() {
|
||||
readURISync(data.url("test-net-url-fake.txt"));
|
||||
@ -122,18 +87,6 @@ exports["test async readURI with data URI"] = function(assert, done) {
|
||||
assert.equal(content, "", "The URL content is not load yet");
|
||||
}
|
||||
|
||||
exports["test sync readURI with data URI"] = function(assert) {
|
||||
let content = "";
|
||||
|
||||
readURI(dataURIutf8, { sync: true }).then(function(data) {
|
||||
content = data;
|
||||
}, function() {
|
||||
assert.fail("should not reject");
|
||||
})
|
||||
|
||||
assert.equal(content, utf8text, "The URL content is loaded properly");
|
||||
}
|
||||
|
||||
exports["test readURISync with data URI"] = function(assert) {
|
||||
let content = readURISync(dataURIutf8);
|
||||
|
||||
@ -155,21 +108,6 @@ exports["test async readURI with data URI and ISO-8859-1 charset"] = function(as
|
||||
assert.equal(content, "", "The URL content is not load yet");
|
||||
}
|
||||
|
||||
exports["test sync readURI with data URI and ISO-8859-1 charset"] = function(assert) {
|
||||
let content = "";
|
||||
|
||||
readURI(dataURIlatin1, {
|
||||
sync: true,
|
||||
charset: "ISO-8859-1"
|
||||
}).then(function(data) {
|
||||
content = unescape(data);
|
||||
}, function() {
|
||||
assert.fail("should not reject");
|
||||
})
|
||||
|
||||
assert.equal(content, latin1text, "The URL content is loaded properly");
|
||||
}
|
||||
|
||||
exports["test readURISync with data URI and ISO-8859-1 charset"] = function(assert) {
|
||||
let content = unescape(readURISync(dataURIlatin1, "ISO-8859-1"));
|
||||
|
||||
@ -197,16 +135,4 @@ exports["test async readURI with chrome URI"] = function(assert, done) {
|
||||
assert.equal(content, "", "The URL content is not load yet");
|
||||
}
|
||||
|
||||
exports["test sync readURI with chrome URI"] = function(assert) {
|
||||
let content = "";
|
||||
|
||||
readURI(chromeURI, { sync: true }).then(function(data) {
|
||||
content = data;
|
||||
}, function() {
|
||||
assert.fail("should not reject");
|
||||
})
|
||||
|
||||
assert.equal(content, readURISync(chromeURI), "The URL content is loaded properly");
|
||||
}
|
||||
|
||||
require("test").run(exports)
|
||||
|
@ -24,6 +24,7 @@ const { isTabPBSupported, isWindowPBSupported, isGlobalPBSupported } = require('
|
||||
const promise = require("sdk/core/promise");
|
||||
const { pb } = require('./private-browsing/helper');
|
||||
const { URL } = require("sdk/url");
|
||||
const { LoaderWithHookedConsole } = require('sdk/test/loader');
|
||||
|
||||
const { waitUntil } = require("sdk/test/utils");
|
||||
const data = require("./fixtures");
|
||||
@ -1531,6 +1532,41 @@ exports.testDetachOnUnload = function(assert, done) {
|
||||
})
|
||||
}
|
||||
|
||||
exports.testConsole = function(assert, done) {
|
||||
let innerID;
|
||||
const TEST_URL = 'data:text/html;charset=utf-8,console';
|
||||
const { loader } = LoaderWithHookedConsole(module, onMessage);
|
||||
const { PageMod } = loader.require('sdk/page-mod');
|
||||
const system = require("sdk/system/events");
|
||||
|
||||
let seenMessage = false;
|
||||
function onMessage(type, msg, msgID) {
|
||||
seenMessage = true;
|
||||
innerID = msgID;
|
||||
}
|
||||
|
||||
let mod = PageMod({
|
||||
include: TEST_URL,
|
||||
contentScriptWhen: "ready",
|
||||
contentScript: Isolate(function() {
|
||||
console.log("Hello from the page mod");
|
||||
self.port.emit("done");
|
||||
}),
|
||||
onAttach: function(worker) {
|
||||
worker.port.on("done", function() {
|
||||
let window = getTabContentWindow(tab);
|
||||
let id = getInnerId(window);
|
||||
assert.ok(seenMessage, "Should have seen the console message");
|
||||
assert.equal(innerID, id, "Should have seen the right inner ID");
|
||||
closeTab(tab);
|
||||
done();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
let tab = openTab(getMostRecentBrowserWindow(), TEST_URL);
|
||||
}
|
||||
|
||||
exports.testSyntaxErrorInContentScript = function(assert, done) {
|
||||
const url = "data:text/html;charset=utf-8,testSyntaxErrorInContentScript";
|
||||
let hitError = null;
|
||||
|
@ -454,8 +454,13 @@ function isDestroyed(page) {
|
||||
try {
|
||||
page.postMessage("foo");
|
||||
}
|
||||
catch (err if err.message == ERR_DESTROYED) {
|
||||
return true;
|
||||
catch (err) {
|
||||
if (err.message == ERR_DESTROYED) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -901,7 +901,7 @@ exports['test passing DOM node as first argument'] = function (assert, done) {
|
||||
|
||||
let widgetNode = document.getElementById(widgetId);
|
||||
|
||||
all(warned.promise, shown.promise).
|
||||
all([warned.promise, shown.promise]).
|
||||
then(loader.unload).
|
||||
then(done, assert.fail)
|
||||
|
||||
|
@ -230,6 +230,31 @@ exports.testPlainTextConsoleBoundMethods = function(assert) {
|
||||
restorePrefs();
|
||||
};
|
||||
|
||||
exports.testConsoleInnerID = function(assert) {
|
||||
let Console = require("sdk/console/plain-text").PlainTextConsole;
|
||||
let { log, info, warn, error, debug, exception, trace } = new Console(function() {}, "test ID");
|
||||
|
||||
let messages = [];
|
||||
function onMessage({ subject }) {
|
||||
let message = subject.wrappedJSObject;
|
||||
messages.push({ msg: message.arguments[0], type: message.level, innerID: message.innerID });
|
||||
}
|
||||
|
||||
const system = require("sdk/system/events");
|
||||
system.on("console-api-log-event", onMessage);
|
||||
|
||||
log("Test log");
|
||||
warn("Test warning");
|
||||
error("Test error");
|
||||
|
||||
assert.equal(messages.length, 3, "Should see 3 log events");
|
||||
assert.deepEqual(messages[0], { msg: "Test log", type: "log", innerID: "test ID" }, "Should see the right event");
|
||||
assert.deepEqual(messages[1], { msg: "Test warning", type: "warn", innerID: "test ID" }, "Should see the right event");
|
||||
assert.deepEqual(messages[2], { msg: "Test error", type: "error", innerID: "test ID" }, "Should see the right event");
|
||||
|
||||
system.off("console-api-log-event", onMessage);
|
||||
};
|
||||
|
||||
function restorePrefs() {
|
||||
if (HAS_ORIGINAL_ADDON_LOG_LEVEL)
|
||||
prefs.set(ADDON_LOG_LEVEL_PREF, ORIGINAL_ADDON_LOG_LEVEL);
|
||||
|
@ -4,277 +4,235 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var core = require('sdk/core/promise'),
|
||||
defer = core.defer, resolve = core.resolve, reject = core.reject, all = core.all,
|
||||
promised = core.promised;
|
||||
|
||||
var { setTimeout } = require('sdk/timers');
|
||||
const { Cc, Cu, Ci } = require('chrome');
|
||||
const { setTimeout } = require('sdk/timers');
|
||||
const { prefixURI, name } = require('@loader/options');
|
||||
const addonPromiseURI = prefixURI + name + '/lib/sdk/core/promise.js';
|
||||
const builtPromiseURI = 'resource://gre/modules/commonjs/sdk/core/promise.js';
|
||||
let { Promise, defer, resolve, reject, all, promised } = require('sdk/core/promise');
|
||||
|
||||
exports['test all observers are notified'] = function(assert, done) {
|
||||
var expected = 'Taram pam param!'
|
||||
var deferred = defer()
|
||||
var pending = 10, i = 0
|
||||
let expected = 'Taram pam param!';
|
||||
let deferred = defer();
|
||||
let pending = 10, i = 0;
|
||||
|
||||
function resolved(value) {
|
||||
assert.equal(value, expected, 'value resolved as expected: #' + pending)
|
||||
if (!--pending) done()
|
||||
assert.equal(value, expected, 'value resolved as expected: #' + pending);
|
||||
if (!--pending) done();
|
||||
}
|
||||
|
||||
while (i++ < pending) deferred.promise.then(resolved)
|
||||
while (i++ < pending) deferred.promise.then(resolved);
|
||||
|
||||
deferred.resolve(expected)
|
||||
}
|
||||
deferred.resolve(expected);
|
||||
};
|
||||
|
||||
exports['test exceptions dont stop notifications'] = function(assert, done) {
|
||||
var threw = false, boom = Error('Boom!')
|
||||
var deferred = defer()
|
||||
let threw = false, boom = Error('Boom!');
|
||||
let deferred = defer();
|
||||
|
||||
var promise2 = deferred.promise.then(function() {
|
||||
threw = true
|
||||
throw boom
|
||||
})
|
||||
let promise2 = deferred.promise.then(function() {
|
||||
threw = true;
|
||||
throw boom;
|
||||
});
|
||||
|
||||
deferred.promise.then(function() {
|
||||
assert.ok(threw, 'observer is called even though previos one threw')
|
||||
assert.ok(threw, 'observer is called even though previos one threw');
|
||||
promise2.then(function() {
|
||||
assert.fail('should not resolve')
|
||||
assert.fail('should not resolve');
|
||||
}, function(reason) {
|
||||
assert.equal(reason, boom, 'rejects to thrown error')
|
||||
done()
|
||||
})
|
||||
})
|
||||
assert.equal(reason, boom, 'rejects to thrown error');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
deferred.resolve('go!')
|
||||
}
|
||||
deferred.resolve('go!');
|
||||
};
|
||||
|
||||
exports['test subsequent resolves are ignored'] = function(assert, done) {
|
||||
var deferred = defer()
|
||||
deferred.resolve(1)
|
||||
deferred.resolve(2)
|
||||
deferred.reject(3)
|
||||
let deferred = defer();
|
||||
deferred.resolve(1);
|
||||
deferred.resolve(2);
|
||||
deferred.reject(3);
|
||||
|
||||
deferred.promise.then(function(actual) {
|
||||
assert.equal(actual, 1, 'resolves to first value')
|
||||
assert.equal(actual, 1, 'resolves to first value');
|
||||
}, function() {
|
||||
assert.fail('must not reject')
|
||||
})
|
||||
assert.fail('must not reject');
|
||||
});
|
||||
deferred.promise.then(function(actual) {
|
||||
assert.equal(actual, 1, 'subsequent resolutions are ignored')
|
||||
done()
|
||||
assert.equal(actual, 1, 'subsequent resolutions are ignored');
|
||||
done();
|
||||
}, function() {
|
||||
assert.fail('must not reject')
|
||||
})
|
||||
}
|
||||
assert.fail('must not reject');
|
||||
});
|
||||
};
|
||||
|
||||
exports['test subsequent rejections are ignored'] = function(assert, done) {
|
||||
var deferred = defer()
|
||||
deferred.reject(1)
|
||||
deferred.resolve(2)
|
||||
deferred.reject(3)
|
||||
let deferred = defer();
|
||||
deferred.reject(1);
|
||||
deferred.resolve(2);
|
||||
deferred.reject(3);
|
||||
|
||||
deferred.promise.then(function(actual) {
|
||||
assert.fail('must not resolve')
|
||||
assert.fail('must not resolve');
|
||||
}, function(actual) {
|
||||
assert.equal(actual, 1, 'must reject to first')
|
||||
})
|
||||
assert.equal(actual, 1, 'must reject to first');
|
||||
});
|
||||
deferred.promise.then(function(actual) {
|
||||
assert.fail('must not resolve')
|
||||
assert.fail('must not resolve');
|
||||
}, function(actual) {
|
||||
assert.equal(actual, 1, 'must reject to first')
|
||||
done()
|
||||
})
|
||||
}
|
||||
assert.equal(actual, 1, 'must reject to first');
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
exports['test error recovery'] = function(assert, done) {
|
||||
var boom = Error('Boom!')
|
||||
var deferred = defer()
|
||||
let boom = Error('Boom!');
|
||||
let deferred = defer();
|
||||
|
||||
deferred.promise.then(function() {
|
||||
assert.fail('rejected promise should not resolve')
|
||||
assert.fail('rejected promise should not resolve');
|
||||
}, function(reason) {
|
||||
assert.equal(reason, boom, 'rejection reason delivered')
|
||||
return 'recovery'
|
||||
assert.equal(reason, boom, 'rejection reason delivered');
|
||||
return 'recovery';
|
||||
}).then(function(value) {
|
||||
assert.equal(value, 'recovery', 'error handled by a handler')
|
||||
done()
|
||||
})
|
||||
|
||||
deferred.reject(boom)
|
||||
}
|
||||
assert.equal(value, 'recovery', 'error handled by a handler');
|
||||
done();
|
||||
});
|
||||
|
||||
deferred.reject(boom);
|
||||
};
|
||||
|
||||
exports['test error recovery with promise'] = function(assert, done) {
|
||||
var deferred = defer()
|
||||
let deferred = defer();
|
||||
|
||||
deferred.promise.then(function() {
|
||||
assert.fail('must reject')
|
||||
assert.fail('must reject');
|
||||
}, function(actual) {
|
||||
assert.equal(actual, 'reason', 'rejected')
|
||||
var deferred = defer()
|
||||
deferred.resolve('recovery')
|
||||
return deferred.promise
|
||||
assert.equal(actual, 'reason', 'rejected');
|
||||
let deferred = defer();
|
||||
deferred.resolve('recovery');
|
||||
return deferred.promise;
|
||||
}).then(function(actual) {
|
||||
assert.equal(actual, 'recovery', 'recorvered via promise')
|
||||
var deferred = defer()
|
||||
deferred.reject('error')
|
||||
return deferred.promise
|
||||
assert.equal(actual, 'recovery', 'recorvered via promise');
|
||||
let deferred = defer();
|
||||
deferred.reject('error');
|
||||
return deferred.promise;
|
||||
}).then(null, function(actual) {
|
||||
assert.equal(actual, 'error', 'rejected via promise')
|
||||
var deferred = defer()
|
||||
deferred.reject('end')
|
||||
return deferred.promise
|
||||
assert.equal(actual, 'error', 'rejected via promise');
|
||||
let deferred = defer();
|
||||
deferred.reject('end');
|
||||
return deferred.promise;
|
||||
}).then(null, function(actual) {
|
||||
assert.equal(actual, 'end', 'rejeced via promise')
|
||||
done()
|
||||
})
|
||||
assert.equal(actual, 'end', 'rejeced via promise');
|
||||
done();
|
||||
});
|
||||
|
||||
deferred.reject('reason')
|
||||
}
|
||||
deferred.reject('reason');
|
||||
};
|
||||
|
||||
exports['test propagation'] = function(assert, done) {
|
||||
var d1 = defer(), d2 = defer(), d3 = defer()
|
||||
let d1 = defer(), d2 = defer(), d3 = defer();
|
||||
|
||||
d1.promise.then(function(actual) {
|
||||
assert.equal(actual, 'expected', 'resolves to expected value')
|
||||
done()
|
||||
})
|
||||
assert.equal(actual, 'expected', 'resolves to expected value');
|
||||
done();
|
||||
});
|
||||
|
||||
d1.resolve(d2.promise)
|
||||
d2.resolve(d3.promise)
|
||||
d3.resolve('expected')
|
||||
}
|
||||
d1.resolve(d2.promise);
|
||||
d2.resolve(d3.promise);
|
||||
d3.resolve('expected');
|
||||
};
|
||||
|
||||
exports['test chaining'] = function(assert, done) {
|
||||
var boom = Error('boom'), brax = Error('braxXXx')
|
||||
var deferred = defer()
|
||||
let boom = Error('boom'), brax = Error('braxXXx');
|
||||
let deferred = defer();
|
||||
|
||||
deferred.promise.then().then().then(function(actual) {
|
||||
assert.equal(actual, 2, 'value propagates unchanged')
|
||||
return actual + 2
|
||||
assert.equal(actual, 2, 'value propagates unchanged');
|
||||
return actual + 2;
|
||||
}).then(null, function(reason) {
|
||||
assert.fail('should not reject')
|
||||
assert.fail('should not reject');
|
||||
}).then(function(actual) {
|
||||
assert.equal(actual, 4, 'value propagates through if not handled')
|
||||
throw boom
|
||||
assert.equal(actual, 4, 'value propagates through if not handled');
|
||||
throw boom;
|
||||
}).then(function(actual) {
|
||||
assert.fail('exception must reject promise')
|
||||
assert.fail('exception must reject promise');
|
||||
}).then().then(null, function(actual) {
|
||||
assert.equal(actual, boom, 'reason propagates unchanged')
|
||||
throw brax
|
||||
assert.equal(actual, boom, 'reason propagates unchanged');
|
||||
throw brax;
|
||||
}).then().then(null, function(actual) {
|
||||
assert.equal(actual, brax, 'reason changed becase of exception')
|
||||
return 'recovery'
|
||||
assert.equal(actual, brax, 'reason changed becase of exception');
|
||||
return 'recovery';
|
||||
}).then(function(actual) {
|
||||
assert.equal(actual, 'recovery', 'recovered from error')
|
||||
done()
|
||||
})
|
||||
|
||||
deferred.resolve(2)
|
||||
}
|
||||
assert.equal(actual, 'recovery', 'recovered from error');
|
||||
done();
|
||||
});
|
||||
|
||||
deferred.resolve(2);
|
||||
};
|
||||
|
||||
exports['test reject'] = function(assert, done) {
|
||||
var expected = Error('boom')
|
||||
let expected = Error('boom');
|
||||
|
||||
reject(expected).then(function() {
|
||||
assert.fail('should reject')
|
||||
assert.fail('should reject');
|
||||
}, function(actual) {
|
||||
assert.equal(actual, expected, 'rejected with expected reason')
|
||||
}).then(function() {
|
||||
done()
|
||||
})
|
||||
}
|
||||
assert.equal(actual, expected, 'rejected with expected reason');
|
||||
}).then(done, assert.fail);
|
||||
};
|
||||
|
||||
exports['test resolve to rejected'] = function(assert, done) {
|
||||
var expected = Error('boom')
|
||||
var deferred = defer()
|
||||
let expected = Error('boom');
|
||||
let deferred = defer();
|
||||
|
||||
deferred.promise.then(function() {
|
||||
assert.fail('should reject')
|
||||
assert.fail('should reject');
|
||||
}, function(actual) {
|
||||
assert.equal(actual, expected, 'rejected with expected failure')
|
||||
}).then(function() {
|
||||
done()
|
||||
})
|
||||
assert.equal(actual, expected, 'rejected with expected failure');
|
||||
}).then(done, assert.fail);
|
||||
|
||||
deferred.resolve(reject(expected))
|
||||
}
|
||||
deferred.resolve(reject(expected));
|
||||
};
|
||||
|
||||
exports['test resolve'] = function(assert, done) {
|
||||
var expected = 'value'
|
||||
let expected = 'value';
|
||||
resolve(expected).then(function(actual) {
|
||||
assert.equal(actual, expected, 'resolved as expected')
|
||||
}).then(function() {
|
||||
done()
|
||||
})
|
||||
}
|
||||
|
||||
exports['test resolve with prototype'] = function(assert, done) {
|
||||
var seventy = resolve(70, {
|
||||
subtract: function subtract(y) {
|
||||
return this.then(function(x) { return x - y })
|
||||
}
|
||||
})
|
||||
|
||||
seventy.subtract(17).then(function(actual) {
|
||||
assert.equal(actual, 70 - 17, 'resolves to expected')
|
||||
done()
|
||||
})
|
||||
}
|
||||
assert.equal(actual, expected, 'resolved as expected');
|
||||
}).catch(assert.fail).then(done);
|
||||
};
|
||||
|
||||
exports['test promised with normal args'] = function(assert, done) {
|
||||
var sum = promised(function(x, y) { return x + y })
|
||||
let sum = promised((x, y) => x + y );
|
||||
|
||||
sum(7, 8).then(function(actual) {
|
||||
assert.equal(actual, 7 + 8, 'resolves as expected')
|
||||
done()
|
||||
})
|
||||
}
|
||||
assert.equal(actual, 7 + 8, 'resolves as expected');
|
||||
}).catch(assert.fail).then(done);
|
||||
};
|
||||
|
||||
exports['test promised with promise args'] = function(assert, done) {
|
||||
var sum = promised(function(x, y) { return x + y })
|
||||
var deferred = defer()
|
||||
let sum = promised((x, y) => x + y );
|
||||
let deferred = defer();
|
||||
|
||||
sum(11, deferred.promise).then(function(actual) {
|
||||
assert.equal(actual, 11 + 24, 'resolved as expected')
|
||||
done()
|
||||
})
|
||||
assert.equal(actual, 11 + 24, 'resolved as expected');
|
||||
}).catch(assert.fail).then(done);
|
||||
|
||||
deferred.resolve(24)
|
||||
}
|
||||
|
||||
exports['test promised with prototype'] = function(assert, done) {
|
||||
var deferred = defer()
|
||||
var numeric = {}
|
||||
numeric.subtract = promised(function(y) { return this - y }, numeric)
|
||||
|
||||
var sum = promised(function(x, y) { return x + y }, numeric)
|
||||
|
||||
sum(7, 70).
|
||||
subtract(14).
|
||||
subtract(deferred.promise).
|
||||
subtract(5).
|
||||
then(function(actual) {
|
||||
assert.equal(actual, 7 + 70 - 14 - 23 - 5, 'resolved as expected')
|
||||
done()
|
||||
})
|
||||
|
||||
deferred.resolve(23)
|
||||
}
|
||||
deferred.resolve(24);
|
||||
};
|
||||
|
||||
exports['test promised error handleing'] = function(assert, done) {
|
||||
var expected = Error('boom')
|
||||
var f = promised(function() {
|
||||
throw expected
|
||||
})
|
||||
let expected = Error('boom');
|
||||
let f = promised(function() {
|
||||
throw expected;
|
||||
});
|
||||
|
||||
f().then(function() {
|
||||
assert.fail('should reject')
|
||||
assert.fail('should reject');
|
||||
}, function(actual) {
|
||||
assert.equal(actual, expected, 'rejected as expected')
|
||||
done()
|
||||
})
|
||||
}
|
||||
assert.equal(actual, expected, 'rejected as expected');
|
||||
}).catch(assert.fail).then(done);
|
||||
};
|
||||
|
||||
exports['test errors in promise resolution handlers are propagated'] = function(assert, done) {
|
||||
var expected = Error('Boom');
|
||||
@ -289,56 +247,67 @@ exports['test errors in promise resolution handlers are propagated'] = function(
|
||||
}).then(done, assert.fail);
|
||||
|
||||
resolve({});
|
||||
}
|
||||
};
|
||||
|
||||
exports['test return promise form promised'] = function(assert, done) {
|
||||
var f = promised(function() {
|
||||
return resolve(17)
|
||||
})
|
||||
let f = promised(function() {
|
||||
return resolve(17);
|
||||
});
|
||||
|
||||
f().then(function(actual) {
|
||||
assert.equal(actual, 17, 'resolves to a promise resolution')
|
||||
done()
|
||||
})
|
||||
}
|
||||
assert.equal(actual, 17, 'resolves to a promise resolution');
|
||||
}).catch(assert.fail).then(done);
|
||||
};
|
||||
|
||||
exports['test promised returning failure'] = function(assert, done) {
|
||||
var expected = Error('boom')
|
||||
var f = promised(function() {
|
||||
return reject(expected)
|
||||
})
|
||||
let expected = Error('boom');
|
||||
let f = promised(function() {
|
||||
return reject(expected);
|
||||
});
|
||||
|
||||
f().then(function() {
|
||||
assert.fail('must reject')
|
||||
assert.fail('must reject');
|
||||
}, function(actual) {
|
||||
assert.equal(actual, expected, 'rejects with expected reason')
|
||||
done()
|
||||
})
|
||||
}
|
||||
assert.equal(actual, expected, 'rejects with expected reason');
|
||||
}).catch(assert.fail).then(done);
|
||||
};
|
||||
|
||||
exports['test promised are greedy'] = function(assert, done) {
|
||||
var runs = 0
|
||||
var f = promised(function() { ++runs })
|
||||
var promise = f()
|
||||
assert.equal(runs, 1, 'promised runs task right away')
|
||||
done()
|
||||
}
|
||||
/*
|
||||
* Changed for compliance in Bug 881047, promises are now always async
|
||||
*/
|
||||
exports['test promises are always async'] = function (assert, done) {
|
||||
let runs = 0;
|
||||
resolve(1)
|
||||
.then(val => ++runs)
|
||||
.catch(assert.fail).then(done);
|
||||
assert.equal(runs, 0, 'resolutions are called in following tick');
|
||||
};
|
||||
|
||||
/*
|
||||
* Changed for compliance in Bug 881047, promised's are now non greedy
|
||||
*/
|
||||
exports['test promised are not greedy'] = function(assert, done) {
|
||||
let runs = 0;
|
||||
promised(() => ++runs)()
|
||||
.catch(assert.fail).then(done);
|
||||
assert.equal(runs, 0, 'promised does not run task right away');
|
||||
};
|
||||
|
||||
exports['test arrays should not flatten'] = function(assert, done) {
|
||||
var a = defer()
|
||||
var b = defer()
|
||||
let a = defer();
|
||||
let b = defer();
|
||||
|
||||
var combine = promised(function(str, arr) {
|
||||
assert.equal(str, 'Hello', 'Array was not flattened')
|
||||
assert.deepEqual(arr, [ 'my', 'friend' ])
|
||||
})
|
||||
let combine = promised(function(str, arr) {
|
||||
assert.equal(str, 'Hello', 'Array was not flattened');
|
||||
assert.deepEqual(arr, [ 'my', 'friend' ]);
|
||||
});
|
||||
|
||||
combine(a.promise, b.promise).then(done)
|
||||
combine(a.promise, b.promise).catch(assert.fail).then(done);
|
||||
|
||||
|
||||
a.resolve('Hello')
|
||||
b.resolve([ 'my', 'friend' ])
|
||||
}
|
||||
a.resolve('Hello');
|
||||
b.resolve([ 'my', 'friend' ]);
|
||||
};
|
||||
|
||||
exports['test `all` for all promises'] = function (assert, done) {
|
||||
all([
|
||||
@ -366,7 +335,7 @@ exports['test `all` aborts upon first reject'] = function (assert, done) {
|
||||
});
|
||||
|
||||
function delayedResolve () {
|
||||
var deferred = defer();
|
||||
let deferred = defer();
|
||||
setTimeout(deferred.resolve, 50);
|
||||
return deferred.promise;
|
||||
}
|
||||
@ -404,4 +373,78 @@ exports['test `all` with multiple rejected'] = function (assert, done) {
|
||||
});
|
||||
};
|
||||
|
||||
require("test").run(exports)
|
||||
exports['test Promise constructor resolve'] = function (assert, done) {
|
||||
var isAsync = true;
|
||||
new Promise(function (resolve, reject) {
|
||||
resolve(5);
|
||||
}).then(x => {
|
||||
isAsync = false;
|
||||
assert.equal(x, 5, 'Promise constructor resolves correctly');
|
||||
}).catch(assert.fail).then(done);
|
||||
assert.ok(isAsync, 'Promise constructor runs async');
|
||||
};
|
||||
|
||||
exports['test Promise constructor reject'] = function (assert, done) {
|
||||
new Promise(function (resolve, reject) {
|
||||
reject(new Error('deferred4life'));
|
||||
}).then(assert.fail, (err) => {
|
||||
assert.equal(err.message, 'deferred4life', 'Promise constructor rejects correctly');
|
||||
}).catch(assert.fail).then(done);
|
||||
};
|
||||
|
||||
exports['test JSM Load and API'] = function (assert, done) {
|
||||
// Use addon URL when loading from cfx/local:
|
||||
// resource://90111c90-c31e-4dc7-ac35-b65947434435-at-jetpack/addon-sdk/lib/sdk/core/promise.js
|
||||
// Use built URL when testing on try, etc.
|
||||
// resource://gre/modules/commonjs/sdk/core/promise.js
|
||||
try {
|
||||
var { Promise } = Cu.import(addonPromiseURI, {});
|
||||
} catch (e) {
|
||||
var { Promise } = Cu.import(builtPromiseURI, {});
|
||||
}
|
||||
testEnvironment(Promise, assert, done, 'JSM');
|
||||
};
|
||||
|
||||
exports['test mozIJSSubScriptLoader exporting'] = function (assert, done) {
|
||||
let { Services } = Cu.import('resource://gre/modules/Services.jsm', {});
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let Promise = new Cu.Sandbox(systemPrincipal);
|
||||
let loader = Cc['@mozilla.org/moz/jssubscript-loader;1']
|
||||
.getService(Ci.mozIJSSubScriptLoader);
|
||||
|
||||
// Use addon URL when loading from cfx/local:
|
||||
// resource://90111c90-c31e-4dc7-ac35-b65947434435-at-jetpack/addon-sdk/lib/sdk/core/promise.js
|
||||
// Use built URL when testing on try, etc.
|
||||
// resource://gre/modules/commonjs/sdk/core/promise.js
|
||||
try {
|
||||
loader.loadSubScript(addonPromiseURI, Promise);
|
||||
} catch (e) {
|
||||
loader.loadSubScript(builtPromiseURI, Promise);
|
||||
}
|
||||
|
||||
testEnvironment(Promise, assert, done, 'mozIJSSubScript');
|
||||
};
|
||||
|
||||
function testEnvironment ({all, resolve, defer, reject, promised}, assert, done, type) {
|
||||
all([resolve(5), resolve(10), 925]).then(val => {
|
||||
assert.equal(val[0], 5, 'promise#all works ' + type);
|
||||
assert.equal(val[1], 10, 'promise#all works ' + type);
|
||||
assert.equal(val[2], 925, 'promise#all works ' + type);
|
||||
return resolve(1000);
|
||||
}).then(value => {
|
||||
assert.equal(value, 1000, 'promise#resolve works ' + type);
|
||||
return reject('testing reject');
|
||||
}).then(null, reason => {
|
||||
assert.equal(reason, 'testing reject', 'promise#reject works ' + type);
|
||||
let deferred = defer();
|
||||
setTimeout(() => deferred.resolve('\\m/'), 10);
|
||||
return deferred.promise;
|
||||
}).then(value => {
|
||||
assert.equal(value, '\\m/', 'promise#defer works ' + type);
|
||||
return promised(x => x * x)(5);
|
||||
}).then(value => {
|
||||
assert.equal(value, 25, 'promise#promised works ' + type);
|
||||
}).then(done, assert.fail);
|
||||
}
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
|
@ -6,6 +6,7 @@ const file = require("sdk/io/file");
|
||||
const prefs = require("sdk/preferences/service");
|
||||
|
||||
const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota";
|
||||
const WRITE_PERIOD_PREF = "extensions.addon-sdk.simple-storage.writePeriod";
|
||||
|
||||
let {Cc,Ci} = require("chrome");
|
||||
|
||||
@ -18,6 +19,7 @@ let storeFile = Cc["@mozilla.org/file/directory_service;1"].
|
||||
storeFile.append("jetpack");
|
||||
storeFile.append(id);
|
||||
storeFile.append("simple-storage");
|
||||
file.mkpath(storeFile.path);
|
||||
storeFile.append("store.json");
|
||||
let storeFilename = storeFile.path;
|
||||
|
||||
@ -33,12 +35,13 @@ exports.testSetGet = function (assert, done) {
|
||||
// Load the module again and make sure the value stuck.
|
||||
loader = Loader(module);
|
||||
ss = loader.require("sdk/simple-storage");
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
file.remove(storeFilename);
|
||||
done();
|
||||
};
|
||||
assert.equal(ss.storage.foo, val, "Value should persist");
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.fail("Nothing should be written since `storage` was not changed.");
|
||||
};
|
||||
loader.unload();
|
||||
file.remove(storeFilename);
|
||||
done();
|
||||
};
|
||||
let val = "foo";
|
||||
ss.storage.foo = val;
|
||||
@ -104,6 +107,23 @@ exports.testEmpty = function (assert) {
|
||||
assert.ok(!file.exists(storeFilename), "Store file should not exist");
|
||||
};
|
||||
|
||||
exports.testStorageDataRecovery = function(assert) {
|
||||
const data = {
|
||||
a: true,
|
||||
b: [3, 13],
|
||||
c: "guilty!",
|
||||
d: { e: 1, f: 2 }
|
||||
};
|
||||
let stream = file.open(storeFilename, "w");
|
||||
stream.write(JSON.stringify(data));
|
||||
stream.close();
|
||||
let loader = Loader(module);
|
||||
let ss = loader.require("sdk/simple-storage");
|
||||
assert.deepEqual(ss.storage, data, "Recovered data should be the same as written");
|
||||
file.remove(storeFilename);
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports.testMalformed = function (assert) {
|
||||
let stream = file.open(storeFilename, "w");
|
||||
stream.write("i'm not json");
|
||||
@ -116,6 +136,7 @@ exports.testMalformed = function (assert) {
|
||||
break;
|
||||
}
|
||||
assert.ok(empty, "Malformed storage should cause root to be empty");
|
||||
file.remove(storeFilename);
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
@ -141,10 +162,11 @@ exports.testQuotaExceededHandle = function (assert, done) {
|
||||
assert.equal(ss.storage.x, 4, "x value should be correct");
|
||||
assert.equal(ss.storage.y, 5, "y value should be correct");
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
prefs.reset(QUOTA_PREF);
|
||||
done();
|
||||
assert.fail("Nothing should be written since `storage` was not changed.");
|
||||
};
|
||||
loader.unload();
|
||||
prefs.reset(QUOTA_PREF);
|
||||
done();
|
||||
};
|
||||
loader.unload();
|
||||
});
|
||||
@ -178,6 +200,9 @@ exports.testQuotaExceededNoHandle = function (assert, done) {
|
||||
assert.equal(ss.storage, val,
|
||||
"Over-quota value should not have been written, " +
|
||||
"old value should have persisted: " + ss.storage);
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.fail("Nothing should be written since `storage` was not changed.");
|
||||
};
|
||||
loader.unload();
|
||||
prefs.reset(QUOTA_PREF);
|
||||
done();
|
||||
@ -232,6 +257,184 @@ exports.testUninstall = function (assert, done) {
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
exports.testChangeInnerArray = function(assert, done) {
|
||||
prefs.set(WRITE_PERIOD_PREF, 10);
|
||||
|
||||
let expected = {
|
||||
x: [5, 7],
|
||||
y: [7, 28],
|
||||
z: [6, 2]
|
||||
};
|
||||
|
||||
// Load the module, set a value.
|
||||
let loader = Loader(module);
|
||||
let ss = loader.require("sdk/simple-storage");
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.ok(file.exists(storeFilename), "Store file should exist");
|
||||
|
||||
// Load the module again and check the result
|
||||
loader = Loader(module);
|
||||
ss = loader.require("sdk/simple-storage");
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
// Add a property
|
||||
ss.storage.x.push(["bar"]);
|
||||
expected.x.push(["bar"]);
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
// Modify a property
|
||||
ss.storage.y[0] = 42;
|
||||
expected.y[0] = 42;
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
// Delete a property
|
||||
delete ss.storage.z[1];
|
||||
delete expected.z[1];
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
// Modify the new inner-object
|
||||
ss.storage.x[2][0] = "baz";
|
||||
expected.x[2][0] = "baz";
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.fail("Nothing should be written since `storage` was not changed.");
|
||||
};
|
||||
loader.unload();
|
||||
|
||||
// Load the module again and check the result
|
||||
loader = Loader(module);
|
||||
ss = loader.require("sdk/simple-storage");
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
loader.unload();
|
||||
file.remove(storeFilename);
|
||||
prefs.reset(WRITE_PERIOD_PREF);
|
||||
done();
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ss.storage = {
|
||||
x: [5, 7],
|
||||
y: [7, 28],
|
||||
z: [6, 2]
|
||||
};
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
exports.testChangeInnerObject = function(assert, done) {
|
||||
prefs.set(WRITE_PERIOD_PREF, 10);
|
||||
|
||||
let expected = {
|
||||
x: {
|
||||
a: 5,
|
||||
b: 7
|
||||
},
|
||||
y: {
|
||||
c: 7,
|
||||
d: 28
|
||||
},
|
||||
z: {
|
||||
e: 6,
|
||||
f: 2
|
||||
}
|
||||
};
|
||||
|
||||
// Load the module, set a value.
|
||||
let loader = Loader(module);
|
||||
let ss = loader.require("sdk/simple-storage");
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.ok(file.exists(storeFilename), "Store file should exist");
|
||||
|
||||
// Load the module again and check the result
|
||||
loader = Loader(module);
|
||||
ss = loader.require("sdk/simple-storage");
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
// Add a property
|
||||
ss.storage.x.g = {foo: "bar"};
|
||||
expected.x.g = {foo: "bar"};
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
// Modify a property
|
||||
ss.storage.y.c = 42;
|
||||
expected.y.c = 42;
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
// Delete a property
|
||||
delete ss.storage.z.f;
|
||||
delete expected.z.f;
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
// Modify the new inner-object
|
||||
ss.storage.x.g.foo = "baz";
|
||||
expected.x.g.foo = "baz";
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.fail("Nothing should be written since `storage` was not changed.");
|
||||
};
|
||||
loader.unload();
|
||||
|
||||
// Load the module again and check the result
|
||||
loader = Loader(module);
|
||||
ss = loader.require("sdk/simple-storage");
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
loader.unload();
|
||||
file.remove(storeFilename);
|
||||
prefs.reset(WRITE_PERIOD_PREF);
|
||||
done();
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ss.storage = {
|
||||
x: {
|
||||
a: 5,
|
||||
b: 7
|
||||
},
|
||||
y: {
|
||||
c: 7,
|
||||
d: 28
|
||||
},
|
||||
z: {
|
||||
e: 6,
|
||||
f: 2
|
||||
}
|
||||
};
|
||||
assert.equal(JSON.stringify(ss.storage),
|
||||
JSON.stringify(expected), "Should see the expected object");
|
||||
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
exports.testSetNoSetRead = function (assert, done) {
|
||||
// Load the module, set a value.
|
||||
let loader = Loader(module);
|
||||
@ -250,12 +453,13 @@ exports.testSetNoSetRead = function (assert, done) {
|
||||
// Load the module a third time and make sure the value stuck.
|
||||
loader = Loader(module);
|
||||
ss = loader.require("sdk/simple-storage");
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
file.remove(storeFilename);
|
||||
done();
|
||||
};
|
||||
assert.equal(ss.storage.foo, val, "Value should persist");
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.fail("Nothing should be written since `storage` was not changed.");
|
||||
};
|
||||
loader.unload();
|
||||
file.remove(storeFilename);
|
||||
done();
|
||||
};
|
||||
let val = "foo";
|
||||
ss.storage.foo = val;
|
||||
@ -276,12 +480,13 @@ function setGetRoot(assert, done, val, compare) {
|
||||
// Load the module again and make sure the value stuck.
|
||||
loader = Loader(module);
|
||||
ss = loader.require("sdk/simple-storage");
|
||||
manager(loader).jsonStore.onWrite = function () {
|
||||
file.remove(storeFilename);
|
||||
done();
|
||||
};
|
||||
assert.ok(compare(ss.storage, val), "Value should persist");
|
||||
manager(loader).jsonStore.onWrite = function (storage) {
|
||||
assert.fail("Nothing should be written since `storage` was not changed.");
|
||||
};
|
||||
loader.unload();
|
||||
file.remove(storeFilename);
|
||||
done();
|
||||
};
|
||||
ss.storage = val;
|
||||
assert.ok(compare(ss.storage, val), "Value read should be value set");
|
||||
|
@ -2,13 +2,15 @@
|
||||
* 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";
|
||||
|
||||
const tabs = require("sdk/tabs"); // From addon-kit
|
||||
const windowUtils = require("sdk/deprecated/window-utils");
|
||||
const { getTabForWindow } = require('sdk/tabs/helpers');
|
||||
const app = require("sdk/system/xul-app");
|
||||
const { viewFor } = require("sdk/view/core");
|
||||
const { getTabId } = require("sdk/tabs/utils");
|
||||
const { modelFor } = require("sdk/model/core");
|
||||
const { getTabId, isTab } = require("sdk/tabs/utils");
|
||||
const { defer } = require("sdk/lang/functional");
|
||||
|
||||
// The primary test tab
|
||||
@ -152,6 +154,22 @@ exports["test viewFor(tab)"] = (assert, done) => {
|
||||
}));
|
||||
|
||||
tabs.open({ url: "about:mozilla" });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports["test modelFor(xulTab)"] = (assert, done) => {
|
||||
tabs.open({
|
||||
url: "about:mozilla",
|
||||
onReady: tab => {
|
||||
const view = viewFor(tab);
|
||||
assert.ok(view, "view is returned");
|
||||
assert.ok(isTab(view), "view is underlaying tab");
|
||||
assert.equal(getTabId(view), tab.id, "tab has a same id");
|
||||
assert.equal(modelFor(view), tab, "modelFor(view) is SDK tab");
|
||||
|
||||
tab.close(defer(done));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
require("test").run(exports);
|
||||
|
@ -48,12 +48,12 @@ exports["test LoaderWithHookedConsole"] = function (assert) {
|
||||
console.debug("5th");
|
||||
console.exception("6th");
|
||||
assert.equal(messages.length, 6, "Got all console messages");
|
||||
assert.deepEqual(messages[0], {type: "log", msg: "1st"}, "Got log");
|
||||
assert.deepEqual(messages[1], {type: "error", msg: "2nd"}, "Got error");
|
||||
assert.deepEqual(messages[2], {type: "warn", msg: "3rd"}, "Got warn");
|
||||
assert.deepEqual(messages[3], {type: "info", msg: "4th"}, "Got info");
|
||||
assert.deepEqual(messages[4], {type: "debug", msg: "5th"}, "Got debug");
|
||||
assert.deepEqual(messages[5], {type: "exception", msg: "6th"}, "Got exception");
|
||||
assert.deepEqual(messages[0], {type: "log", msg: "1st", innerID: null}, "Got log");
|
||||
assert.deepEqual(messages[1], {type: "error", msg: "2nd", innerID: null}, "Got error");
|
||||
assert.deepEqual(messages[2], {type: "warn", msg: "3rd", innerID: null}, "Got warn");
|
||||
assert.deepEqual(messages[3], {type: "info", msg: "4th", innerID: null}, "Got info");
|
||||
assert.deepEqual(messages[4], {type: "debug", msg: "5th", innerID: null}, "Got debug");
|
||||
assert.deepEqual(messages[5], {type: "exception", msg: "6th", innerID: null}, "Got exception");
|
||||
assert.equal(count, 6, "Called for all messages");
|
||||
};
|
||||
|
||||
|
@ -48,9 +48,14 @@ exports.testFromExceptionWithString = function(assert) {
|
||||
try {
|
||||
throw "foob";
|
||||
assert.fail("an exception should've been thrown");
|
||||
} catch (e if e == "foob") {
|
||||
var tb = traceback.fromException(e);
|
||||
assert.equal(tb.length, 0);
|
||||
} catch (e) {
|
||||
if (e == "foob") {
|
||||
var tb = traceback.fromException(e);
|
||||
assert.equal(tb.length, 0);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -65,11 +70,16 @@ exports.testFromExceptionWithError = function(assert) {
|
||||
try {
|
||||
throwError();
|
||||
assert.fail("an exception should've been thrown");
|
||||
} catch (e if e instanceof Error) {
|
||||
var tb = traceback.fromException(e);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
var tb = traceback.fromException(e);
|
||||
|
||||
var xulApp = require("sdk/system/xul-app");
|
||||
assert.equal(tb.slice(-1)[0].name, "throwError");
|
||||
var xulApp = require("sdk/system/xul-app");
|
||||
assert.equal(tb.slice(-1)[0].name, "throwError");
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -77,9 +87,14 @@ exports.testFromExceptionWithNsIException = function(assert) {
|
||||
try {
|
||||
throwNsIException();
|
||||
assert.fail("an exception should've been thrown");
|
||||
} catch (e if e.result == Cr.NS_ERROR_MALFORMED_URI) {
|
||||
var tb = traceback.fromException(e);
|
||||
assert.equal(tb[tb.length - 1].name, "throwNsIException");
|
||||
} catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_MALFORMED_URI) {
|
||||
var tb = traceback.fromException(e);
|
||||
assert.equal(tb[tb.length - 1].name, "throwNsIException");
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,7 @@ module.metadata = {
|
||||
}
|
||||
};
|
||||
|
||||
const { Cu } = require("chrome");
|
||||
const { Frame } = require("sdk/ui/frame");
|
||||
const { Toolbar } = require("sdk/ui/toolbar");
|
||||
const { Loader } = require("sdk/test/loader");
|
||||
@ -16,15 +17,29 @@ const { identify } = require("sdk/ui/id");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
const { getMostRecentBrowserWindow, open } = require("sdk/window/utils");
|
||||
const { ready, loaded, close } = require("sdk/window/helpers");
|
||||
const { defer } = require("sdk/core/promise");
|
||||
const { defer, all } = require("sdk/core/promise");
|
||||
const { send } = require("sdk/event/utils");
|
||||
const { object } = require("sdk/util/sequence");
|
||||
const { OutputPort } = require("sdk/output/system");
|
||||
const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
const output = new OutputPort({ id: "toolbar-change" });
|
||||
|
||||
const wait = (toolbar, event) => {
|
||||
const wait = (toolbar, event, times) => {
|
||||
let { promise, resolve } = defer();
|
||||
toolbar.once(event, resolve);
|
||||
if (times) {
|
||||
let resolveArray = [];
|
||||
let counter = 0;
|
||||
toolbar.on(event, function onEvent (e) {
|
||||
resolveArray.push(e);
|
||||
if (++counter === times) {
|
||||
toolbar.off(event, onEvent);
|
||||
resolve(resolveArray);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
toolbar.once(event, resolve);
|
||||
}
|
||||
return promise;
|
||||
};
|
||||
|
||||
@ -36,7 +51,9 @@ const stateEventsFor = frame =>
|
||||
const isAttached = ({id}, window=getMostRecentBrowserWindow()) =>
|
||||
!!window.document.getElementById(id);
|
||||
|
||||
exports["test frame API"] = function*(assert) {
|
||||
// Use `Task.spawn` instead of `Task.async` because the returned function does not contain
|
||||
// a length for the test harness to determine whether the test should be executed
|
||||
exports["test frame API"] = function* (assert) {
|
||||
const url = "data:text/html,frame-api";
|
||||
assert.throws(() => new Frame(),
|
||||
/The `options.url`/,
|
||||
@ -86,8 +103,7 @@ exports["test frame API"] = function*(assert) {
|
||||
f3.destroy();
|
||||
};
|
||||
|
||||
|
||||
exports["test frame in toolbar"] = function*(assert) {
|
||||
exports["test frame in toolbar"] = function* (assert) {
|
||||
const assertEvent = (event, type) => {
|
||||
assert.ok(event, "`" + type + "` event was dispatched");
|
||||
assert.equal(event.type, type, "event.type is: " + type);
|
||||
@ -116,7 +132,6 @@ exports["test frame in toolbar"] = function*(assert) {
|
||||
const [a2, r2, l2] = stateEventsFor(f1);
|
||||
const w2 = open();
|
||||
|
||||
|
||||
assertEvent((yield a2), "attach");
|
||||
assert.ok(isAttached(f1, w2), "frame is in the window#2");
|
||||
assertEvent((yield r2), "ready");
|
||||
@ -126,7 +141,6 @@ exports["test frame in toolbar"] = function*(assert) {
|
||||
|
||||
const d1 = wait(f1, "detach");
|
||||
yield close(w2);
|
||||
|
||||
assertEvent((yield d1), "detach");
|
||||
assert.pass("frame detached when window is closed");
|
||||
|
||||
@ -138,7 +152,7 @@ exports["test frame in toolbar"] = function*(assert) {
|
||||
};
|
||||
|
||||
|
||||
exports["test host to content messaging"] = function*(assert) {
|
||||
exports["test host to content messaging"] = function* (assert) {
|
||||
const url = "data:text/html,<script>new " + function() {
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.data === "ping!")
|
||||
@ -159,7 +173,7 @@ exports["test host to content messaging"] = function*(assert) {
|
||||
};
|
||||
|
||||
|
||||
exports["test content to host messaging"] = function*(assert) {
|
||||
exports["test content to host messaging"] = function* (assert) {
|
||||
const url = "data:text/html,<script>new " + function() {
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.data === "pong!")
|
||||
@ -182,10 +196,11 @@ exports["test content to host messaging"] = function*(assert) {
|
||||
|
||||
t1.destroy();
|
||||
yield wait(t1, "detach");
|
||||
|
||||
};
|
||||
|
||||
|
||||
exports["test direct messaging"] = function*(assert) {
|
||||
exports["test direct messaging"] = function* (assert) {
|
||||
const url = "data:text/html,<script>new " + function() {
|
||||
var n = 0;
|
||||
window.addEventListener("message", (event) => {
|
||||
@ -208,31 +223,30 @@ exports["test direct messaging"] = function*(assert) {
|
||||
yield wait(f1, "ready");
|
||||
assert.pass("document loaded in window#2");
|
||||
|
||||
let messages = wait(f1, "message", 2);
|
||||
f1.postMessage("inc", f1.origin);
|
||||
f1.postMessage("print", f1.origin);
|
||||
|
||||
const e1 = yield wait(f1, "message");
|
||||
const [e1, e2] = yield messages;
|
||||
assert.deepEqual(e1.data, {n: 1}, "received message from window#1");
|
||||
|
||||
const e2 = yield wait(f1, "message");
|
||||
assert.deepEqual(e2.data, {n: 1}, "received message from window#2");
|
||||
|
||||
let message = wait(f1, "message");
|
||||
e1.source.postMessage("inc", e1.origin);
|
||||
|
||||
e1.source.postMessage("print", e1.origin);
|
||||
|
||||
const e3 = yield wait(f1, "message");
|
||||
const e3 = yield message;
|
||||
assert.deepEqual(e3.data, {n: 2}, "state changed in window#1");
|
||||
|
||||
let message = wait(f1, "message");
|
||||
e2.source.postMessage("print", e2.origin);
|
||||
const e4 = yield wait(f1, "message");
|
||||
|
||||
yield message;
|
||||
assert.deepEqual(e2.data, {n:1}, "window#2 didn't received inc message");
|
||||
|
||||
yield close(w2);
|
||||
t1.destroy();
|
||||
|
||||
yield wait(t1, "detach");
|
||||
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
|
@ -829,7 +829,7 @@ exports.testShowingInOneWindowDoesNotAffectOtherWindows = function(assert, done)
|
||||
}, assert.fail);
|
||||
}
|
||||
|
||||
exports.testHidingAHiddenSidebarRejects = function(assert) {
|
||||
exports.testHidingAHiddenSidebarRejects = function(assert, done) {
|
||||
const { Sidebar } = require('sdk/ui/sidebar');
|
||||
let testName = 'testHidingAHiddenSidebarRejects';
|
||||
let url = 'data:text/html;charset=utf-8,'+testName;
|
||||
@ -1385,7 +1385,7 @@ exports.testEventListeners = function(assert, done) {
|
||||
onHide.resolve();
|
||||
});
|
||||
|
||||
all(constructorOnShow.promise,
|
||||
all([constructorOnShow.promise,
|
||||
constructorOnAttach.promise,
|
||||
constructorOnReady.promise,
|
||||
constructorOnHide.promise,
|
||||
@ -1396,7 +1396,7 @@ exports.testEventListeners = function(assert, done) {
|
||||
onShow.promise,
|
||||
onAttach.promise,
|
||||
onReady.promise,
|
||||
onHide.promise).then(function() {
|
||||
onHide.promise]).then(function() {
|
||||
assert.equal(eventListenerOrder.join(), [
|
||||
'onAttach',
|
||||
'once attach',
|
||||
@ -1436,31 +1436,22 @@ exports.testAttachDoesNotEmitWhenShown = function(assert, done) {
|
||||
}
|
||||
|
||||
if (++count == 1) {
|
||||
setTimeout(function() {
|
||||
let shown = false;
|
||||
let endShownTest = false;
|
||||
sidebar.once('show', function() {
|
||||
assert.pass('shown was emitted');
|
||||
shown = !endShownTest && true;
|
||||
});
|
||||
setImmediate(function() {
|
||||
let shownFired = 0;
|
||||
let onShow = () => shownFired++;
|
||||
sidebar.on('show', onShow);
|
||||
|
||||
sidebar.show().then(function() {
|
||||
assert.pass('calling hide');
|
||||
sidebar.hide();
|
||||
}).then(function() {
|
||||
endShownTest = true;
|
||||
|
||||
setTimeout(function() {
|
||||
sidebar.show().then(function() {
|
||||
assert.ok(!shown, 'show did not emit');
|
||||
|
||||
sidebar.hide().then(function() {
|
||||
sidebar.destroy();
|
||||
done();
|
||||
}).then(null, assert.fail);
|
||||
})
|
||||
})
|
||||
}).then(null, assert.fail);
|
||||
sidebar.show()
|
||||
.then(() => assert.equal(shownFired, 0, 'shown should not be fired again when already showing from after attach'))
|
||||
.then(sidebar.hide.bind(sidebar))
|
||||
.then(sidebar.show.bind(sidebar))
|
||||
.then(() => assert.equal(shownFired, 1, 'shown was emitted when `show` called after being hidden'))
|
||||
.then(sidebar.show.bind(sidebar))
|
||||
.then(() => {
|
||||
assert.equal(shownFired, 1, 'shown was not emitted again if already being shown');
|
||||
sidebar.off('show', onShow);
|
||||
sidebar.destroy();
|
||||
}).catch(assert.fail).then(done);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,10 @@
|
||||
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { browserWindows } = require('sdk/windows');
|
||||
const { viewFor } = require('sdk/view/core');
|
||||
const { modelFor } = require('sdk/model/core');
|
||||
const { Ci } = require("chrome");
|
||||
const { isBrowser, getWindowTitle } = require("sdk/window/utils");
|
||||
|
||||
// TEST: browserWindows Iterator
|
||||
exports.testBrowserWindowsIterator = function(assert) {
|
||||
@ -57,4 +60,37 @@ exports.testWindowActivateMethod_simple = function(assert) {
|
||||
'Active tab is active after window.activate() call');
|
||||
};
|
||||
|
||||
|
||||
exports["test getView(window)"] = function(assert, done) {
|
||||
browserWindows.once("open", window => {
|
||||
const view = viewFor(window);
|
||||
|
||||
assert.ok(view instanceof Ci.nsIDOMWindow, "view is a window");
|
||||
assert.ok(isBrowser(view), "view is a browser window");
|
||||
assert.equal(getWindowTitle(view), window.title,
|
||||
"window has a right title");
|
||||
|
||||
window.close(done);
|
||||
});
|
||||
|
||||
|
||||
browserWindows.open({ url: "data:text/html;charset=utf-8,<title>yo</title>" });
|
||||
};
|
||||
|
||||
|
||||
exports["test modelFor(window)"] = function(assert, done) {
|
||||
browserWindows.once("open", window => {
|
||||
const view = viewFor(window);
|
||||
|
||||
assert.ok(view instanceof Ci.nsIDOMWindow, "view is a window");
|
||||
assert.ok(isBrowser(view), "view is a browser window");
|
||||
assert.ok(modelFor(view) === window, "modelFor(browserWindow) is SDK window");
|
||||
|
||||
window.close(done);
|
||||
});
|
||||
|
||||
|
||||
browserWindows.open({ url: "data:text/html;charset=utf-8,<title>yo</title>" });
|
||||
};
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
Loading…
Reference in New Issue
Block a user