Skip to content
This repository has been archived by the owner on Feb 26, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1511 from erikvold/1024791
Browse files Browse the repository at this point in the history
Bug 1024791 - Scan the add-on for tests r=@Gozala
  • Loading branch information
erikvold committed Jun 16, 2014
2 parents baf961a + 1527be4 commit a9750f0
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 107 deletions.
1 change: 0 additions & 1 deletion app-extension/bootstrap.js
Expand Up @@ -233,7 +233,6 @@ function startup(data, reasonCode) {
// Arguments related to test runner.
modules: {
'@test/options': {
allTestModules: options.allTestModules,
iterations: options.iterations,
filter: options.filter,
profileMemory: options.profileMemory,
Expand Down
4 changes: 2 additions & 2 deletions lib/sdk/addon/installer.js
Expand Up @@ -54,7 +54,6 @@ exports.install = function install(xpiPath) {
setTimeout(resolve, 0, aAddon.id);
},
onInstallFailed: function (aInstall) {
console.log("failed");
aInstall.removeListener(listener);
reject(aInstall.error);
},
Expand Down Expand Up @@ -114,8 +113,9 @@ exports.isActive = function isActive(addonId) {
return getAddon(addonId).then(addon => addon.isActive && !addon.appDisabled);
};

function getAddon (id) {
const getAddon = function getAddon (id) {
let { promise, resolve, reject } = defer();
AddonManager.getAddonByID(id, addon => addon ? resolve(addon) : reject());
return promise;
}
exports.getAddon = getAddon;
2 changes: 0 additions & 2 deletions lib/sdk/addon/window.js
Expand Up @@ -56,8 +56,6 @@ eventTarget.addEventListener("DOMContentLoaded", function handler(event) {
resolve();
}, false);



exports.ready = promise;
exports.window = window;

Expand Down
152 changes: 108 additions & 44 deletions lib/sdk/deprecated/unit-test-finder.js
@@ -1,7 +1,6 @@
/* 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 = {
Expand All @@ -10,9 +9,97 @@ module.metadata = {

const file = require("../io/file");
const memory = require('./memory');
const suites = require('@test/options').allTestModules;
const { Loader } = require("sdk/test/loader");
const cuddlefish = require("sdk/loader/cuddlefish");
const { Loader } = require("../test/loader");
const cuddlefish = require("../loader/cuddlefish");
const { defer, resolve } = require("../core/promise");
const { getAddon } = require("../addon/installer");
const { id } = require("sdk/self");
const { newURI } = require('sdk/url/utils');
const { getZipReader } = require("../zip/utils");

const { Cc, Ci, Cu } = require("chrome");
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
var ios = Cc['@mozilla.org/network/io-service;1']
.getService(Ci.nsIIOService);

const TEST_REGEX = /(tests?\/test-[^\.\/]+)\.js$/;

const { mapcat, map, filter, fromEnumerator } = require("sdk/util/sequence");

const toFile = x => x.QueryInterface(Ci.nsIFile);
const isTestFile = ({leafName}) => leafName.substr(0, 5) == "test-" && leafName.substr(-3, 3) == ".js";
const getFileURI = x => ios.newFileURI(x).spec;

const getDirectoryEntries = file => map(toFile, fromEnumerator(_ => file.directoryEntries));
const getTestFiles = directory => filter(isTestFile, getDirectoryEntries(directory));
const getTestURIs = directory => map(getFileURI, getTestFiles(directory));

const isDirectory = x => x.isDirectory();
const getTestEntries = directory => mapcat(entry =>
/^tests?$/.test(entry.leafName) ? getTestURIs(entry) : getTestEntries(entry),
filter(isDirectory, getDirectoryEntries(directory)));

const getSuites = function getSuites({ id }) {
return getAddon(id).then(addon => {
let fileURI = addon.getResourceURI("tests/");
let isPacked = fileURI.scheme == "jar";
let xpiURI = addon.getResourceURI();
let file = xpiURI.QueryInterface(Ci.nsIFileURL).file;
let suites = [];

if (isPacked) {
return getZipReader(file).then(zip => {
let entries = zip.findEntries(null);
while (entries.hasMore()) {
let entry = entries.getNext();
if (TEST_REGEX.test(entry)) {
suites.push(RegExp.$1);
}
}
zip.close();
return suites.sort();
})
} else {
let tests = getTestEntries(file);
[...tests].forEach(path => {
if (TEST_REGEX.test(path)) {
suites.push(RegExp.$1);
}
});
}

return suites.sort();
});
}
exports.getSuites = getSuites;

const makeFilter = function makeFilter(options) {
// A filter string is {fileNameRegex}[:{testNameRegex}] - ie, a colon
// optionally separates a regex for the test fileName from a regex for the
// testName.
if (options.filter) {
let colonPos = this.filter.indexOf(':');
let filterFileRegex, filterNameRegex;

if (colonPos === -1) {
filterFileRegex = new RegExp(options.filter);
} else {
filterFileRegex = new RegExp(options.filter.substr(0, colonPos));
filterNameRegex = new RegExp(options.filter.substr(colonPos + 1));
}
// This function will first be called with just the filename; if
// it returns true the module will be loaded then the function
// called again with both the filename and the testname.
return (filename, testname) => {
return filterFileRegex.test(filename) &&
((testname && filterNameRegex) ? filterNameRegex.test(testname)
: true);
};
}

return () => true;
}
exports.makeFilter = makeFilter;

let loader = Loader(module);
const NOT_TESTS = ['setup', 'teardown'];
Expand All @@ -25,65 +112,42 @@ var TestFinder = exports.TestFinder = function TestFinder(options) {
};

TestFinder.prototype = {
findTests: function findTests(cb) {
var self = this;
var tests = [];
var filter;
// A filter string is {fileNameRegex}[:{testNameRegex}] - ie, a colon
// optionally separates a regex for the test fileName from a regex for the
// testName.
if (this.filter) {
var colonPos = this.filter.indexOf(':');
var filterFileRegex, filterNameRegex;
if (colonPos === -1) {
filterFileRegex = new RegExp(self.filter);
} else {
filterFileRegex = new RegExp(self.filter.substr(0, colonPos));
filterNameRegex = new RegExp(self.filter.substr(colonPos + 1));
}
// This function will first be called with just the filename; if
// it returns true the module will be loaded then the function
// called again with both the filename and the testname.
filter = function(filename, testname) {
return filterFileRegex.test(filename) &&
((testname && filterNameRegex) ? filterNameRegex.test(testname)
: true);
};
} else
filter = function() {return true};

suites.forEach(function(suite) {
findTests: function findTests() {
return getSuites({ id: id }).then(suites => {
let filter = makeFilter({ filter: this.filter });
let tests = [];

suites.forEach(suite => {
// Load each test file as a main module in its own loader instance
// `suite` is defined by cuddlefish/manifest.py:ManifestBuilder.build

let suiteModule;

try {
suiteModule = cuddlefish.main(loader, suite);
}
catch (e) {
if (!/^Unsupported Application/.test(e.message))
throw e;
// If `Unsupported Application` error thrown during test,
// skip the test suite
suiteModule = {
'test suite skipped': assert => assert.pass(e.message)
};
}

if (self.testInProcess)
if (this.testInProcess) {
for each (let name in Object.keys(suiteModule).sort()) {
if(NOT_TESTS.indexOf(name) === -1 && filter(suite, name)) {
if (NOT_TESTS.indexOf(name) === -1 && filter(suite, name)) {
tests.push({
setup: suiteModule.setup,
teardown: suiteModule.teardown,
testFunction: suiteModule[name],
name: suite + "." + name
});
setup: suiteModule.setup,
teardown: suiteModule.teardown,
testFunction: suiteModule[name],
name: suite + "." + name
});
}
}
});
}
})

cb(tests);
return tests;
});
}
};
53 changes: 26 additions & 27 deletions lib/sdk/deprecated/unit-test.js
@@ -1,7 +1,6 @@
/* 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 = {
Expand All @@ -14,23 +13,25 @@ var cfxArgs = require("@test/options");
const { getTabs, getURI } = require("../tabs/utils");
const { windows, isBrowser } = require("../window/utils");

exports.findAndRunTests = function findAndRunTests(options) {
const findAndRunTests = function findAndRunTests(options) {
var TestFinder = require("./unit-test-finder").TestFinder;
var finder = new TestFinder({
filter: options.filter,
testInProcess: options.testInProcess,
testOutOfProcess: options.testOutOfProcess
});
var runner = new TestRunner({fs: options.fs});
finder.findTests(
function (tests) {
runner.startMany({tests: tests,
stopOnError: options.stopOnError,
onDone: options.onDone});
finder.findTests().then(tests => {
runner.startMany({
tests: tests,
stopOnError: options.stopOnError,
onDone: options.onDone
});
});
};
exports.findAndRunTests = findAndRunTests;

var TestRunner = exports.TestRunner = function TestRunner(options) {
const TestRunner = function TestRunner(options) {
if (options) {
this.fs = options.fs;
}
Expand Down Expand Up @@ -252,9 +253,9 @@ TestRunner.prototype = {
assertArray: function(a, message) {
this.assertStrictEqual('[object Array]', Object.prototype.toString.apply(a), message);
},

assertNumber: function(a, message) {
this.assertStrictEqual('[object Number]', Object.prototype.toString.apply(a), message);
this.assertStrictEqual('[object Number]', Object.prototype.toString.apply(a), message);
},

done: function done() {
Expand Down Expand Up @@ -321,32 +322,32 @@ TestRunner.prototype = {
}
}
},

// Set of assertion functions to wait for an assertion to become true
// These functions take the same arguments as the TestRunner.assert* methods.
waitUntil: function waitUntil() {
return this._waitUntil(this.assert, arguments);
},

waitUntilNotEqual: function waitUntilNotEqual() {
return this._waitUntil(this.assertNotEqual, arguments);
},

waitUntilEqual: function waitUntilEqual() {
return this._waitUntil(this.assertEqual, arguments);
},

waitUntilMatches: function waitUntilMatches() {
return this._waitUntil(this.assertMatches, arguments);
},

/**
* Internal function that waits for an assertion to become true.
* @param {Function} assertionMethod
* Reference to a TestRunner assertion method like test.assert,
* Reference to a TestRunner assertion method like test.assert,
* test.assertEqual, ...
* @param {Array} args
* List of arguments to give to the previous assertion method.
* List of arguments to give to the previous assertion method.
* All functions in this list are going to be called to retrieve current
* assertion values.
*/
Expand All @@ -360,7 +361,6 @@ TestRunner.prototype = {

let callback = null;
let finished = false;

let test = this;

// capture a traceback before we go async.
Expand Down Expand Up @@ -398,8 +398,8 @@ TestRunner.prototype = {
timeout = timer.setTimeout(loop, test.PAUSE_DELAY);
}
};
// Automatically call args closures in order to build arguments for

// Automatically call args closures in order to build arguments for
// assertion function
let appliedArgs = [];
for (let i = 0, l = args.length; i < l; i++) {
Expand All @@ -417,27 +417,25 @@ TestRunner.prototype = {
}
appliedArgs.push(a);
}

// Finally call assertion function with current assertion values
assertionMethod.apply(mock, appliedArgs);
}
loop();
this.waitUntilCallback = loop;
// Return an object with `then` method, to offer a way to execute

// Return an object with `then` method, to offer a way to execute
// some code when the assertion passed or failed
return {
then: function (c) {
callback = c;

then: function (callback) {
// In case of immediate positive result, we need to execute callback
// immediately here:
if (finished)
callback();
}
};
},

waitUntilDone: function waitUntilDone(ms) {
if (ms === undefined)
ms = this.DEFAULT_PAUSE_TIMEOUT;
Expand Down Expand Up @@ -514,3 +512,4 @@ TestRunner.prototype = {
this.done();
}
};
exports.TestRunner = TestRunner;
5 changes: 1 addition & 4 deletions lib/sdk/test/harness.js
Expand Up @@ -621,7 +621,4 @@ var runTests = exports.runTests = function runTests(options) {
}
};

unload(function() {
cService.unregisterListener(consoleListener);
});

unload(_ => cService.unregisterListener(consoleListener));

0 comments on commit a9750f0

Please sign in to comment.