зеркало из https://github.com/mozilla/gecko-dev.git
209 строки
5.9 KiB
JavaScript
209 строки
5.9 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/. */
|
|
|
|
"use strict";
|
|
|
|
const {utils: Cu} = Components;
|
|
|
|
Cu.import("chrome://marionette/content/error.js");
|
|
|
|
this.EXPORTED_SYMBOLS = ["simpletest"];
|
|
|
|
this.simpletest = {};
|
|
|
|
/**
|
|
* The simpletest harness, exposed in the script evaluation sandbox.
|
|
*/
|
|
simpletest.Harness = class {
|
|
constructor(window, context, contentLogger, timeout, testName) {
|
|
this.window = window;
|
|
this.tests = [];
|
|
this.logger = contentLogger;
|
|
this.context = context;
|
|
this.timeout = timeout;
|
|
this.testName = testName;
|
|
this.TEST_UNEXPECTED_FAIL = "TEST-UNEXPECTED-FAIL";
|
|
this.TEST_UNEXPECTED_PASS = "TEST-UNEXPECTED-PASS";
|
|
this.TEST_PASS = "TEST-PASS";
|
|
this.TEST_KNOWN_FAIL = "TEST-KNOWN-FAIL";
|
|
}
|
|
|
|
get exports() {
|
|
return new Map([
|
|
["ok", this.ok.bind(this)],
|
|
["is", this.is.bind(this)],
|
|
["isnot", this.isnot.bind(this)],
|
|
["todo", this.todo.bind(this)],
|
|
["log", this.log.bind(this)],
|
|
["getLogs", this.getLogs.bind(this)],
|
|
["generate_results", this.generate_results.bind(this)],
|
|
["waitFor", this.waitFor.bind(this)],
|
|
["TEST_PASS", this.TEST_PASS],
|
|
["TEST_KNOWN_FAIL", this.TEST_KNOWN_FAIL],
|
|
["TEST_UNEXPECTED_FAIL", this.TEST_UNEXPECTED_FAIL],
|
|
["TEST_UNEXPECTED_PASS", this.TEST_UNEXPECTED_PASS],
|
|
]);
|
|
}
|
|
|
|
addTest(condition, name, passString, failString, diag, state) {
|
|
let test = {
|
|
result: !!condition,
|
|
name: name,
|
|
diag: diag,
|
|
state: state
|
|
};
|
|
this.logResult(
|
|
test,
|
|
typeof passString == "undefined" ? this.TEST_PASS : passString,
|
|
typeof failString == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString);
|
|
this.tests.push(test);
|
|
}
|
|
|
|
ok(condition, name, passString, failString) {
|
|
let diag = `${this.repr(condition)} was ${!!condition}, expected true`;
|
|
this.addTest(condition, name, passString, failString, diag);
|
|
}
|
|
|
|
is(a, b, name, passString, failString) {
|
|
let pass = (a == b);
|
|
let diag = pass ? this.repr(a) + " should equal " + this.repr(b)
|
|
: "got " + this.repr(a) + ", expected " + this.repr(b);
|
|
this.addTest(pass, name, passString, failString, diag);
|
|
}
|
|
|
|
isnot(a, b, name, passString, failString) {
|
|
let pass = (a != b);
|
|
let diag = pass ? this.repr(a) + " should not equal " + this.repr(b)
|
|
: "didn't expect " + this.repr(a) + ", but got it";
|
|
this.addTest(pass, name, passString, failString, diag);
|
|
}
|
|
|
|
todo(condition, name, passString, failString) {
|
|
let diag = this.repr(condition) + " was expected false";
|
|
this.addTest(!condition,
|
|
name,
|
|
typeof(passString) == "undefined" ? this.TEST_KNOWN_FAIL : passString,
|
|
typeof(failString) == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString,
|
|
diag,
|
|
"todo");
|
|
}
|
|
|
|
log(msg, level) {
|
|
dump("MARIONETTE LOG: " + (level ? level : "INFO") + ": " + msg + "\n");
|
|
if (this.logger) {
|
|
this.logger.log(msg, level);
|
|
}
|
|
}
|
|
|
|
// TODO(ato): Suspect this isn't used anywhere
|
|
getLogs() {
|
|
if (this.logger) {
|
|
return this.logger.get();
|
|
}
|
|
}
|
|
|
|
generate_results() {
|
|
let passed = 0;
|
|
let failures = [];
|
|
let expectedFailures = [];
|
|
let unexpectedSuccesses = [];
|
|
for (let i in this.tests) {
|
|
let isTodo = (this.tests[i].state == "todo");
|
|
if(this.tests[i].result) {
|
|
if (isTodo) {
|
|
expectedFailures.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
|
|
}
|
|
else {
|
|
passed++;
|
|
}
|
|
}
|
|
else {
|
|
if (isTodo) {
|
|
unexpectedSuccesses.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
|
|
}
|
|
else {
|
|
failures.push({'name': this.tests[i].name, 'diag': this.tests[i].diag});
|
|
}
|
|
}
|
|
}
|
|
// Reset state in case this object is reused for more tests.
|
|
this.tests = [];
|
|
return {
|
|
passed: passed,
|
|
failures: failures,
|
|
expectedFailures: expectedFailures,
|
|
unexpectedSuccesses: unexpectedSuccesses,
|
|
};
|
|
}
|
|
|
|
logToFile(file) {
|
|
//TODO
|
|
}
|
|
|
|
logResult(test, passString, failString) {
|
|
//TODO: dump to file
|
|
let resultString = test.result ? passString : failString;
|
|
let diagnostic = test.name + (test.diag ? " - " + test.diag : "");
|
|
let msg = resultString + " | " + this.testName + " | " + diagnostic;
|
|
dump("MARIONETTE TEST RESULT:" + msg + "\n");
|
|
}
|
|
|
|
repr(o) {
|
|
if (typeof o == "undefined") {
|
|
return "undefined";
|
|
} else if (o === null) {
|
|
return "null";
|
|
}
|
|
|
|
try {
|
|
if (typeof o.__repr__ == "function") {
|
|
return o.__repr__();
|
|
} else if (typeof o.repr == "function" && o.repr !== arguments.callee) {
|
|
return o.repr();
|
|
}
|
|
} catch (e) {}
|
|
|
|
try {
|
|
if (typeof o.NAME === "string" &&
|
|
(o.toString === Function.prototype.toString || o.toString === Object.prototype.toString)) {
|
|
return o.NAME;
|
|
}
|
|
} catch (e) {}
|
|
|
|
let ostring;
|
|
try {
|
|
ostring = (o + "");
|
|
} catch (e) {
|
|
return "[" + typeof(o) + "]";
|
|
}
|
|
|
|
if (typeof o == "function") {
|
|
o = ostring.replace(/^\s+/, "");
|
|
let idx = o.indexOf("{");
|
|
if (idx != -1) {
|
|
o = o.substr(0, idx) + "{...}";
|
|
}
|
|
}
|
|
return ostring;
|
|
}
|
|
|
|
waitFor(callback, test, timeout) {
|
|
if (test()) {
|
|
callback();
|
|
return;
|
|
}
|
|
|
|
let now = new Date();
|
|
let deadline = (timeout instanceof Date) ? timeout :
|
|
new Date(now.valueOf() + (typeof timeout == "undefined" ? this.timeout : timeout));
|
|
if (deadline <= now) {
|
|
dump("waitFor timeout: " + test.toString() + "\n");
|
|
// the script will timeout here, so no need to raise a separate
|
|
// timeout exception
|
|
return;
|
|
}
|
|
this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, deadline);
|
|
}
|
|
};
|