diff --git a/addon-sdk/moz.build b/addon-sdk/moz.build
index 7ae13484ec31..2186e00d2587 100644
--- a/addon-sdk/moz.build
+++ b/addon-sdk/moz.build
@@ -29,6 +29,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
EXTRA_JS_MODULES.commonjs.sdk.deprecated += [
'source/lib/sdk/deprecated/api-utils.js',
+ 'source/lib/sdk/deprecated/memory.js',
'source/lib/sdk/deprecated/sync-worker.js',
'source/lib/sdk/deprecated/unit-test-finder.js',
'source/lib/sdk/deprecated/unit-test.js',
@@ -257,10 +258,6 @@ EXTRA_JS_MODULES.commonjs.sdk.content += [
'source/lib/sdk/content/worker.js',
]
-EXTRA_JS_MODULES.commonjs.sdk.content.sandbox += [
- 'source/lib/sdk/content/sandbox/events.js',
-]
-
EXTRA_JS_MODULES.commonjs.sdk['context-menu'] += [
'source/lib/sdk/context-menu/context.js',
'source/lib/sdk/context-menu/core.js',
@@ -456,6 +453,7 @@ EXTRA_JS_MODULES.commonjs.sdk.url += [
EXTRA_JS_MODULES.commonjs.sdk.util += [
'source/lib/sdk/util/array.js',
+ 'source/lib/sdk/util/bond.js',
'source/lib/sdk/util/collection.js',
'source/lib/sdk/util/contract.js',
'source/lib/sdk/util/deprecate.js',
diff --git a/addon-sdk/source/.travis.yml b/addon-sdk/source/.travis.yml
index 287b62a4f8b6..d74bec240146 100644
--- a/addon-sdk/source/.travis.yml
+++ b/addon-sdk/source/.travis.yml
@@ -1,7 +1,7 @@
sudo: false
language: node_js
node_js:
- - "0.12"
+ - "0.10"
env:
- JPM_FX_DEBUG=0
diff --git a/addon-sdk/source/bin/jpm-test.js b/addon-sdk/source/bin/jpm-test.js
index f22a552ea7ba..cc06e8c32172 100644
--- a/addon-sdk/source/bin/jpm-test.js
+++ b/addon-sdk/source/bin/jpm-test.js
@@ -17,13 +17,12 @@ exports.run = function(type) {
return new Promise(function(resolve) {
type = type || "";
[
- (!isDebug && /^(firefox-bin)?$/.test(type)) && require.resolve("../bin/node-scripts/test.firefox-bin"),
+ (!isDebug && /^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"),
+ (!isDebug && /^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"),
+ (/^(examples)?$/.test(type)) && require.resolve("../bin/node-scripts/test.examples"),
(!isDebug && /^(docs)?$/.test(type)) && require.resolve("../bin/node-scripts/test.docs"),
(!isDebug && /^(ini)?$/.test(type)) && require.resolve("../bin/node-scripts/test.ini"),
- (/^(examples)?$/.test(type)) && require.resolve("../bin/node-scripts/test.examples"),
- (!isDebug && /^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"),
- (!isDebug && /^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"),
- ].forEach(function(filepath) {
+ ].sort().forEach(function(filepath) {
filepath && mocha.addFile(filepath);
})
diff --git a/addon-sdk/source/bin/node-scripts/test.firefox-bin.js b/addon-sdk/source/bin/node-scripts/test.firefox-bin.js
deleted file mode 100644
index 2570dae20f89..000000000000
--- a/addon-sdk/source/bin/node-scripts/test.firefox-bin.js
+++ /dev/null
@@ -1,37 +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";
-
-var fs = require("fs");
-var Promise = require("promise");
-var chai = require("chai");
-var expect = chai.expect;
-var normalizeBinary = require("fx-runner/lib/utils").normalizeBinary;
-
-//var firefox_binary = process.env["JPM_FIREFOX_BINARY"] || normalizeBinary("nightly");
-
-describe("Checking Firefox binary", function () {
-
- it("using matching fx-runner version with jpm", function () {
- var sdkPackageJSON = require("../../package.json");
- var jpmPackageINI = require("jpm/package.json");
- expect(sdkPackageJSON.devDependencies["fx-runner"]).to.be.equal(jpmPackageINI.dependencies["fx-runner"]);
- });
-
- it("exists", function (done) {
- var useEnvVar = new Promise(function(resolve) {
- resolve(process.env["JPM_FIREFOX_BINARY"]);
- });
-
- var firefox_binary = process.env["JPM_FIREFOX_BINARY"] ? useEnvVar : normalizeBinary("nightly");
- firefox_binary.then(function(path) {
- expect(path).to.be.ok;
- fs.exists(path, function (exists) {
- expect(exists).to.be.ok;
- done();
- });
- })
- });
-
-});
diff --git a/addon-sdk/source/bin/node-scripts/test.ini.js b/addon-sdk/source/bin/node-scripts/test.ini.js
index 07bd15d1fde5..5b8f76e7af88 100644
--- a/addon-sdk/source/bin/node-scripts/test.ini.js
+++ b/addon-sdk/source/bin/node-scripts/test.ini.js
@@ -11,7 +11,6 @@ var expect = chai.expect;
var ini = require("./update-ini");
var addonINI = path.resolve("./test/addons/jetpack-addon.ini");
-var packageINI = path.resolve("./test/jetpack-package.ini");
describe("Checking ini files", function () {
@@ -21,10 +20,7 @@ describe("Checking ini files", function () {
if (err) {
throw err;
}
- // filter comments
- var text = data.toString().split("\n").filter(function(line) {
- return !/^\s*#/.test(line);
- }).join("\n");
+ var text = data.toString();
var expected = "";
ini.makeAddonIniContent()
@@ -32,32 +28,7 @@ describe("Checking ini files", function () {
expected = contents;
setTimeout(function end() {
- expect(text.trim()).to.be.equal(expected.trim());
- done();
- });
- });
- });
-
- });
-
- it("Check test/jetpack-package.ini", function (done) {
-
- fs.readFile(packageINI, function (err, data) {
- if (err) {
- throw err;
- }
- // filter comments
- var text = data.toString().split("\n").filter(function(line) {
- return !/^\s*#/.test(line);
- }).join("\n");
- var expected = "";
-
- ini.makePackageIniContent()
- .then(function(contents) {
- expected = contents;
-
- setTimeout(function end() {
- expect(text.trim()).to.be.equal(expected.trim());
+ expect(expected.trim()).to.be.equal(text.trim());
done();
});
});
diff --git a/addon-sdk/source/bin/node-scripts/update-ini.js b/addon-sdk/source/bin/node-scripts/update-ini.js
index a433615b45dd..250d7da01ddf 100644
--- a/addon-sdk/source/bin/node-scripts/update-ini.js
+++ b/addon-sdk/source/bin/node-scripts/update-ini.js
@@ -11,15 +11,6 @@ var parser = require("ini-parser");
var addonINI = path.resolve("./test/addons/jetpack-addon.ini");
var addonsDir = path.resolve("./test/addons/");
-var packageINI = path.resolve("./test/jetpack-package.ini");
-var packageDir = path.resolve("./test/");
-var packageIgnorables = [ "addons", "preferences" ];
-var packageSupportFiles = [
- "fixtures.js",
- "pagemod-test-helpers.js",
- "test-context-menu.html",
- "util.js"
-]
function updateAddonINI() {
return new Promise(function(resolve) {
@@ -41,18 +32,16 @@ function makeAddonIniContent() {
var result = {};
fs.readdir(addonsDir, function(err, files) {
- // get a list of folders
var folders = files.filter(function(file) {
return fs.statSync(path.resolve(addonsDir, file)).isDirectory();
}).sort();
- // copy any related data from the existing ini
folders.forEach(function(folder) {
var oldData = data[folder + ".xpi"];
result[folder] = oldData ? oldData : {};
});
- // build a new ini file
+ // build ini file
var contents = [];
Object.keys(result).sort().forEach(function(key) {
contents.push("[" + key + ".xpi]");
@@ -67,76 +56,3 @@ function makeAddonIniContent() {
});
}
exports.makeAddonIniContent = makeAddonIniContent;
-
-function makePackageIniContent() {
- return new Promise(function(resolve) {
- var data = parser.parse(fs.readFileSync(packageINI, { encoding: "utf8" }).toString());
- var result = {};
-
- fs.readdir(packageDir, function(err, files) {
- // get a list of folders
- var folders = files.filter(function(file) {
- var ignore = (packageIgnorables.indexOf(file) >= 0);
- var isDir = fs.statSync(path.resolve(packageDir, file)).isDirectory();
- return (isDir && !ignore);
- }).sort();
-
- // get a list of "test-"" files
- var files = files.filter(function(file) {
- var ignore = !/^test\-.*\.js$/i.test(file);
- var isDir = fs.statSync(path.resolve(packageDir, file)).isDirectory();
- return (!isDir && !ignore);
- }).sort();
-
- // get a list of the support files
- var support_files = packageSupportFiles.map(function(file) {
- return " " + file;
- });
- folders.forEach(function(folder) {
- support_files.push(" " + folder + "/**");
- });
- support_files = support_files.sort();
-
- // copy any related data from the existing ini
- files.forEach(function(file) {
- var oldData = data[file];
- result[file] = oldData ? oldData : {};
- });
-
- // build a new ini file
- var contents = [
- "[DEFAULT]",
- "support-files ="
- ];
- support_files.forEach(function(support_file) {
- contents.push(support_file);
- });
- contents.push("");
-
- Object.keys(result).sort().forEach(function(key) {
- contents.push("[" + key + "]");
- Object.keys(result[key]).forEach(function(dataKey) {
- contents.push(dataKey + " = " + result[key][dataKey]);
- });
- });
- contents = contents.join("\n") + "\n";
-
- return resolve(contents);
- });
- });
-}
-exports.makePackageIniContent = makePackageIniContent;
-
-function updatePackageINI() {
- return new Promise(function(resolve) {
- console.log("Start updating " + packageINI);
-
- makeAddonIniContent().
- then(function(contents) {
- fs.writeFileSync(packageINI, contents, { encoding: "utf8" });
- console.log("Done updating " + packageINI);
- resolve();
- });
- })
-}
-exports.updatePackageINI = updatePackageINI;
diff --git a/addon-sdk/source/bin/node-scripts/utils.js b/addon-sdk/source/bin/node-scripts/utils.js
index 1d7f94474cf9..9cb47d04e235 100644
--- a/addon-sdk/source/bin/node-scripts/utils.js
+++ b/addon-sdk/source/bin/node-scripts/utils.js
@@ -65,9 +65,6 @@ function run (cmd, options, p) {
if (p) {
proc.stdout.pipe(p.stdout);
}
- else if (!isDebug) {
- proc.stdout.pipe(DEFAULT_PROCESS.stdout);
- }
else {
proc.stdout.on("data", function (data) {
data = (data || "") + "";
diff --git a/addon-sdk/source/gulpfile.js b/addon-sdk/source/gulpfile.js
index 4020dd9d49eb..362ef11c362f 100644
--- a/addon-sdk/source/gulpfile.js
+++ b/addon-sdk/source/gulpfile.js
@@ -28,11 +28,7 @@ gulp.task('test:modules', function(done) {
});
gulp.task('test:ini', function(done) {
- require("./bin/jpm-test").run("ini").catch(console.error).then(done);
-});
-
-gulp.task('test:firefox-bin', function(done) {
- require("./bin/jpm-test").run("firefox-bin").catch(console.error).then(done);
+ test("ini").catch(console.error).then(done);
});
gulp.task('patch:clean', function(done) {
@@ -42,3 +38,7 @@ gulp.task('patch:clean', function(done) {
gulp.task('patch:apply', function(done) {
patch.apply().catch(console.error).then(done);
});
+
+gulp.task('update:ini', function(done) {
+ ini.updateAddonINI().catch(console.error).then(done);
+});
diff --git a/addon-sdk/source/lib/sdk/console/traceback.js b/addon-sdk/source/lib/sdk/console/traceback.js
index be0fb7b94ff6..93e387b2585a 100644
--- a/addon-sdk/source/lib/sdk/console/traceback.js
+++ b/addon-sdk/source/lib/sdk/console/traceback.js
@@ -1,16 +1,19 @@
/* 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 { Ci, components } = require("chrome");
+const { Cc, Ci, components } = require("chrome");
const { parseStack, sourceURI } = require("toolkit/loader");
const { readURISync } = require("../net/url");
+exports.sourceURI = sourceURI
+
function safeGetFileLine(path, line) {
try {
var scheme = require("../url").URL(path).scheme;
diff --git a/addon-sdk/source/lib/sdk/content/sandbox.js b/addon-sdk/source/lib/sdk/content/sandbox.js
index 4a66eab53b9e..503c48c67c1b 100644
--- a/addon-sdk/source/lib/sdk/content/sandbox.js
+++ b/addon-sdk/source/lib/sdk/content/sandbox.js
@@ -10,7 +10,6 @@ module.metadata = {
const { Class } = require('../core/heritage');
const { EventTarget } = require('../event/target');
const { on, off, emit } = require('../event/core');
-const { events } = require('./sandbox/events');
const { requiresAddonGlobal } = require('./utils');
const { delay: async } = require('../lang/functional');
const { Ci, Cu, Cc } = require('chrome');
@@ -21,7 +20,8 @@ const { merge } = require('../util/object');
const { getTabForContentWindow } = require('../tabs/utils');
const { getInnerId } = require('../window/utils');
const { PlainTextConsole } = require('../console/plain-text');
-const { data } = require('../self');const { isChildLoader } = require('../remote/core');
+const { data } = require('../self');
+const { isChildLoader } = require('../remote/core');
// WeakMap of sandboxes so we can access private values
const sandboxes = new WeakMap();
@@ -166,7 +166,6 @@ const WorkerSandbox = Class({
get top() top,
get parent() parent
});
-
// Use the Greasemonkey naming convention to provide access to the
// unwrapped window object so the content script can access document
// JavaScript values.
@@ -262,11 +261,6 @@ const WorkerSandbox = Class({
win.console = con;
};
- emit(events, "content-script-before-inserted", {
- window: window,
- worker: worker
- });
-
// The order of `contentScriptFile` and `contentScript` evaluation is
// intentional, so programs can load libraries like jQuery from script URLs
// and use them in scripts.
@@ -279,7 +273,6 @@ const WorkerSandbox = Class({
if (contentScriptFile)
importScripts.apply(null, [this].concat(contentScriptFile));
-
if (contentScript) {
evaluateIn(
this,
diff --git a/addon-sdk/source/lib/sdk/deprecated/memory.js b/addon-sdk/source/lib/sdk/deprecated/memory.js
new file mode 100644
index 000000000000..b2aa48e888e4
--- /dev/null
+++ b/addon-sdk/source/lib/sdk/deprecated/memory.js
@@ -0,0 +1,129 @@
+/* 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": "deprecated"
+};
+
+const { Cc, Ci, Cu, components } = require("chrome");
+const { when: unload } = require("../system/unload")
+
+var trackedObjects = {};
+const Compacter = {
+ notify: function() {
+ var newTrackedObjects = {};
+
+ for (let name in trackedObjects) {
+ let oldBin = trackedObjects[name];
+ let newBin = [];
+ let strongRefs = [];
+
+ for (let i = 0, l = oldBin.length; i < l; i++) {
+ let strongRef = oldBin[i].weakref.get();
+
+ if (strongRef && strongRefs.indexOf(strongRef) == -1) {
+ strongRefs.push(strongRef);
+ newBin.push(oldBin[i]);
+ }
+ }
+
+ if (newBin.length)
+ newTrackedObjects[name] = newBin;
+ }
+
+ trackedObjects = newTrackedObjects;
+ }
+};
+
+var timer = Cc["@mozilla.org/timer;1"]
+ .createInstance(Ci.nsITimer);
+timer.initWithCallback(Compacter,
+ 5000,
+ Ci.nsITimer.TYPE_REPEATING_SLACK);
+
+function track(object, bin, stackFrameNumber) {
+ var frame = components.stack.caller;
+ var weakref = Cu.getWeakReference(object);
+
+ if (!bin && 'constructor' in object)
+ bin = object.constructor.name;
+ if (bin == "Object")
+ bin = frame.name;
+ if (!bin)
+ bin = "generic";
+ if (!(bin in trackedObjects))
+ trackedObjects[bin] = [];
+
+ if (stackFrameNumber > 0)
+ for (var i = 0; i < stackFrameNumber; i++)
+ frame = frame.caller;
+
+ trackedObjects[bin].push({weakref: weakref,
+ created: new Date(),
+ filename: frame.filename,
+ lineNo: frame.lineNumber,
+ bin: bin});
+}
+exports.track = track;
+
+var getBins = exports.getBins = function getBins() {
+ var names = [];
+ for (let name in trackedObjects)
+ names.push(name);
+ return names;
+};
+
+function getObjects(bin) {
+ var results = [];
+
+ function getLiveObjectsInBin(bin) {
+ for (let i = 0, l = bin.length; i < l; i++) {
+ let object = bin[i].weakref.get();
+
+ if (object) {
+ results.push(bin[i]);
+ }
+ }
+ }
+
+ if (bin) {
+ if (bin in trackedObjects)
+ getLiveObjectsInBin(trackedObjects[bin]);
+ }
+ else {
+ for (let name in trackedObjects)
+ getLiveObjectsInBin(trackedObjects[name]);
+ }
+
+ return results;
+}
+exports.getObjects = getObjects;
+
+function gc() {
+ // Components.utils.forceGC() doesn't currently perform
+ // cycle collection, which means that e.g. DOM elements
+ // won't be collected by it. Fortunately, there are
+ // other ways...
+ var test_utils = Cc["@mozilla.org/appshell/appShellService;1"]
+ .getService(Ci.nsIAppShellService)
+ .hiddenDOMWindow
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ test_utils.garbageCollect();
+ // Clean metadata for dead objects
+ Compacter.notify();
+ // Not sure why, but sometimes it appears that we don't get
+ // them all with just one CC, so let's do it again.
+ test_utils.garbageCollect();
+};
+exports.gc = gc;
+
+unload(_ => {
+ trackedObjects = {};
+ if (timer) {
+ timer.cancel();
+ timer = null;
+ }
+});
diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
index 518d813df4dc..2f062b5b3574 100644
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
@@ -8,6 +8,7 @@ module.metadata = {
};
const file = require("../io/file");
+const memory = require('./memory');
const { Loader } = require("../test/loader");
const { isNative } = require('@loader/options');
@@ -131,6 +132,7 @@ let loader = Loader(module);
const NOT_TESTS = ['setup', 'teardown'];
var TestFinder = exports.TestFinder = function TestFinder(options) {
+ memory.track(this);
this.filter = options.filter;
this.testInProcess = options.testInProcess === false ? false : true;
this.testOutOfProcess = options.testOutOfProcess === true ? true : false;
diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test.js b/addon-sdk/source/lib/sdk/deprecated/unit-test.js
index b93001971ced..976472f5a824 100644
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js
@@ -7,6 +7,7 @@ module.metadata = {
"stability": "deprecated"
};
+const memory = require("./memory");
const timer = require("../timers");
const cfxArgs = require("../test/options");
const { getTabs, closeTab, getURI, getTabId, getSelectedTab } = require("../tabs/utils");
@@ -46,6 +47,7 @@ const TestRunner = function TestRunner(options) {
this.fs = options.fs;
this.console = options.console || console;
+ memory.track(this);
this.passed = 0;
this.failed = 0;
this.testRunSummary = [];
@@ -281,46 +283,40 @@ TestRunner.prototype = {
}
this.isDone = true;
- this.pass("This test is done.");
-
if (this.test.teardown) {
this.test.teardown(this);
}
-
if (this.waitTimeout !== null) {
timer.clearTimeout(this.waitTimeout);
this.waitTimeout = null;
}
-
// Do not leave any callback set when calling to `waitUntil`
this.waitUntilCallback = null;
if (this.test.passed == 0 && this.test.failed == 0) {
this._logTestFailed("empty test");
-
if ("testMessage" in this.console) {
this.console.testMessage(false, false, this.test.name, "Empty test");
}
else {
this.console.error("fail:", "Empty test")
}
-
this.failed++;
this.test.failed++;
}
let wins = windows(null, { includePrivate: true });
- let winPromises = wins.map(win => {
- return new Promise(resolve => {
- if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) {
- resolve()
- }
- else {
- win.addEventListener("DOMContentLoaded", function onLoad() {
- win.removeEventListener("DOMContentLoaded", onLoad, false);
- resolve();
- }, false);
- }
- });
+ let winPromises = wins.map(win => {
+ let { promise, resolve } = defer();
+ if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) {
+ resolve()
+ }
+ else {
+ win.addEventListener("DOMContentLoaded", function onLoad() {
+ win.removeEventListener("DOMContentLoaded", onLoad, false);
+ resolve();
+ }, false);
+ }
+ return promise;
});
PromiseDebugging.flushUncaughtErrors();
@@ -362,17 +358,9 @@ TestRunner.prototype = {
}
}
- return failure;
- }).
- then(failure => {
- if (!failure) {
- this.pass("There was a clean UI.");
- return null;
- }
- return cleanUI().then(() => {
- this.pass("There is a clean UI.");
- });
+ return null;
}).
+ then(cleanUI).
then(() => {
this.testRunSummary.push({
name: this.test.name,
diff --git a/addon-sdk/source/lib/sdk/io/text-streams.js b/addon-sdk/source/lib/sdk/io/text-streams.js
index ed4ec4972b29..7a385cf03c49 100644
--- a/addon-sdk/source/lib/sdk/io/text-streams.js
+++ b/addon-sdk/source/lib/sdk/io/text-streams.js
@@ -1,15 +1,17 @@
/* 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 { Cc, Ci, Cu, components } = require("chrome");
-const { ensure } = require("../system/unload");
-const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
+const {Cc,Ci,Cu,components} = require("chrome");
+var NetUtil = {};
+Cu.import("resource://gre/modules/NetUtil.jsm", NetUtil);
+NetUtil = NetUtil.NetUtil;
// NetUtil.asyncCopy() uses this buffer length, and since we call it, for best
// performance we use it, too.
@@ -17,6 +19,8 @@ const BUFFER_BYTE_LEN = 0x8000;
const PR_UINT32_MAX = 0xffffffff;
const DEFAULT_CHARSET = "UTF-8";
+exports.TextReader = TextReader;
+exports.TextWriter = TextWriter;
/**
* An input stream that reads text from a backing stream using a given text
@@ -31,6 +35,7 @@ const DEFAULT_CHARSET = "UTF-8";
* documentation on how to determine other valid values for this.
*/
function TextReader(inputStream, charset) {
+ const self = this;
charset = checkCharset(charset);
let stream = Cc["@mozilla.org/intl/converter-input-stream;1"].
@@ -84,7 +89,6 @@ function TextReader(inputStream, charset) {
return str;
};
}
-exports.TextReader = TextReader;
/**
* A buffered output stream that writes text to a backing stream using a given
@@ -99,6 +103,7 @@ exports.TextReader = TextReader;
* for documentation on how to determine other valid values for this.
*/
function TextWriter(outputStream, charset) {
+ const self = this;
charset = checkCharset(charset);
let stream = outputStream;
@@ -164,7 +169,7 @@ function TextWriter(outputStream, charset) {
this.writeAsync = function TextWriter_writeAsync(str, callback) {
manager.ensureOpened();
let istream = uconv.convertToInputStream(str);
- NetUtil.asyncCopy(istream, stream, (result) => {
+ NetUtil.asyncCopy(istream, stream, function (result) {
let err = components.isSuccessCode(result) ? undefined :
new Error("An error occured while writing to the stream: " + result);
if (err)
@@ -175,7 +180,7 @@ function TextWriter(outputStream, charset) {
if (typeof(callback) === "function") {
try {
- callback.call(this, err);
+ callback.call(self, err);
}
catch (exc) {
console.exception(exc);
@@ -184,32 +189,34 @@ function TextWriter(outputStream, charset) {
});
};
}
-exports.TextWriter = TextWriter;
// This manages the lifetime of stream, a TextReader or TextWriter. It defines
// closed and close() on stream and registers an unload listener that closes
// rawStream if it's still opened. It also provides ensureOpened(), which
// throws an exception if the stream is closed.
function StreamManager(stream, rawStream) {
+ const self = this;
this.rawStream = rawStream;
this.opened = true;
/**
* True iff the stream is closed.
*/
- stream.__defineGetter__("closed", () => !this.opened);
+ stream.__defineGetter__("closed", function stream_closed() {
+ return !self.opened;
+ });
/**
* Closes both the stream and its backing stream. If the stream is already
* closed, an exception is thrown. For TextWriters, this first flushes the
* backing stream's buffer.
*/
- stream.close = () => {
- this.ensureOpened();
- this.unload();
+ stream.close = function stream_close() {
+ self.ensureOpened();
+ self.unload();
};
- ensure(this);
+ require("../system/unload").ensure(this);
}
StreamManager.prototype = {
diff --git a/addon-sdk/source/lib/sdk/places/host/host-query.js b/addon-sdk/source/lib/sdk/places/host/host-query.js
index 6ce12c231c95..12ba203afcd6 100644
--- a/addon-sdk/source/lib/sdk/places/host/host-query.js
+++ b/addon-sdk/source/lib/sdk/places/host/host-query.js
@@ -1,6 +1,7 @@
/* 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 = {
@@ -12,7 +13,7 @@ module.metadata = {
};
const { Cc, Ci } = require('chrome');
-const { all } = require('../../core/promise');
+const { defer, all, resolve } = require('../../core/promise');
const { safeMerge, omit } = require('../../util/object');
const historyService = Cc['@mozilla.org/browser/nav-history-service;1']
.getService(Ci.nsINavHistoryService);
@@ -44,11 +45,13 @@ const PLACES_PROPERTIES = [
];
function execute (queries, options) {
- return new Promise(resolve => {
- let root = historyService
- .executeQueries(queries, queries.length, options).root;
- resolve(collect([], root));
- });
+ let deferred = defer();
+ let root = historyService
+ .executeQueries(queries, queries.length, options).root;
+
+ let items = collect([], root);
+ deferred.resolve(items);
+ return deferred.promise;
}
function collect (acc, node) {
@@ -66,35 +69,40 @@ function collect (acc, node) {
}
function query (queries, options) {
- return new Promise((resolve, reject) => {
- queries = queries || [];
- options = options || {};
- let optionsObj, queryObjs;
+ queries = queries || [];
+ options = options || {};
+ let deferred = defer();
+ let optionsObj, queryObjs;
+ try {
optionsObj = historyService.getNewQueryOptions();
queryObjs = [].concat(queries).map(createQuery);
if (!queryObjs.length) {
queryObjs = [historyService.getNewQuery()];
}
safeMerge(optionsObj, options);
+ } catch (e) {
+ deferred.reject(e);
+ return deferred.promise;
+ }
- /*
- * Currently `places:` queries are not supported
- */
- optionsObj.excludeQueries = true;
+ /*
+ * Currently `places:` queries are not supported
+ */
+ optionsObj.excludeQueries = true;
- execute(queryObjs, optionsObj).then((results) => {
- if (optionsObj.queryType === 0) {
- return results.map(normalize);
- }
- else if (optionsObj.queryType === 1) {
- // Formats query results into more standard
- // data structures for returning
- return all(results.map(({itemId}) =>
- send('sdk-places-bookmarks-get', { id: itemId })));
- }
- }).then(resolve, reject);
- });
+ execute(queryObjs, optionsObj).then(function (results) {
+ if (optionsObj.queryType === 0) {
+ return results.map(normalize);
+ } else if (optionsObj.queryType === 1) {
+ // Formats query results into more standard
+ // data structures for returning
+ return all(results.map(({itemId}) =>
+ send('sdk-places-bookmarks-get', { id: itemId })));
+ }
+ }).then(deferred.resolve, deferred.reject);
+
+ return deferred.promise;
}
exports.query = query;
@@ -132,7 +140,7 @@ function queryReceiver (message) {
/*
* Converts a nsINavHistoryResultNode into a plain object
- *
+ *
* https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryResultNode
*/
function normalize (historyObj) {
@@ -142,8 +150,7 @@ function normalize (historyObj) {
else if (prop === 'time') {
// Cast from microseconds to milliseconds
obj.time = Math.floor(historyObj.time / 1000)
- }
- else if (prop === 'accessCount')
+ } else if (prop === 'accessCount')
obj.visitCount = historyObj[prop];
else
obj[prop] = historyObj[prop];
diff --git a/addon-sdk/source/lib/sdk/places/utils.js b/addon-sdk/source/lib/sdk/places/utils.js
index f03a8f6a75a5..e016a1452532 100644
--- a/addon-sdk/source/lib/sdk/places/utils.js
+++ b/addon-sdk/source/lib/sdk/places/utils.js
@@ -51,14 +51,14 @@ exports.TreeNode = TreeNode;
/*
* Descends down from `node` applying `fn` to each in order.
* `fn` can return values or promises -- if promise returned,
- * children are not processed until resolved. `fn` is passed
+ * 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 => {
return all(curr.children.map(child => walk(child, fn)));
});
-}
+}
/*
* Descends from the TreeNode `node`, returning
@@ -122,7 +122,7 @@ exports.isRootGroup = isRootGroup;
/*
* Merges appropriate options into query based off of url
* 4 scenarios:
- *
+ *
* 'moz.com' // domain: moz.com, domainIsHost: true
* --> 'http://moz.com', 'http://moz.com/thunderbird'
* '*.moz.com' // domain: moz.com, domainIsHost: false
@@ -177,9 +177,9 @@ function createQuery (type, query) {
let qObj = {
searchTerms: query.query
};
-
+
urlQueryParser(qObj, query.url);
-
+
// 0 === history
if (type === 0) {
// PRTime used by query is in microseconds, not milliseconds
@@ -194,7 +194,7 @@ function createQuery (type, query) {
else if (type === 1) {
qObj.tags = query.tags;
qObj.folder = query.group && query.group.id;
- }
+ }
// 2 === unified (not implemented on platform)
else if (type === 2) {
diff --git a/addon-sdk/source/lib/sdk/test/harness.js b/addon-sdk/source/lib/sdk/test/harness.js
index c5e3f09d4930..b32cf54f7ef1 100644
--- a/addon-sdk/source/lib/sdk/test/harness.js
+++ b/addon-sdk/source/lib/sdk/test/harness.js
@@ -15,6 +15,7 @@ const { PlainTextConsole } = require("../console/plain-text");
const { when: unload } = require("../system/unload");
const { format, fromException } = require("../console/traceback");
const system = require("../system");
+const memory = require('../deprecated/memory');
const { gc: gcPromise } = require('./memory');
const { defer } = require('../core/promise');
const { extend } = require('../core/heritage');
@@ -149,7 +150,7 @@ function reportMemoryUsage() {
return emptyPromise();
}
- return gcPromise().then((() => {
+ return gcPromise().then((function () {
var mgr = Cc["@mozilla.org/memory-reporter-manager;1"]
.getService(Ci.nsIMemoryReporterManager);
let count = 0;
@@ -157,6 +158,11 @@ function reportMemoryUsage() {
print(((++count == 1) ? "\n" : "") + description + ": " + amount + "\n");
}
mgr.getReportsForThisProcess(logReporter, null, /* anonymize = */ false);
+
+ var weakrefs = [info.weakref.get()
+ for (info of memory.getObjects())];
+ weakrefs = [weakref for (weakref of weakrefs) if (weakref)];
+ print("Tracked memory objects in testing sandbox: " + weakrefs.length + "\n");
}));
}
@@ -210,6 +216,16 @@ function showResults() {
function cleanup() {
let coverObject = {};
try {
+ for (let name in loader.modules)
+ memory.track(loader.modules[name],
+ "module global scope: " + name);
+ memory.track(loader, "Cuddlefish Loader");
+
+ if (profileMemory) {
+ gWeakrefInfo = [{ weakref: info.weakref, bin: info.bin }
+ for (info of memory.getObjects())];
+ }
+
loader.unload();
if (loader.globals.console.errorsLogged && !results.failed) {
@@ -235,7 +251,7 @@ function cleanup() {
consoleListener.unregister();
- Cu.forceGC();
+ memory.gc();
}
catch (e) {
results.failed++;
@@ -262,7 +278,7 @@ function cleanup() {
}
function getPotentialLeaks() {
- Cu.forceGC();
+ memory.gc();
// Things we can assume are part of the platform and so aren't leaks
let GOOD_BASE_URLS = [
diff --git a/addon-sdk/source/lib/sdk/test/memory.js b/addon-sdk/source/lib/sdk/test/memory.js
index bd1198bfe52d..1c564331266f 100644
--- a/addon-sdk/source/lib/sdk/test/memory.js
+++ b/addon-sdk/source/lib/sdk/test/memory.js
@@ -4,8 +4,17 @@
'use strict';
const { Cu } = require("chrome");
+const memory = require('../deprecated/memory');
+const { defer } = require('../core/promise');
function gc() {
- return new Promise(resolve => Cu.schedulePreciseGC(resolve));
+ let { promise, resolve } = defer();
+
+ Cu.forceGC();
+ memory.gc();
+
+ Cu.schedulePreciseGC(_ => resolve());
+
+ return promise;
}
exports.gc = gc;
diff --git a/addon-sdk/source/lib/sdk/util/bond.js b/addon-sdk/source/lib/sdk/util/bond.js
new file mode 100644
index 000000000000..422f57737e17
--- /dev/null
+++ b/addon-sdk/source/lib/sdk/util/bond.js
@@ -0,0 +1,36 @@
+/* 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 makeDescriptor = (name, method) => ({
+ get() {
+ if (!Object.hasOwnProperty.call(this, name)) {
+ Object.defineProperty(this, name, {value: method.bind(this)});
+ return this[name];
+ } else {
+ return method;
+ }
+ }
+});
+
+const Bond = function(methods) {
+ let descriptor = {};
+ let members = [...Object.getOwnPropertyNames(methods),
+ ...Object.getOwnPropertySymbols(methods)];
+
+ for (let name of members) {
+ let method = methods[name];
+ if (typeof(method) !== "function") {
+ throw new TypeError(`Property named "${name}" passed to Bond must be a function`);
+ }
+ descriptor[name] = makeDescriptor(name, method);
+ }
+
+ return Object.create(Bond.prototype, descriptor);
+}
+exports.Bond = Bond;
diff --git a/addon-sdk/source/lib/sdk/zip/utils.js b/addon-sdk/source/lib/sdk/zip/utils.js
index e600380cbea6..bc1e0b610b7e 100644
--- a/addon-sdk/source/lib/sdk/zip/utils.js
+++ b/addon-sdk/source/lib/sdk/zip/utils.js
@@ -1,16 +1,22 @@
/* 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';
-const { Cc, Ci } = require("chrome");
+const { Cc, Ci, Cu } = require("chrome");
+const { defer } = require("../core/promise");
-function getZipReader(aFile) {
- return new Promise(resolve => {
- let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
- createInstance(Ci.nsIZipReader);
+const getZipReader = function getZipReader(aFile) {
+ let { promise, resolve, reject } = defer();
+ let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
+ createInstance(Ci.nsIZipReader);
+ try {
zipReader.open(aFile);
- resolve(zipReader);
- });
+ }
+ catch(e){
+ reject(e);
+ }
+ resolve(zipReader);
+ return promise;
};
exports.getZipReader = getZipReader;
diff --git a/addon-sdk/source/mapping.json b/addon-sdk/source/mapping.json
index d8f497a26fc7..18b78b979a1f 100644
--- a/addon-sdk/source/mapping.json
+++ b/addon-sdk/source/mapping.json
@@ -13,6 +13,7 @@
"l10n/prefs": "sdk/l10n/prefs",
"list": "sdk/util/list",
"loader": "sdk/loader/loader",
+ "memory": "sdk/deprecated/memory",
"namespace": "sdk/core/namespace",
"preferences-service": "sdk/preferences/service",
"promise": "sdk/core/promise",
diff --git a/addon-sdk/source/package.json b/addon-sdk/source/package.json
index 5a9707afb838..35a4e9c9034e 100644
--- a/addon-sdk/source/package.json
+++ b/addon-sdk/source/package.json
@@ -22,7 +22,6 @@
"async": "0.9.0",
"chai": "2.1.1",
"fs-extra": "0.18.2",
- "fx-runner": "0.0.7",
"glob": "4.4.2",
"gulp": "3.8.11",
"ini-parser": "0.0.2",
diff --git a/addon-sdk/source/python-lib/cuddlefish/__init__.py b/addon-sdk/source/python-lib/cuddlefish/__init__.py
index 365d96c5ef4d..7fafe14689b1 100644
--- a/addon-sdk/source/python-lib/cuddlefish/__init__.py
+++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py
@@ -236,6 +236,10 @@ parser_groups = (
help="Where to put the finished .xpi",
default=None,
cmds=['xpi'])),
+ (("", "--manifest-overload",), dict(dest="manifest_overload",
+ help="JSON file to overload package.json properties",
+ default=None,
+ cmds=['xpi'])),
(("", "--abort-on-missing-module",), dict(dest="abort_on_missing",
help="Abort if required module is missing",
action="store_true",
@@ -657,6 +661,10 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
target_cfg_json = os.path.join(options.pkgdir, 'package.json')
target_cfg = packaging.get_config_in_dir(options.pkgdir)
+ if options.manifest_overload:
+ for k, v in packaging.load_json_file(options.manifest_overload).items():
+ target_cfg[k] = v
+
# At this point, we're either building an XPI or running Jetpack code in
# a Mozilla application (which includes running tests).
diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/main.js b/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/main.js
new file mode 100644
index 000000000000..22018c2a2eb0
--- /dev/null
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/main.js
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { Cc, Ci } = require("chrome");
+
+exports.main = function(options, callbacks) {
+ // Close Firefox window. Firefox should quit.
+ require("sdk/deprecated/window-utils").activeBrowserWindow.close();
+
+ // But not on Mac where it stay alive! We have to request application quit.
+ if (require("sdk/system/runtime").OS == "Darwin") {
+ let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
+ getService(Ci.nsIAppStartup);
+ appStartup.quit(appStartup.eAttemptQuit);
+ }
+}
diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/manifest-overload.json b/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/manifest-overload.json
new file mode 100644
index 000000000000..a446378b0cfb
--- /dev/null
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/manifest-overload.json
@@ -0,0 +1,3 @@
+{
+ "version": "1.0-nightly"
+}
diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/package.json b/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/package.json
new file mode 100644
index 000000000000..afbc15803daa
--- /dev/null
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/package.json
@@ -0,0 +1,6 @@
+{
+ "id": "simplest-test",
+ "directories": {
+ "lib": "."
+ }
+}
diff --git a/addon-sdk/source/lib/sdk/content/sandbox/events.js b/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js
similarity index 65%
rename from addon-sdk/source/lib/sdk/content/sandbox/events.js
rename to addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js
index d6f7eb004063..533cd34e6fba 100644
--- a/addon-sdk/source/lib/sdk/content/sandbox/events.js
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js
@@ -2,11 +2,6 @@
* 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"
+exports.minimalTest = function(test) {
+ test.assert(true);
};
-
-const events = {};
-exports.events = events;
diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/test_init.py b/addon-sdk/source/python-lib/cuddlefish/tests/test_init.py
index 5ececfea6020..f331b09cbea9 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_init.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_init.py
@@ -182,6 +182,35 @@ class TestCfxQuits(unittest.TestCase):
container)
self.fail(standardMsg)
+ def test_cfx_run(self):
+ addon_path = os.path.join(tests_path,
+ "addons", "simplest-test")
+ rc, out, err = self.run_cfx(addon_path, ["run"])
+ self.assertEqual(rc, 0)
+ self.assertIn("Program terminated successfully.", err)
+
+ def test_cfx_test(self):
+ addon_path = os.path.join(tests_path, "addons", "simplest-test")
+ rc, out, err = self.run_cfx(addon_path, ["test"])
+ self.assertEqual(rc, 0)
+ self.assertIn("1 of 1 tests passed.", err)
+ self.assertIn("Program terminated successfully.", err)
+
+ def test_cfx_xpi(self):
+ addon_path = os.path.join(tests_path,
+ "addons", "simplest-test")
+ rc, out, err = self.run_cfx(addon_path, \
+ ["xpi", "--manifest-overload", "manifest-overload.json"])
+ self.assertEqual(rc, 0)
+ # Ensure that the addon version from our manifest overload is used
+ # in install.rdf
+ xpi_path = os.path.join(addon_path, "simplest-test.xpi")
+ xpi = zipfile.ZipFile(xpi_path, "r")
+ manifest = xpi.read("install.rdf")
+ self.assertIn("
This is an add-on page test!
-