mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
2018f6f0f5
--HG-- extra : rebase_source : 6e967421250dd6093c0fcc89dcbd078c0812fcb6
786 lines
21 KiB
JavaScript
786 lines
21 KiB
JavaScript
/* 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/. */
|
|
|
|
var EXPORTED_SYMBOLS = ['Collector','Runner','events', 'runTestFile', 'log',
|
|
'timers', 'persisted', 'shutdownApplication'];
|
|
|
|
const Cc = Components.classes;
|
|
const Ci = Components.interfaces;
|
|
const Cu = Components.utils;
|
|
|
|
const TIMEOUT_SHUTDOWN_HTTPD = 15000;
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
Cu.import('resource://mozmill/stdlib/httpd.js');
|
|
|
|
var broker = {}; Cu.import('resource://mozmill/driver/msgbroker.js', broker);
|
|
var assertions = {}; Cu.import('resource://mozmill/modules/assertions.js', assertions);
|
|
var errors = {}; Cu.import('resource://mozmill/modules/errors.js', errors);
|
|
var os = {}; Cu.import('resource://mozmill/stdlib/os.js', os);
|
|
var strings = {}; Cu.import('resource://mozmill/stdlib/strings.js', strings);
|
|
var arrays = {}; Cu.import('resource://mozmill/stdlib/arrays.js', arrays);
|
|
var withs = {}; Cu.import('resource://mozmill/stdlib/withs.js', withs);
|
|
var utils = {}; Cu.import('resource://mozmill/stdlib/utils.js', utils);
|
|
|
|
var securableModule = {};
|
|
Cu.import('resource://mozmill/stdlib/securable-module.js', securableModule);
|
|
|
|
var uuidgen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
|
|
|
var httpd = null;
|
|
var persisted = {};
|
|
|
|
var assert = new assertions.Assert();
|
|
|
|
var mozmill = undefined;
|
|
var mozelement = undefined;
|
|
var modules = undefined;
|
|
|
|
var timers = [];
|
|
|
|
|
|
/**
|
|
* Shutdown or restart the application
|
|
*
|
|
* @param {boolean} [aFlags=undefined]
|
|
* Additional flags how to handle the shutdown or restart. The attributes
|
|
* eRestarti386 and eRestartx86_64 have not been documented yet.
|
|
* @see https://developer.mozilla.org/nsIAppStartup#Attributes
|
|
*/
|
|
function shutdownApplication(aFlags) {
|
|
var flags = Ci.nsIAppStartup.eForceQuit;
|
|
|
|
if (aFlags) {
|
|
flags |= aFlags;
|
|
}
|
|
|
|
// Send a request to shutdown the application. That will allow us and other
|
|
// components to finish up with any shutdown code. Please note that we don't
|
|
// care if other components or add-ons want to prevent this via cancelQuit,
|
|
// we really force the shutdown.
|
|
let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
|
|
createInstance(Components.interfaces.nsISupportsPRBool);
|
|
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
|
|
|
|
// Use a timer to trigger the application restart, which will allow us to
|
|
// send an ACK packet via jsbridge if the method has been called via Python.
|
|
var event = {
|
|
notify: function(timer) {
|
|
Services.startup.quit(flags);
|
|
}
|
|
}
|
|
|
|
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
timer.initWithCallback(event, 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
}
|
|
|
|
function stateChangeBase(possibilties, restrictions, target, cmeta, v) {
|
|
if (possibilties) {
|
|
if (!arrays.inArray(possibilties, v)) {
|
|
// TODO Error value not in this.poss
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (restrictions) {
|
|
for (var i in restrictions) {
|
|
var r = restrictions[i];
|
|
if (!r(v)) {
|
|
// TODO error value did not pass restriction
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fire jsbridge notification, logging notification, listener notifications
|
|
events[target] = v;
|
|
events.fireEvent(cmeta, target);
|
|
}
|
|
|
|
|
|
var events = {
|
|
appQuit : false,
|
|
currentModule : null,
|
|
currentState : null,
|
|
currentTest : null,
|
|
shutdownRequested : false,
|
|
userShutdown : null,
|
|
userShutdownTimer : null,
|
|
|
|
listeners : {},
|
|
globalListeners : []
|
|
}
|
|
|
|
events.setState = function (v) {
|
|
return stateChangeBase(['dependencies', 'setupModule', 'teardownModule',
|
|
'test', 'setupTest', 'teardownTest', 'collection'],
|
|
null, 'currentState', 'setState', v);
|
|
}
|
|
|
|
events.toggleUserShutdown = function (obj){
|
|
if (!this.userShutdown) {
|
|
this.userShutdown = obj;
|
|
|
|
var event = {
|
|
notify: function(timer) {
|
|
events.toggleUserShutdown(obj);
|
|
}
|
|
}
|
|
|
|
this.userShutdownTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
this.userShutdownTimer.initWithCallback(event, obj.timeout, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
} else {
|
|
this.userShutdownTimer.cancel();
|
|
|
|
// If the application is not going to shutdown, the user shutdown failed and
|
|
// we have to force a shutdown.
|
|
if (!events.appQuit) {
|
|
this.fail({'function':'events.toggleUserShutdown',
|
|
'message':'Shutdown expected but none detected before timeout',
|
|
'userShutdown': obj});
|
|
|
|
var flags = Ci.nsIAppStartup.eAttemptQuit;
|
|
if (events.isRestartShutdown()) {
|
|
flags |= Ci.nsIAppStartup.eRestart;
|
|
}
|
|
|
|
shutdownApplication(flags);
|
|
}
|
|
}
|
|
}
|
|
|
|
events.isUserShutdown = function () {
|
|
return this.userShutdown ? this.userShutdown["user"] : false;
|
|
}
|
|
|
|
events.isRestartShutdown = function () {
|
|
return this.userShutdown.restart;
|
|
}
|
|
|
|
events.startShutdown = function (obj) {
|
|
events.fireEvent('shutdown', obj);
|
|
|
|
if (obj["user"]) {
|
|
events.toggleUserShutdown(obj);
|
|
} else {
|
|
shutdownApplication(obj.flags);
|
|
}
|
|
}
|
|
|
|
events.setTest = function (test) {
|
|
test.__start__ = Date.now();
|
|
test.__passes__ = [];
|
|
test.__fails__ = [];
|
|
|
|
events.currentTest = test;
|
|
|
|
var obj = {'filename': events.currentModule.__file__,
|
|
'name': test.__name__}
|
|
events.fireEvent('setTest', obj);
|
|
}
|
|
|
|
events.endTest = function (test) {
|
|
// use the current test unless specified
|
|
if (test === undefined) {
|
|
test = events.currentTest;
|
|
}
|
|
|
|
// If no test is set it has already been reported. Beside that we don't want
|
|
// to report it a second time.
|
|
if (!test || test.status === 'done')
|
|
return;
|
|
|
|
// report the end of a test
|
|
test.__end__ = Date.now();
|
|
test.status = 'done';
|
|
|
|
var obj = {'filename': events.currentModule.__file__,
|
|
'passed': test.__passes__.length,
|
|
'failed': test.__fails__.length,
|
|
'passes': test.__passes__,
|
|
'fails' : test.__fails__,
|
|
'name' : test.__name__,
|
|
'time_start': test.__start__,
|
|
'time_end': test.__end__}
|
|
|
|
if (test.skipped) {
|
|
obj['skipped'] = true;
|
|
obj.skipped_reason = test.skipped_reason;
|
|
}
|
|
|
|
if (test.meta) {
|
|
obj.meta = test.meta;
|
|
}
|
|
|
|
// Report the test result only if the test is a true test or if it is failing
|
|
if (withs.startsWith(test.__name__, "test") || test.__fails__.length > 0) {
|
|
events.fireEvent('endTest', obj);
|
|
}
|
|
}
|
|
|
|
events.setModule = function (aModule) {
|
|
aModule.__start__ = Date.now();
|
|
aModule.__status__ = 'running';
|
|
|
|
var result = stateChangeBase(null,
|
|
[function (aModule) {return (aModule.__file__ != undefined)}],
|
|
'currentModule', 'setModule', aModule);
|
|
|
|
return result;
|
|
}
|
|
|
|
events.endModule = function (aModule) {
|
|
// It should only reported once, so check if it already has been done
|
|
if (aModule.__status__ === 'done')
|
|
return;
|
|
|
|
aModule.__end__ = Date.now();
|
|
aModule.__status__ = 'done';
|
|
|
|
var obj = {
|
|
'filename': aModule.__file__,
|
|
'time_start': aModule.__start__,
|
|
'time_end': aModule.__end__
|
|
}
|
|
|
|
events.fireEvent('endModule', obj);
|
|
}
|
|
|
|
events.pass = function (obj) {
|
|
// a low level event, such as a keystroke, succeeds
|
|
if (events.currentTest) {
|
|
events.currentTest.__passes__.push(obj);
|
|
}
|
|
|
|
for each (var timer in timers) {
|
|
timer.actions.push(
|
|
{"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__,
|
|
"obj": obj,
|
|
"result": "pass"}
|
|
);
|
|
}
|
|
|
|
events.fireEvent('pass', obj);
|
|
}
|
|
|
|
events.fail = function (obj) {
|
|
var error = obj.exception;
|
|
|
|
if (error) {
|
|
// Error objects aren't enumerable https://bugzilla.mozilla.org/show_bug.cgi?id=637207
|
|
obj.exception = {
|
|
name: error.name,
|
|
message: error.message,
|
|
lineNumber: error.lineNumber,
|
|
fileName: error.fileName,
|
|
stack: error.stack
|
|
};
|
|
}
|
|
|
|
// a low level event, such as a keystroke, fails
|
|
if (events.currentTest) {
|
|
events.currentTest.__fails__.push(obj);
|
|
}
|
|
|
|
for each (var time in timers) {
|
|
timer.actions.push(
|
|
{"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__,
|
|
"obj": obj,
|
|
"result": "fail"}
|
|
);
|
|
}
|
|
|
|
events.fireEvent('fail', obj);
|
|
}
|
|
|
|
events.skip = function (reason) {
|
|
// this is used to report skips associated with setupModule and nothing else
|
|
events.currentTest.skipped = true;
|
|
events.currentTest.skipped_reason = reason;
|
|
|
|
for (var timer of timers) {
|
|
timer.actions.push(
|
|
{"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__,
|
|
"obj": reason,
|
|
"result": "skip"}
|
|
);
|
|
}
|
|
|
|
events.fireEvent('skip', reason);
|
|
}
|
|
|
|
events.fireEvent = function (name, obj) {
|
|
if (events.appQuit) {
|
|
// dump('* Event discarded: ' + name + ' ' + JSON.stringify(obj) + '\n');
|
|
return;
|
|
}
|
|
|
|
if (this.listeners[name]) {
|
|
for (var i in this.listeners[name]) {
|
|
this.listeners[name][i](obj);
|
|
}
|
|
}
|
|
|
|
for each(var listener in this.globalListeners) {
|
|
listener(name, obj);
|
|
}
|
|
}
|
|
|
|
events.addListener = function (name, listener) {
|
|
if (this.listeners[name]) {
|
|
this.listeners[name].push(listener);
|
|
} else if (name == '') {
|
|
this.globalListeners.push(listener)
|
|
} else {
|
|
this.listeners[name] = [listener];
|
|
}
|
|
}
|
|
|
|
events.removeListener = function (listener) {
|
|
for (var listenerIndex in this.listeners) {
|
|
var e = this.listeners[listenerIndex];
|
|
|
|
for (var i in e){
|
|
if (e[i] == listener) {
|
|
this.listeners[listenerIndex] = arrays.remove(e, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i in this.globalListeners) {
|
|
if (this.globalListeners[i] == listener) {
|
|
this.globalListeners = arrays.remove(this.globalListeners, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
events.persist = function () {
|
|
try {
|
|
events.fireEvent('persist', persisted);
|
|
} catch (e) {
|
|
events.fireEvent('error', "persist serialization failed.")
|
|
}
|
|
}
|
|
|
|
events.firePythonCallback = function (obj) {
|
|
obj['test'] = events.currentModule.__file__;
|
|
events.fireEvent('firePythonCallback', obj);
|
|
}
|
|
|
|
events.screenshot = function (obj) {
|
|
// Find the name of the test function
|
|
for (var attr in events.currentModule) {
|
|
if (events.currentModule[attr] == events.currentTest) {
|
|
var testName = attr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
obj['test_file'] = events.currentModule.__file__;
|
|
obj['test_name'] = testName;
|
|
events.fireEvent('screenshot', obj);
|
|
}
|
|
|
|
var log = function (obj) {
|
|
events.fireEvent('log', obj);
|
|
}
|
|
|
|
// Register the listeners
|
|
broker.addObject({'endTest': events.endTest,
|
|
'fail': events.fail,
|
|
'firePythonCallback': events.firePythonCallback,
|
|
'log': log,
|
|
'pass': events.pass,
|
|
'persist': events.persist,
|
|
'screenshot': events.screenshot,
|
|
'shutdown': events.startShutdown,
|
|
});
|
|
|
|
try {
|
|
Cu.import('resource://jsbridge/modules/Events.jsm');
|
|
|
|
events.addListener('', function (name, obj) {
|
|
Events.fireEvent('mozmill.' + name, obj);
|
|
});
|
|
} catch (e) {
|
|
Services.console.logStringMessage("Event module of JSBridge not available.");
|
|
}
|
|
|
|
|
|
/**
|
|
* Observer for notifications when the application is going to shutdown
|
|
*/
|
|
function AppQuitObserver() {
|
|
this.runner = null;
|
|
|
|
Services.obs.addObserver(this, "quit-application-requested", false);
|
|
}
|
|
|
|
AppQuitObserver.prototype = {
|
|
observe: function (aSubject, aTopic, aData) {
|
|
switch (aTopic) {
|
|
case "quit-application-requested":
|
|
Services.obs.removeObserver(this, "quit-application-requested");
|
|
|
|
// If we observe a quit notification make sure to send the
|
|
// results of the current test. In those cases we don't reach
|
|
// the equivalent code in runTestModule()
|
|
events.pass({'message': 'AppQuitObserver: ' + JSON.stringify(aData),
|
|
'userShutdown': events.userShutdown});
|
|
|
|
if (this.runner) {
|
|
this.runner.end();
|
|
}
|
|
|
|
if (httpd) {
|
|
httpd.stop();
|
|
}
|
|
|
|
events.appQuit = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
var appQuitObserver = new AppQuitObserver();
|
|
|
|
/**
|
|
* The collector handles HTTPd.js and initilizing the module
|
|
*/
|
|
function Collector() {
|
|
this.test_modules_by_filename = {};
|
|
this.testing = [];
|
|
}
|
|
|
|
Collector.prototype.addHttpResource = function (aDirectory, aPath) {
|
|
var fp = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
|
fp.initWithPath(os.abspath(aDirectory, this.current_file));
|
|
|
|
return httpd.addHttpResource(fp, aPath);
|
|
}
|
|
|
|
Collector.prototype.initTestModule = function (filename, testname) {
|
|
var test_module = this.loadFile(filename, this);
|
|
var has_restarted = !(testname == null);
|
|
test_module.__tests__ = [];
|
|
|
|
for (var i in test_module) {
|
|
if (typeof(test_module[i]) == "function") {
|
|
test_module[i].__name__ = i;
|
|
|
|
// Only run setupModule if we are a single test OR if we are the first
|
|
// test of a restart chain (don't run it prior to members in a restart
|
|
// chain)
|
|
if (i == "setupModule" && !has_restarted) {
|
|
test_module.__setupModule__ = test_module[i];
|
|
} else if (i == "setupTest") {
|
|
test_module.__setupTest__ = test_module[i];
|
|
} else if (i == "teardownTest") {
|
|
test_module.__teardownTest__ = test_module[i];
|
|
} else if (i == "teardownModule") {
|
|
test_module.__teardownModule__ = test_module[i];
|
|
} else if (withs.startsWith(i, "test")) {
|
|
if (testname && (i != testname)) {
|
|
continue;
|
|
}
|
|
|
|
testname = null;
|
|
test_module.__tests__.push(test_module[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
test_module.collector = this;
|
|
test_module.status = 'loaded';
|
|
|
|
this.test_modules_by_filename[filename] = test_module;
|
|
|
|
return test_module;
|
|
}
|
|
|
|
Collector.prototype.loadFile = function (path, collector) {
|
|
var moduleLoader = new securableModule.Loader({
|
|
rootPaths: ["resource://mozmill/modules/"],
|
|
defaultPrincipal: "system",
|
|
globals : { Cc: Cc,
|
|
Ci: Ci,
|
|
Cu: Cu,
|
|
Cr: Components.results}
|
|
});
|
|
|
|
// load a test module from a file and add some candy
|
|
var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
|
file.initWithPath(path);
|
|
var uri = Services.io.newFileURI(file).spec;
|
|
|
|
this.loadTestResources();
|
|
|
|
var systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
|
var module = new Components.utils.Sandbox(systemPrincipal);
|
|
module.assert = new assertions.Assert();
|
|
module.Cc = Cc;
|
|
module.Ci = Ci;
|
|
module.Cr = Components.results;
|
|
module.Cu = Cu;
|
|
module.collector = collector;
|
|
module.driver = moduleLoader.require("driver");
|
|
module.elementslib = mozelement;
|
|
module.errors = errors;
|
|
module.expect = new assertions.Expect();
|
|
module.findElement = mozelement;
|
|
module.log = log;
|
|
module.mozmill = mozmill;
|
|
module.persisted = persisted;
|
|
|
|
module.require = function (mod) {
|
|
var loader = new securableModule.Loader({
|
|
rootPaths: [Services.io.newFileURI(file.parent).spec,
|
|
"resource://mozmill/modules/"],
|
|
defaultPrincipal: "system",
|
|
globals : { mozmill: mozmill,
|
|
elementslib: mozelement, // This a quick hack to maintain backwards compatibility with 1.5.x
|
|
findElement: mozelement,
|
|
persisted: persisted,
|
|
Cc: Cc,
|
|
Ci: Ci,
|
|
Cu: Cu,
|
|
log: log }
|
|
});
|
|
|
|
if (modules != undefined) {
|
|
loader.modules = modules;
|
|
}
|
|
|
|
var retval = loader.require(mod);
|
|
modules = loader.modules;
|
|
|
|
return retval;
|
|
}
|
|
|
|
if (collector != undefined) {
|
|
collector.current_file = file;
|
|
collector.current_path = path;
|
|
}
|
|
|
|
try {
|
|
Services.scriptloader.loadSubScript(uri, module, "UTF-8");
|
|
} catch (e) {
|
|
var obj = {
|
|
'filename': path,
|
|
'passed': 0,
|
|
'failed': 1,
|
|
'passes': [],
|
|
'fails' : [{'exception' : {
|
|
message: e.message,
|
|
filename: e.filename,
|
|
lineNumber: e.lineNumber}}],
|
|
'name' :'<TOP_LEVEL>'
|
|
};
|
|
|
|
events.fail({'exception': e});
|
|
events.fireEvent('endTest', obj);
|
|
}
|
|
|
|
module.__file__ = path;
|
|
module.__uri__ = uri;
|
|
|
|
return module;
|
|
}
|
|
|
|
Collector.prototype.loadTestResources = function () {
|
|
// load resources we want in our tests
|
|
if (mozmill === undefined) {
|
|
mozmill = {};
|
|
Cu.import("resource://mozmill/driver/mozmill.js", mozmill);
|
|
}
|
|
if (mozelement === undefined) {
|
|
mozelement = {};
|
|
Cu.import("resource://mozmill/driver/mozelement.js", mozelement);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
function Httpd(aPort) {
|
|
this.http_port = aPort;
|
|
|
|
while (true) {
|
|
try {
|
|
var srv = new HttpServer();
|
|
srv.registerContentType("sjs", "sjs");
|
|
srv.identity.setPrimary("http", "localhost", this.http_port);
|
|
srv.start(this.http_port);
|
|
|
|
this._httpd = srv;
|
|
break;
|
|
}
|
|
catch (e) {
|
|
// Failure most likely due to port conflict
|
|
this.http_port++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Httpd.prototype.addHttpResource = function (aDir, aPath) {
|
|
var path = aPath ? ("/" + aPath + "/") : "/";
|
|
|
|
try {
|
|
this._httpd.registerDirectory(path, aDir);
|
|
return 'http://localhost:' + this.http_port + path;
|
|
}
|
|
catch (e) {
|
|
throw Error("Failure to register directory: " + aDir.path);
|
|
}
|
|
};
|
|
|
|
Httpd.prototype.stop = function () {
|
|
if (!this._httpd) {
|
|
return;
|
|
}
|
|
|
|
var shutdown = false;
|
|
this._httpd.stop(function () { shutdown = true; });
|
|
|
|
assert.waitFor(function () {
|
|
return shutdown;
|
|
}, "Local HTTP server has been stopped", TIMEOUT_SHUTDOWN_HTTPD);
|
|
|
|
this._httpd = null;
|
|
};
|
|
|
|
function startHTTPd() {
|
|
if (!httpd) {
|
|
// Ensure that we start the HTTP server only once during a session
|
|
httpd = new Httpd(43336);
|
|
}
|
|
}
|
|
|
|
|
|
function Runner() {
|
|
this.collector = new Collector();
|
|
this.ended = false;
|
|
|
|
var m = {}; Cu.import('resource://mozmill/driver/mozmill.js', m);
|
|
this.platform = m.platform;
|
|
|
|
events.fireEvent('startRunner', true);
|
|
}
|
|
|
|
Runner.prototype.end = function () {
|
|
if (!this.ended) {
|
|
this.ended = true;
|
|
|
|
appQuitObserver.runner = null;
|
|
|
|
events.endTest();
|
|
events.endModule(events.currentModule);
|
|
events.fireEvent('endRunner', true);
|
|
events.persist();
|
|
}
|
|
};
|
|
|
|
Runner.prototype.runTestFile = function (filename, name) {
|
|
var module = this.collector.initTestModule(filename, name);
|
|
this.runTestModule(module);
|
|
};
|
|
|
|
Runner.prototype.runTestModule = function (module) {
|
|
appQuitObserver.runner = this;
|
|
events.setModule(module);
|
|
|
|
// If setupModule passes, run all the tests. Otherwise mark them as skipped.
|
|
if (this.execFunction(module.__setupModule__, module)) {
|
|
for (var test of module.__tests__) {
|
|
if (events.shutdownRequested) {
|
|
break;
|
|
}
|
|
|
|
// If setupTest passes, run the test. Otherwise mark it as skipped.
|
|
if (this.execFunction(module.__setupTest__, module)) {
|
|
this.execFunction(test);
|
|
} else {
|
|
this.skipFunction(test, module.__setupTest__.__name__ + " failed");
|
|
}
|
|
|
|
this.execFunction(module.__teardownTest__, module);
|
|
}
|
|
|
|
} else {
|
|
for (var test of module.__tests__) {
|
|
this.skipFunction(test, module.__setupModule__.__name__ + " failed");
|
|
}
|
|
}
|
|
|
|
this.execFunction(module.__teardownModule__, module);
|
|
events.endModule(module);
|
|
};
|
|
|
|
Runner.prototype.execFunction = function (func, arg) {
|
|
if (typeof func !== "function" || events.shutdownRequested) {
|
|
return true;
|
|
}
|
|
|
|
var isTest = withs.startsWith(func.__name__, "test");
|
|
|
|
events.setState(isTest ? "test" : func.__name);
|
|
events.setTest(func);
|
|
|
|
// skip excluded platforms
|
|
if (func.EXCLUDED_PLATFORMS != undefined) {
|
|
if (arrays.inArray(func.EXCLUDED_PLATFORMS, this.platform)) {
|
|
events.skip("Platform exclusion");
|
|
events.endTest(func);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// skip function if requested
|
|
if (func.__force_skip__ != undefined) {
|
|
events.skip(func.__force_skip__);
|
|
events.endTest(func);
|
|
return false;
|
|
}
|
|
|
|
// execute the test function
|
|
try {
|
|
func(arg);
|
|
} catch (e) {
|
|
if (e instanceof errors.ApplicationQuitError) {
|
|
events.shutdownRequested = true;
|
|
} else {
|
|
events.fail({'exception': e, 'test': func})
|
|
}
|
|
}
|
|
|
|
// If a user shutdown has been requested and the function already returned,
|
|
// we can assume that a shutdown will not happen anymore. We should force a
|
|
// shutdown then, to prevent the next test from being executed.
|
|
if (events.isUserShutdown()) {
|
|
events.shutdownRequested = true;
|
|
events.toggleUserShutdown(events.userShutdown);
|
|
}
|
|
|
|
events.endTest(func);
|
|
return events.currentTest.__fails__.length == 0;
|
|
};
|
|
|
|
function runTestFile(filename, name) {
|
|
var runner = new Runner();
|
|
runner.runTestFile(filename, name);
|
|
runner.end();
|
|
|
|
return true;
|
|
}
|
|
|
|
Runner.prototype.skipFunction = function (func, message) {
|
|
events.setTest(func);
|
|
events.skip(message);
|
|
events.endTest(func);
|
|
};
|