summaryrefslogtreecommitdiffstats
path: root/testing/marionette/simpletest.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/marionette/simpletest.js')
-rw-r--r--testing/marionette/simpletest.js208
1 files changed, 208 insertions, 0 deletions
diff --git a/testing/marionette/simpletest.js b/testing/marionette/simpletest.js
new file mode 100644
index 000000000..b179d2a8c
--- /dev/null
+++ b/testing/marionette/simpletest.js
@@ -0,0 +1,208 @@
+/* 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);
+ }
+};