diff options
author | Matt A. Tobin <email@mattatobin.com> | 2018-02-10 02:51:36 -0500 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2018-02-10 02:51:36 -0500 |
commit | 37d5300335d81cecbecc99812747a657588c63eb (patch) | |
tree | 765efa3b6a56bb715d9813a8697473e120436278 /addon-sdk/source/lib/sdk/test | |
parent | b2bdac20c02b12f2057b9ef70b0a946113a00e00 (diff) | |
parent | 4fb11cd5966461bccc3ed1599b808237be6b0de9 (diff) | |
download | UXP-37d5300335d81cecbecc99812747a657588c63eb.tar UXP-37d5300335d81cecbecc99812747a657588c63eb.tar.gz UXP-37d5300335d81cecbecc99812747a657588c63eb.tar.lz UXP-37d5300335d81cecbecc99812747a657588c63eb.tar.xz UXP-37d5300335d81cecbecc99812747a657588c63eb.zip |
Merge branch 'ext-work'
Diffstat (limited to 'addon-sdk/source/lib/sdk/test')
-rw-r--r-- | addon-sdk/source/lib/sdk/test/assert.js | 366 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/test/harness.js | 645 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/test/httpd.js | 6 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/test/loader.js | 123 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/test/memory.js | 11 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/test/options.js | 23 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/test/runner.js | 131 | ||||
-rw-r--r-- | addon-sdk/source/lib/sdk/test/utils.js | 199 |
8 files changed, 0 insertions, 1504 deletions
diff --git a/addon-sdk/source/lib/sdk/test/assert.js b/addon-sdk/source/lib/sdk/test/assert.js deleted file mode 100644 index 8478c8414..000000000 --- a/addon-sdk/source/lib/sdk/test/assert.js +++ /dev/null @@ -1,366 +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" -}; - -const { isFunction, isNull, isObject, isString, - isRegExp, isArray, isDate, isPrimitive, - isUndefined, instanceOf, source } = require("../lang/type"); - -/** - * The `AssertionError` is defined in assert. - * @extends Error - * @example - * new assert.AssertionError({ - * message: message, - * actual: actual, - * expected: expected - * }) - */ -function AssertionError(options) { - let assertionError = Object.create(AssertionError.prototype); - - if (isString(options)) - options = { message: options }; - if ("actual" in options) - assertionError.actual = options.actual; - if ("expected" in options) - assertionError.expected = options.expected; - if ("operator" in options) - assertionError.operator = options.operator; - - assertionError.message = options.message; - assertionError.stack = new Error().stack; - return assertionError; -} -AssertionError.prototype = Object.create(Error.prototype, { - constructor: { value: AssertionError }, - name: { value: "AssertionError", enumerable: true }, - toString: { value: function toString() { - let value; - if (this.message) { - value = this.name + " : " + this.message; - } - else { - value = [ - this.name + " : ", - source(this.expected), - this.operator, - source(this.actual) - ].join(" "); - } - return value; - }} -}); -exports.AssertionError = AssertionError; - -function Assert(logger) { - let assert = Object.create(Assert.prototype, { _log: { value: logger }}); - - assert.fail = assert.fail.bind(assert); - assert.pass = assert.pass.bind(assert); - - return assert; -} - -Assert.prototype = { - fail: function fail(e) { - if (!e || typeof(e) !== 'object') { - this._log.fail(e); - return; - } - let message = e.message; - try { - if ('operator' in e) { - message += [ - " -", - source(e.actual), - e.operator, - source(e.expected) - ].join(" "); - } - } - catch(e) {} - this._log.fail(message); - }, - pass: function pass(message) { - this._log.pass(message); - return true; - }, - error: function error(e) { - this._log.exception(e); - }, - ok: function ok(value, message) { - if (!!!value) { - this.fail({ - actual: value, - expected: true, - message: message, - operator: "==" - }); - return false; - } - - this.pass(message); - return true; - }, - - /** - * The equality assertion tests shallow, coercive equality with `==`. - * @example - * assert.equal(1, 1, "one is one"); - */ - equal: function equal(actual, expected, message) { - if (actual == expected) { - this.pass(message); - return true; - } - - this.fail({ - actual: actual, - expected: expected, - message: message, - operator: "==" - }); - return false; - }, - - /** - * The non-equality assertion tests for whether two objects are not equal - * with `!=`. - * @example - * assert.notEqual(1, 2, "one is not two"); - */ - notEqual: function notEqual(actual, expected, message) { - if (actual != expected) { - this.pass(message); - return true; - } - - this.fail({ - actual: actual, - expected: expected, - message: message, - operator: "!=", - }); - return false; - }, - - /** - * The equivalence assertion tests a deep (with `===`) equality relation. - * @example - * assert.deepEqual({ a: "foo" }, { a: "foo" }, "equivalent objects") - */ - deepEqual: function deepEqual(actual, expected, message) { - if (isDeepEqual(actual, expected)) { - this.pass(message); - return true; - } - - this.fail({ - actual: actual, - expected: expected, - message: message, - operator: "deepEqual" - }); - return false; - }, - - /** - * The non-equivalence assertion tests for any deep (with `===`) inequality. - * @example - * assert.notDeepEqual({ a: "foo" }, Object.create({ a: "foo" }), - * "object's inherit from different prototypes"); - */ - notDeepEqual: function notDeepEqual(actual, expected, message) { - if (!isDeepEqual(actual, expected)) { - this.pass(message); - return true; - } - - this.fail({ - actual: actual, - expected: expected, - message: message, - operator: "notDeepEqual" - }); - return false; - }, - - /** - * The strict equality assertion tests strict equality, as determined by - * `===`. - * @example - * assert.strictEqual(null, null, "`null` is `null`") - */ - strictEqual: function strictEqual(actual, expected, message) { - if (actual === expected) { - this.pass(message); - return true; - } - - this.fail({ - actual: actual, - expected: expected, - message: message, - operator: "===" - }); - return false; - }, - - /** - * The strict non-equality assertion tests for strict inequality, as - * determined by `!==`. - * @example - * assert.notStrictEqual(null, undefined, "`null` is not `undefined`"); - */ - notStrictEqual: function notStrictEqual(actual, expected, message) { - if (actual !== expected) { - this.pass(message); - return true; - } - - this.fail({ - actual: actual, - expected: expected, - message: message, - operator: "!==" - }); - return false; - }, - - /** - * The assertion whether or not given `block` throws an exception. If optional - * `Error` argument is provided and it's type of function thrown error is - * asserted to be an instance of it, if type of `Error` is string then message - * of throw exception is asserted to contain it. - * @param {Function} block - * Function that is expected to throw. - * @param {Error|RegExp} [Error] - * Error constructor that is expected to be thrown or a string that - * must be contained by a message of the thrown exception, or a RegExp - * matching a message of the thrown exception. - * @param {String} message - * Description message - * - * @examples - * - * assert.throws(function block() { - * doSomething(4) - * }, "Object is expected", "Incorrect argument is passed"); - * - * assert.throws(function block() { - * Object.create(5) - * }, TypeError, "TypeError is thrown"); - */ - throws: function throws(block, Error, message) { - let threw = false; - let exception = null; - - // If third argument is not provided and second argument is a string it - // means that optional `Error` argument was not passed, so we shift - // arguments. - if (isString(Error) && isUndefined(message)) { - message = Error; - Error = undefined; - } - - // Executing given `block`. - try { - block(); - } - catch (e) { - threw = true; - exception = e; - } - - // If exception was thrown and `Error` argument was not passed assert is - // passed. - if (threw && (isUndefined(Error) || - // If passed `Error` is RegExp using it's test method to - // assert thrown exception message. - (isRegExp(Error) && (Error.test(exception.message) || Error.test(exception.toString()))) || - // If passed `Error` is a constructor function testing if - // thrown exception is an instance of it. - (isFunction(Error) && instanceOf(exception, Error)))) - { - this.pass(message); - return true; - } - - // Otherwise we report assertion failure. - let failure = { - message: message, - operator: "matches" - }; - - if (exception) { - failure.actual = exception.message || exception.toString(); - } - - if (Error) { - failure.expected = Error.toString(); - } - - this.fail(failure); - return false; - } -}; -exports.Assert = Assert; - -function isDeepEqual(actual, expected) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - } - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - else if (isDate(actual) && isDate(expected)) { - return actual.getTime() === expected.getTime(); - } - - // XXX specification bug: this should be specified - else if (isPrimitive(actual) || isPrimitive(expected)) { - return expected === actual; - } - - // 7.3. Other pairs that do not both pass typeof value == "object", - // equivalence is determined by ==. - else if (!isObject(actual) && !isObject(expected)) { - return actual == expected; - } - - // 7.4. For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical "prototype" property. Note: this - // accounts for both named and indexed properties on Arrays. - else { - return actual.prototype === expected.prototype && - isEquivalent(actual, expected); - } -} - -function isEquivalent(a, b, stack) { - let aKeys = Object.keys(a); - let bKeys = Object.keys(b); - - return aKeys.length === bKeys.length && - isArrayEquivalent(aKeys.sort(), bKeys.sort()) && - aKeys.every(function(key) { - return isDeepEqual(a[key], b[key], stack) - }); -} - -function isArrayEquivalent(a, b, stack) { - return isArray(a) && isArray(b) && - a.every(function(value, index) { - return isDeepEqual(value, b[index]); - }); -} diff --git a/addon-sdk/source/lib/sdk/test/harness.js b/addon-sdk/source/lib/sdk/test/harness.js deleted file mode 100644 index 1b31a1c79..000000000 --- a/addon-sdk/source/lib/sdk/test/harness.js +++ /dev/null @@ -1,645 +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": "experimental" -}; - -const { Cc, Ci, Cu } = require("chrome"); -const { Loader } = require('./loader'); -const { serializeStack, parseStack } = require("toolkit/loader"); -const { setTimeout } = require('../timers'); -const { PlainTextConsole } = require("../console/plain-text"); -const { when: unload } = require("../system/unload"); -const { format, fromException } = require("../console/traceback"); -const system = require("../system"); -const { gc: gcPromise } = require('./memory'); -const { defer } = require('../core/promise'); -const { extend } = require('../core/heritage'); - -// Trick manifest builder to make it think we need these modules ? -const unit = require("../deprecated/unit-test"); -const test = require("../../test"); -const url = require("../url"); - -function emptyPromise() { - let { promise, resolve } = defer(); - resolve(); - return promise; -} - -var cService = Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService); - -// The console used to log messages -var testConsole; - -// Cuddlefish loader in which we load and execute tests. -var loader; - -// Function to call when we're done running tests. -var onDone; - -// Function to print text to a console, w/o CR at the end. -var print; - -// How many more times to run all tests. -var iterationsLeft; - -// Whether to report memory profiling information. -var profileMemory; - -// Whether we should stop as soon as a test reports a failure. -var stopOnError; - -// Function to call to retrieve a list of tests to execute -var findAndRunTests; - -// Combined information from all test runs. -var results; - -// A list of the compartments and windows loaded after startup -var startLeaks; - -// JSON serialization of last memory usage stats; we keep it stringified -// so we don't actually change the memory usage stats (in terms of objects) -// of the JSRuntime we're profiling. -var lastMemoryUsage; - -function analyzeRawProfilingData(data) { - var graph = data.graph; - var shapes = {}; - - // Convert keys in the graph from strings to ints. - // TODO: Can we get rid of this ridiculousness? - var newGraph = {}; - for (id in graph) { - newGraph[parseInt(id)] = graph[id]; - } - graph = newGraph; - - var modules = 0; - var moduleIds = []; - var moduleObjs = {UNKNOWN: 0}; - for (let name in data.namedObjects) { - moduleObjs[name] = 0; - moduleIds[data.namedObjects[name]] = name; - modules++; - } - - var count = 0; - for (id in graph) { - var parent = graph[id].parent; - while (parent) { - if (parent in moduleIds) { - var name = moduleIds[parent]; - moduleObjs[name]++; - break; - } - if (!(parent in graph)) { - moduleObjs.UNKNOWN++; - break; - } - parent = graph[parent].parent; - } - count++; - } - - print("\nobject count is " + count + " in " + modules + " modules" + - " (" + data.totalObjectCount + " across entire JS runtime)\n"); - if (lastMemoryUsage) { - var last = JSON.parse(lastMemoryUsage); - var diff = { - moduleObjs: dictDiff(last.moduleObjs, moduleObjs), - totalObjectClasses: dictDiff(last.totalObjectClasses, - data.totalObjectClasses) - }; - - for (let name in diff.moduleObjs) - print(" " + diff.moduleObjs[name] + " in " + name + "\n"); - for (let name in diff.totalObjectClasses) - print(" " + diff.totalObjectClasses[name] + " instances of " + - name + "\n"); - } - lastMemoryUsage = JSON.stringify( - {moduleObjs: moduleObjs, - totalObjectClasses: data.totalObjectClasses} - ); -} - -function dictDiff(last, curr) { - var diff = {}; - - for (let name in last) { - var result = (curr[name] || 0) - last[name]; - if (result) - diff[name] = (result > 0 ? "+" : "") + result; - } - for (let name in curr) { - var result = curr[name] - (last[name] || 0); - if (result) - diff[name] = (result > 0 ? "+" : "") + result; - } - return diff; -} - -function reportMemoryUsage() { - if (!profileMemory) { - return emptyPromise(); - } - - return gcPromise().then((() => { - var mgr = Cc["@mozilla.org/memory-reporter-manager;1"] - .getService(Ci.nsIMemoryReporterManager); - let count = 0; - function logReporter(process, path, kind, units, amount, description) { - print(((++count == 1) ? "\n" : "") + description + ": " + amount + "\n"); - } - mgr.getReportsForThisProcess(logReporter, null, /* anonymize = */ false); - })); -} - -var gWeakrefInfo; - -function checkMemory() { - return gcPromise().then(_ => { - let leaks = getPotentialLeaks(); - - let compartmentURLs = Object.keys(leaks.compartments).filter(function(url) { - return !(url in startLeaks.compartments); - }); - - let windowURLs = Object.keys(leaks.windows).filter(function(url) { - return !(url in startLeaks.windows); - }); - - for (let url of compartmentURLs) - console.warn("LEAKED", leaks.compartments[url]); - - for (let url of windowURLs) - console.warn("LEAKED", leaks.windows[url]); - }).then(showResults); -} - -function showResults() { - let { promise, resolve } = defer(); - - if (gWeakrefInfo) { - gWeakrefInfo.forEach( - function(info) { - var ref = info.weakref.get(); - if (ref !== null) { - var data = ref.__url__ ? ref.__url__ : ref; - var warning = data == "[object Object]" - ? "[object " + data.constructor.name + "(" + - Object.keys(data).join(", ") + ")]" - : data; - console.warn("LEAK", warning, info.bin); - } - } - ); - } - - onDone(results); - - resolve(); - return promise; -} - -function cleanup() { - let coverObject = {}; - try { - loader.unload(); - - if (loader.globals.console.errorsLogged && !results.failed) { - results.failed++; - console.error("warnings and/or errors were logged."); - } - - if (consoleListener.errorsLogged && !results.failed) { - console.warn(consoleListener.errorsLogged + " " + - "warnings or errors were logged to the " + - "platform's nsIConsoleService, which could " + - "be of no consequence; however, they could also " + - "be indicative of aberrant behavior."); - } - - // read the code coverage object, if it exists, from CoverJS-moz - if (typeof loader.globals.global == "object") { - coverObject = loader.globals.global['__$coverObject'] || {}; - } - - consoleListener.errorsLogged = 0; - loader = null; - - consoleListener.unregister(); - - Cu.forceGC(); - } - catch (e) { - results.failed++; - console.error("unload.send() threw an exception."); - console.exception(e); - }; - - setTimeout(require("./options").checkMemory ? checkMemory : showResults, 1); - - // dump the coverobject - if (Object.keys(coverObject).length){ - const self = require('sdk/self'); - const {pathFor} = require("sdk/system"); - let file = require('sdk/io/file'); - const {env} = require('sdk/system/environment'); - console.log("CWD:", env.PWD); - let out = file.join(env.PWD,'coverstats-'+self.id+'.json'); - console.log('coverstats:', out); - let outfh = file.open(out,'w'); - outfh.write(JSON.stringify(coverObject,null,2)); - outfh.flush(); - outfh.close(); - } -} - -function getPotentialLeaks() { - Cu.forceGC(); - - // Things we can assume are part of the platform and so aren't leaks - let GOOD_BASE_URLS = [ - "chrome://", - "resource:///", - "resource://app/", - "resource://gre/", - "resource://gre-resources/", - "resource://pdf.js/", - "resource://pdf.js.components/", - "resource://services-common/", - "resource://services-crypto/", - "resource://services-sync/" - ]; - - let ioService = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - let uri = ioService.newURI("chrome://global/content/", "UTF-8", null); - let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIChromeRegistry); - uri = chromeReg.convertChromeURL(uri); - let spec = uri.spec; - let pos = spec.indexOf("!/"); - GOOD_BASE_URLS.push(spec.substring(0, pos + 2)); - - let zoneRegExp = new RegExp("^explicit/js-non-window/zones/zone[^/]+/compartment\\((.+)\\)"); - let compartmentRegexp = new RegExp("^explicit/js-non-window/compartments/non-window-global/compartment\\((.+)\\)/"); - let compartmentDetails = new RegExp("^([^,]+)(?:, (.+?))?(?: \\(from: (.*)\\))?$"); - let windowRegexp = new RegExp("^explicit/window-objects/top\\((.*)\\)/active"); - let windowDetails = new RegExp("^(.*), id=.*$"); - - function isPossibleLeak(item) { - if (!item.location) - return false; - - for (let url of GOOD_BASE_URLS) { - if (item.location.substring(0, url.length) == url) { - return false; - } - } - - return true; - } - - let compartments = {}; - let windows = {}; - function logReporter(process, path, kind, units, amount, description) { - let matches; - - if ((matches = compartmentRegexp.exec(path)) || (matches = zoneRegExp.exec(path))) { - if (matches[1] in compartments) - return; - - let details = compartmentDetails.exec(matches[1]); - if (!details) { - console.error("Unable to parse compartment detail " + matches[1]); - return; - } - - let item = { - path: matches[1], - principal: details[1], - location: details[2] ? details[2].replace(/\\/g, "/") : undefined, - source: details[3] ? details[3].split(" -> ").reverse() : undefined, - toString: function() { - return this.location; - } - }; - - if (!isPossibleLeak(item)) - return; - - compartments[matches[1]] = item; - return; - } - - if ((matches = windowRegexp.exec(path))) { - if (matches[1] in windows) - return; - - let details = windowDetails.exec(matches[1]); - if (!details) { - console.error("Unable to parse window detail " + matches[1]); - return; - } - - let item = { - path: matches[1], - location: details[1].replace(/\\/g, "/"), - source: [details[1].replace(/\\/g, "/")], - toString: function() { - return this.location; - } - }; - - if (!isPossibleLeak(item)) - return; - - windows[matches[1]] = item; - } - } - - Cc["@mozilla.org/memory-reporter-manager;1"] - .getService(Ci.nsIMemoryReporterManager) - .getReportsForThisProcess(logReporter, null, /* anonymize = */ false); - - return { compartments: compartments, windows: windows }; -} - -function nextIteration(tests) { - if (tests) { - results.passed += tests.passed; - results.failed += tests.failed; - - reportMemoryUsage().then(_ => { - let testRun = []; - for (let test of tests.testRunSummary) { - let testCopy = {}; - for (let info in test) { - testCopy[info] = test[info]; - } - testRun.push(testCopy); - } - - results.testRuns.push(testRun); - iterationsLeft--; - - checkForEnd(); - }) - } - else { - checkForEnd(); - } -} - -function checkForEnd() { - if (iterationsLeft && (!stopOnError || results.failed == 0)) { - // Pass the loader which has a hooked console that doesn't dispatch - // errors to the JS console and avoid firing false alarm in our - // console listener - findAndRunTests(loader, nextIteration); - } - else { - setTimeout(cleanup, 0); - } -} - -var POINTLESS_ERRORS = [ - 'Invalid chrome URI:', - 'OpenGL LayerManager Initialized Succesfully.', - '[JavaScript Error: "TelemetryStopwatch:', - 'reference to undefined property', - '[JavaScript Error: "The character encoding of the HTML document was ' + - 'not declared.', - '[Javascript Warning: "Error: Failed to preserve wrapper of wrapped ' + - 'native weak map key', - '[JavaScript Warning: "Duplicate resource declaration for', - 'file: "chrome://browser/content/', - 'file: "chrome://global/content/', - '[JavaScript Warning: "The character encoding of a framed document was ' + - 'not declared.', - 'file: "chrome://browser/skin/' -]; - -// These are messages that will cause a test to fail if logged through the -// console service -var IMPORTANT_ERRORS = [ - 'Sending message that cannot be cloned. Are you trying to send an XPCOM object?', -]; - -var consoleListener = { - registered: false, - - register: function() { - if (this.registered) - return; - cService.registerListener(this); - this.registered = true; - }, - - unregister: function() { - if (!this.registered) - return; - cService.unregisterListener(this); - this.registered = false; - }, - - errorsLogged: 0, - - observe: function(object) { - if (!(object instanceof Ci.nsIScriptError)) - return; - this.errorsLogged++; - var message = object.QueryInterface(Ci.nsIConsoleMessage).message; - if (IMPORTANT_ERRORS.find(msg => message.indexOf(msg) >= 0)) { - testConsole.error(message); - return; - } - var pointless = POINTLESS_ERRORS.filter(err => message.indexOf(err) >= 0); - if (pointless.length == 0 && message) - testConsole.log(message); - } -}; - -function TestRunnerConsole(base, options) { - let proto = extend(base, { - errorsLogged: 0, - warn: function warn() { - this.errorsLogged++; - base.warn.apply(base, arguments); - }, - error: function error() { - this.errorsLogged++; - base.error.apply(base, arguments); - }, - info: function info(first) { - if (options.verbose) - base.info.apply(base, arguments); - else - if (first == "pass:") - print("."); - }, - }); - return Object.create(proto); -} - -function stringify(arg) { - try { - return String(arg); - } - catch(ex) { - return "<toString() error>"; - } -} - -function stringifyArgs(args) { - return Array.map(args, stringify).join(" "); -} - -function TestRunnerTinderboxConsole(base, options) { - this.base = base; - this.print = options.print; - this.verbose = options.verbose; - this.errorsLogged = 0; - - // Binding all the public methods to an instance so that they can be used - // as callback / listener functions straightaway. - this.log = this.log.bind(this); - this.info = this.info.bind(this); - this.warn = this.warn.bind(this); - this.error = this.error.bind(this); - this.debug = this.debug.bind(this); - this.exception = this.exception.bind(this); - this.trace = this.trace.bind(this); -}; - -TestRunnerTinderboxConsole.prototype = { - testMessage: function testMessage(pass, expected, test, message) { - let type = "TEST-"; - if (expected) { - if (pass) - type += "PASS"; - else - type += "KNOWN-FAIL"; - } - else { - this.errorsLogged++; - if (pass) - type += "UNEXPECTED-PASS"; - else - type += "UNEXPECTED-FAIL"; - } - - this.print(type + " | " + test + " | " + message + "\n"); - if (!expected) - this.trace(); - }, - - log: function log() { - this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n"); - }, - - info: function info(first) { - this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n"); - }, - - warn: function warn() { - this.errorsLogged++; - this.print("TEST-UNEXPECTED-FAIL | " + stringifyArgs(arguments) + "\n"); - }, - - error: function error() { - this.errorsLogged++; - this.print("TEST-UNEXPECTED-FAIL | " + stringifyArgs(arguments) + "\n"); - this.base.error.apply(this.base, arguments); - }, - - debug: function debug() { - this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n"); - }, - - exception: function exception(e) { - this.print("An exception occurred.\n" + - require("../console/traceback").format(e) + "\n" + e + "\n"); - }, - - trace: function trace() { - var traceback = require("../console/traceback"); - var stack = traceback.get(); - stack.splice(-1, 1); - this.print("TEST-INFO | " + stringify(traceback.format(stack)) + "\n"); - } -}; - -var runTests = exports.runTests = function runTests(options) { - iterationsLeft = options.iterations; - profileMemory = options.profileMemory; - stopOnError = options.stopOnError; - onDone = options.onDone; - print = options.print; - findAndRunTests = options.findAndRunTests; - - results = { - passed: 0, - failed: 0, - testRuns: [] - }; - - try { - consoleListener.register(); - print("Running tests on " + system.name + " " + system.version + - "/Gecko " + system.platformVersion + " (Build " + - system.build + ") (" + system.id + ") under " + - system.platform + "/" + system.architecture + ".\n"); - - if (options.parseable) - testConsole = new TestRunnerTinderboxConsole(new PlainTextConsole(), options); - else - testConsole = new TestRunnerConsole(new PlainTextConsole(), options); - - loader = Loader(module, { - console: testConsole, - global: {} // useful for storing things like coverage testing. - }); - - // Load these before getting initial leak stats as they will still be in - // memory when we check later - require("../deprecated/unit-test"); - require("../deprecated/unit-test-finder"); - if (profileMemory) - startLeaks = getPotentialLeaks(); - - nextIteration(); - } catch (e) { - let frames = fromException(e).reverse().reduce(function(frames, frame) { - if (frame.fileName.split("/").pop() === "unit-test-finder.js") - frames.done = true - if (!frames.done) frames.push(frame) - - return frames - }, []) - - let prototype = typeof(e) === "object" ? e.constructor.prototype : - Error.prototype; - let stack = serializeStack(frames.reverse()); - - let error = Object.create(prototype, { - message: { value: e.message, writable: true, configurable: true }, - fileName: { value: e.fileName, writable: true, configurable: true }, - lineNumber: { value: e.lineNumber, writable: true, configurable: true }, - stack: { value: stack, writable: true, configurable: true }, - toString: { value: () => String(e), writable: true, configurable: true }, - }); - - print("Error: " + error + " \n " + format(error)); - onDone({passed: 0, failed: 1}); - } -}; - -unload(_ => consoleListener.unregister()); diff --git a/addon-sdk/source/lib/sdk/test/httpd.js b/addon-sdk/source/lib/sdk/test/httpd.js deleted file mode 100644 index 218493924..000000000 --- a/addon-sdk/source/lib/sdk/test/httpd.js +++ /dev/null @@ -1,6 +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/. */ - -throw new Error(`This file was removed. A copy can be obtained from: - https://github.com/mozilla/addon-sdk/blob/master/test/lib/httpd.js`); diff --git a/addon-sdk/source/lib/sdk/test/loader.js b/addon-sdk/source/lib/sdk/test/loader.js deleted file mode 100644 index 33ba2ca5a..000000000 --- a/addon-sdk/source/lib/sdk/test/loader.js +++ /dev/null @@ -1,123 +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"; - -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'); - -var defaultGlobals = override(require('../system/globals'), { - console: console -}); - -function CustomLoader(module, globals, packaging, overrides={}) { - let options = packaging || require("@loader/options"); - options = override(options, { - id: overrides.id || options.id, - globals: override(defaultGlobals, globals || {}), - modules: override(override(options.modules || {}, overrides.modules || {}), { - 'sdk/addon/window': addonWindow - }) - }); - - let loaderModule = options.isNative ? '../../toolkit/loader' : '../loader/cuddlefish'; - let { Loader } = require(loaderModule); - let loader = Loader(options); - let wrapper = Object.create(loader, descriptor({ - require: Require(loader, module), - sandbox: function(id) { - let requirement = loader.resolve(id, module.id); - if (!requirement) - requirement = id; - let uri = resolveURI(requirement, loader.mapping); - return loader.sandboxes[uri]; - }, - unload: function(reason) { - unload(loader, reason); - } - })); - ensure(wrapper); - return wrapper; -}; -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(type, innerID, msg) { - messages.push({ type: type, msg: msg, innerID: innerID }); - if (callback) - callback(type, msg, innerID); - } - - return { - loader: CustomLoader(module, { - console: new HookedPlainTextConsole(hook, null, null) - }, null, { - modules: { - 'sdk/console/plain-text': { - PlainTextConsole: HookedPlainTextConsole.bind(null, hook) - } - } - }), - messages: messages - }; -} - -// Same than LoaderWithHookedConsole with lower level, instead we get what is -// actually printed to the command line console -exports.LoaderWithHookedConsole2 = function (module, callback) { - let messages = []; - return { - loader: CustomLoader(module, { - console: new PlainTextConsole(function (msg) { - messages.push(msg); - if (callback) - callback(msg); - }) - }), - messages: messages - }; -} - -// Creates a custom loader with a filtered console. The callback is passed every -// console message type and message and if it returns false the message will -// not be logged normally -exports.LoaderWithFilteredConsole = function (module, callback) { - function hook(type, innerID, msg) { - if (callback && callback(type, msg, innerID) == false) - return; - console[type](msg); - } - - return CustomLoader(module, { - console: new HookedPlainTextConsole(hook, null, null) - }, null, { - modules: { - 'sdk/console/plain-text': { - PlainTextConsole: HookedPlainTextConsole.bind(null, hook) - } - } - }); -} diff --git a/addon-sdk/source/lib/sdk/test/memory.js b/addon-sdk/source/lib/sdk/test/memory.js deleted file mode 100644 index bd1198bfe..000000000 --- a/addon-sdk/source/lib/sdk/test/memory.js +++ /dev/null @@ -1,11 +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'; - -const { Cu } = require("chrome"); - -function gc() { - return new Promise(resolve => Cu.schedulePreciseGC(resolve)); -} -exports.gc = gc; diff --git a/addon-sdk/source/lib/sdk/test/options.js b/addon-sdk/source/lib/sdk/test/options.js deleted file mode 100644 index 9bc611ca5..000000000 --- a/addon-sdk/source/lib/sdk/test/options.js +++ /dev/null @@ -1,23 +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" -}; - -const options = require("@test/options"); -const { id } = require("../self"); -const { get } = require("../preferences/service"); - -const readPref = (key) => get("extensions." + id + ".sdk." + key); - -exports.iterations = readPref("test.iterations") || options.iterations; -exports.filter = readPref("test.filter") || options.filter; -exports.profileMemory = readPref("profile.memory") || options.profileMemory; -exports.stopOnError = readPref("test.stop") || options.stopOnError; -exports.keepOpen = readPref("test.keepOpen") || false; -exports.verbose = (readPref("output.logLevel") == "verbose") || options.verbose; -exports.parseable = (readPref("output.format") == "tbpl") || options.parseable; -exports.checkMemory = readPref("profile.leaks") || options.check_memory; diff --git a/addon-sdk/source/lib/sdk/test/runner.js b/addon-sdk/source/lib/sdk/test/runner.js deleted file mode 100644 index ea37ac84f..000000000 --- a/addon-sdk/source/lib/sdk/test/runner.js +++ /dev/null @@ -1,131 +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": "experimental" -}; - -var { exit, stdout } = require("../system"); -var cfxArgs = require("../test/options"); -var events = require("../system/events"); -const { resolve } = require("../core/promise"); - -function runTests(findAndRunTests) { - var harness = require("./harness"); - - function onDone(tests) { - stdout.write("\n"); - var total = tests.passed + tests.failed; - stdout.write(tests.passed + " of " + total + " tests passed.\n"); - - events.emit("sdk:test:results", { data: JSON.stringify(tests) }); - - if (tests.failed == 0) { - if (tests.passed === 0) - stdout.write("No tests were run\n"); - if (!cfxArgs.keepOpen) - exit(0); - } else { - if (cfxArgs.verbose || cfxArgs.parseable) - printFailedTests(tests, stdout.write); - if (!cfxArgs.keepOpen) - exit(1); - } - }; - - // We may have to run test on next cycle, otherwise XPCOM components - // are not correctly updated. - // For ex: nsIFocusManager.getFocusedElementForWindow may throw - // NS_ERROR_ILLEGAL_VALUE exception. - require("../timers").setTimeout(_ => harness.runTests({ - findAndRunTests: findAndRunTests, - iterations: cfxArgs.iterations || 1, - filter: cfxArgs.filter, - profileMemory: cfxArgs.profileMemory, - stopOnError: cfxArgs.stopOnError, - verbose: cfxArgs.verbose, - parseable: cfxArgs.parseable, - print: stdout.write, - onDone: onDone - })); -} - -function printFailedTests(tests, print) { - let iterationNumber = 0; - let singleIteration = (tests.testRuns || []).length == 1; - let padding = singleIteration ? "" : " "; - - print("\nThe following tests failed:\n"); - - for (let testRun of tests.testRuns) { - iterationNumber++; - - if (!singleIteration) - print(" Iteration " + iterationNumber + ":\n"); - - for (let test of testRun) { - if (test.failed > 0) { - print(padding + " " + test.name + ": " + test.errors +"\n"); - } - } - print("\n"); - } -} - -function main() { - var testsStarted = false; - - if (!testsStarted) { - testsStarted = true; - runTests(function findAndRunTests(loader, nextIteration) { - loader.require("../deprecated/unit-test").findAndRunTests({ - testOutOfProcess: false, - testInProcess: true, - stopOnError: cfxArgs.stopOnError, - filter: cfxArgs.filter, - onDone: nextIteration - }); - }); - } -}; - -if (require.main === module) - main(); - -exports.runTestsFromModule = function runTestsFromModule(module) { - let id = module.id; - // Make a copy of exports as it may already be frozen by module loader - let exports = {}; - Object.keys(module.exports).forEach(key => { - exports[key] = module.exports[key]; - }); - - runTests(function findAndRunTests(loader, nextIteration) { - // Consider that all these tests are CommonJS ones - loader.require('../../test').run(exports); - - // Reproduce what is done in sdk/deprecated/unit-test-finder.findTests() - let tests = []; - for (let name of Object.keys(exports).sort()) { - tests.push({ - setup: exports.setup, - teardown: exports.teardown, - testFunction: exports[name], - name: id + "." + name - }); - } - - // Reproduce what is done by unit-test.findAndRunTests() - var { TestRunner } = loader.require("../deprecated/unit-test"); - var runner = new TestRunner(); - runner.startMany({ - tests: { - getNext: () => resolve(tests.shift()) - }, - stopOnError: cfxArgs.stopOnError, - onDone: nextIteration - }); - }); -} diff --git a/addon-sdk/source/lib/sdk/test/utils.js b/addon-sdk/source/lib/sdk/test/utils.js deleted file mode 100644 index b01df67d4..000000000 --- a/addon-sdk/source/lib/sdk/test/utils.js +++ /dev/null @@ -1,199 +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' -}; - -const { defer } = require('../core/promise'); -const { setInterval, clearInterval } = require('../timers'); -const { getTabs, closeTab } = require("../tabs/utils"); -const { windows: getWindows } = require("../window/utils"); -const { close: closeWindow } = require("../window/helpers"); -const { isGenerator } = require("../lang/type"); -const { env } = require("../system/environment"); -const { Task } = require("resource://gre/modules/Task.jsm"); - -const getTestNames = (exports) => - Object.keys(exports).filter(name => /^test/.test(name)); - -const isTestAsync = ({length}) => length > 1; -const isHelperAsync = ({length}) => length > 2; - -/* - * Takes an `exports` object of a test file and a function `beforeFn` - * to be run before each test. `beforeFn` is called with a `name` string - * as the first argument of the test name, and may specify a second - * argument function `done` to indicate that this function should - * resolve asynchronously - */ -function before (exports, beforeFn) { - getTestNames(exports).map(name => { - let testFn = exports[name]; - - // GENERATOR TESTS - if (isGenerator(testFn) && isGenerator(beforeFn)) { - exports[name] = function*(assert) { - yield Task.spawn(beforeFn.bind(null, name, assert)); - yield Task.spawn(testFn.bind(null, assert)); - } - } - else if (isGenerator(testFn) && !isHelperAsync(beforeFn)) { - exports[name] = function*(assert) { - beforeFn(name, assert); - yield Task.spawn(testFn.bind(null, assert)); - } - } - else if (isGenerator(testFn) && isHelperAsync(beforeFn)) { - exports[name] = function*(assert) { - yield new Promise(resolve => beforeFn(name, assert, resolve)); - yield Task.spawn(testFn.bind(null, assert)); - } - } - // SYNC TESTS - else if (!isTestAsync(testFn) && isGenerator(beforeFn)) { - exports[name] = function*(assert) { - yield Task.spawn(beforeFn.bind(null, name, assert)); - testFn(assert); - }; - } - else if (!isTestAsync(testFn) && !isHelperAsync(beforeFn)) { - exports[name] = function (assert) { - beforeFn(name, assert); - testFn(assert); - }; - } - else if (!isTestAsync(testFn) && isHelperAsync(beforeFn)) { - exports[name] = function (assert, done) { - beforeFn(name, assert, () => { - testFn(assert); - done(); - }); - }; - } - // ASYNC TESTS - else if (isTestAsync(testFn) && isGenerator(beforeFn)) { - exports[name] = function*(assert) { - yield Task.spawn(beforeFn.bind(null, name, assert)); - yield new Promise(resolve => testFn(assert, resolve)); - }; - } - else if (isTestAsync(testFn) && !isHelperAsync(beforeFn)) { - exports[name] = function (assert, done) { - beforeFn(name, assert); - testFn(assert, done); - }; - } - else if (isTestAsync(testFn) && isHelperAsync(beforeFn)) { - exports[name] = function (assert, done) { - beforeFn(name, assert, () => { - testFn(assert, done); - }); - }; - } - }); -} -exports.before = before; - -/* - * Takes an `exports` object of a test file and a function `afterFn` - * to be run after each test. `afterFn` is called with a `name` string - * as the first argument of the test name, and may specify a second - * argument function `done` to indicate that this function should - * resolve asynchronously - */ -function after (exports, afterFn) { - getTestNames(exports).map(name => { - let testFn = exports[name]; - - // GENERATOR TESTS - if (isGenerator(testFn) && isGenerator(afterFn)) { - exports[name] = function*(assert) { - yield Task.spawn(testFn.bind(null, assert)); - yield Task.spawn(afterFn.bind(null, name, assert)); - } - } - else if (isGenerator(testFn) && !isHelperAsync(afterFn)) { - exports[name] = function*(assert) { - yield Task.spawn(testFn.bind(null, assert)); - afterFn(name, assert); - } - } - else if (isGenerator(testFn) && isHelperAsync(afterFn)) { - exports[name] = function*(assert) { - yield Task.spawn(testFn.bind(null, assert)); - yield new Promise(resolve => afterFn(name, assert, resolve)); - } - } - // SYNC TESTS - else if (!isTestAsync(testFn) && isGenerator(afterFn)) { - exports[name] = function*(assert) { - testFn(assert); - yield Task.spawn(afterFn.bind(null, name, assert)); - }; - } - else if (!isTestAsync(testFn) && !isHelperAsync(afterFn)) { - exports[name] = function (assert) { - testFn(assert); - afterFn(name, assert); - }; - } - else if (!isTestAsync(testFn) && isHelperAsync(afterFn)) { - exports[name] = function (assert, done) { - testFn(assert); - afterFn(name, assert, done); - }; - } - // ASYNC TESTS - else if (isTestAsync(testFn) && isGenerator(afterFn)) { - exports[name] = function*(assert) { - yield new Promise(resolve => testFn(assert, resolve)); - yield Task.spawn(afterFn.bind(null, name, assert)); - }; - } - else if (isTestAsync(testFn) && !isHelperAsync(afterFn)) { - exports[name] = function*(assert) { - yield new Promise(resolve => testFn(assert, resolve)); - afterFn(name, assert); - }; - } - else if (isTestAsync(testFn) && isHelperAsync(afterFn)) { - exports[name] = function*(assert) { - yield new Promise(resolve => testFn(assert, resolve)); - yield new Promise(resolve => afterFn(name, assert, resolve)); - }; - } - }); -} -exports.after = after; - -function waitUntil (predicate, delay) { - let { promise, resolve } = defer(); - let interval = setInterval(() => { - if (!predicate()) return; - clearInterval(interval); - resolve(); - }, delay || 10); - return promise; -} -exports.waitUntil = waitUntil; - -var cleanUI = function cleanUI() { - let { promise, resolve } = defer(); - - let windows = getWindows(null, { includePrivate: true }); - if (windows.length > 1) { - return closeWindow(windows[1]).then(cleanUI); - } - - getTabs(windows[0]).slice(1).forEach(closeTab); - - resolve(); - - return promise; -} -exports.cleanUI = cleanUI; - -exports.isTravisCI = ("TRAVIS" in env && "CI" in env); |