michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: /* michael@0: * The Marionette object, passed to the script context. michael@0: */ michael@0: michael@0: this.Marionette = function Marionette(scope, window, context, logObj, timeout, michael@0: heartbeatCallback, testName) { michael@0: this.scope = scope; michael@0: this.window = window; michael@0: this.tests = []; michael@0: this.logObj = logObj; michael@0: this.context = context; michael@0: this.timeout = timeout; michael@0: this.heartbeatCallback = heartbeatCallback; michael@0: this.testName = testName; michael@0: this.TEST_UNEXPECTED_FAIL = "TEST-UNEXPECTED-FAIL"; michael@0: this.TEST_PASS = "TEST-PASS"; michael@0: this.TEST_KNOWN_FAIL = "TEST-KNOWN-FAIL"; michael@0: } michael@0: michael@0: Marionette.prototype = { michael@0: exports: ['ok', 'is', 'isnot', 'log', 'getLogs', 'generate_results', 'waitFor', michael@0: 'runEmulatorCmd', 'runEmulatorShell', 'TEST_PASS', 'TEST_KNOWN_FAIL', michael@0: 'TEST_UNEXPECTED_FAIL'], michael@0: michael@0: ok: function Marionette__ok(condition, name, passString, failString, diag) { michael@0: this.heartbeatCallback(); michael@0: if (typeof(diag) == "undefined") { michael@0: diag = this.repr(condition) + " was " + !!condition + ", expected true"; michael@0: } michael@0: let test = {'result': !!condition, 'name': name, 'diag': diag}; michael@0: this.logResult(test, michael@0: typeof(passString) == "undefined" ? this.TEST_PASS : passString, michael@0: typeof(failString) == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString); michael@0: this.tests.push(test); michael@0: }, michael@0: michael@0: is: function Marionette__is(a, b, name, passString, failString) { michael@0: this.heartbeatCallback(); michael@0: let pass = (a == b); michael@0: let diag = pass ? this.repr(a) + " should equal " + this.repr(b) michael@0: : "got " + this.repr(a) + ", expected " + this.repr(b); michael@0: this.ok(pass, name, passString, failString, diag); michael@0: }, michael@0: michael@0: isnot: function Marionette__isnot (a, b, name, passString, failString) { michael@0: this.heartbeatCallback(); michael@0: let pass = (a != b); michael@0: let diag = pass ? this.repr(a) + " should not equal " + this.repr(b) michael@0: : "didn't expect " + this.repr(a) + ", but got it"; michael@0: this.ok(pass, name, passString, failString, diag); michael@0: }, michael@0: michael@0: log: function Marionette__log(msg, level) { michael@0: this.heartbeatCallback(); michael@0: dump("MARIONETTE LOG: " + (level ? level : "INFO") + ": " + msg + "\n"); michael@0: if (this.logObj != null) { michael@0: this.logObj.log(msg, level); michael@0: } michael@0: }, michael@0: michael@0: getLogs: function Marionette__getLogs() { michael@0: this.heartbeatCallback(); michael@0: if (this.logObj != null) { michael@0: this.logObj.getLogs(); michael@0: } michael@0: }, michael@0: michael@0: generate_results: function Marionette__generate_results() { michael@0: this.heartbeatCallback(); michael@0: let passed = 0; michael@0: let failed = 0; michael@0: let failures = []; michael@0: for (let i in this.tests) { michael@0: if(this.tests[i].result) { michael@0: passed++; michael@0: } michael@0: else { michael@0: failed++; michael@0: failures.push({'name': this.tests[i].name, michael@0: 'diag': this.tests[i].diag}); michael@0: } michael@0: } michael@0: // Reset state in case this object is reused for more tests. michael@0: this.tests = []; michael@0: return {"passed": passed, "failed": failed, "failures": failures}; michael@0: }, michael@0: michael@0: logToFile: function Marionette__logToFile(file) { michael@0: this.heartbeatCallback(); michael@0: //TODO michael@0: }, michael@0: michael@0: logResult: function Marionette__logResult(test, passString, failString) { michael@0: this.heartbeatCallback(); michael@0: //TODO: dump to file michael@0: let resultString = test.result ? passString : failString; michael@0: let diagnostic = test.name + (test.diag ? " - " + test.diag : ""); michael@0: let msg = resultString + " | " + this.testName + " | " + diagnostic; michael@0: dump("MARIONETTE TEST RESULT:" + msg + "\n"); michael@0: }, michael@0: michael@0: repr: function Marionette__repr(o) { michael@0: if (typeof(o) == "undefined") { michael@0: return "undefined"; michael@0: } else if (o === null) { michael@0: return "null"; michael@0: } michael@0: try { michael@0: if (typeof(o.__repr__) == 'function') { michael@0: return o.__repr__(); michael@0: } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) { michael@0: return o.repr(); michael@0: } michael@0: } catch (e) { michael@0: } michael@0: try { michael@0: if (typeof(o.NAME) == 'string' && ( michael@0: o.toString == Function.prototype.toString || michael@0: o.toString == Object.prototype.toString michael@0: )) { michael@0: return o.NAME; michael@0: } michael@0: } catch (e) { michael@0: } michael@0: let ostring; michael@0: try { michael@0: ostring = (o + ""); michael@0: } catch (e) { michael@0: return "[" + typeof(o) + "]"; michael@0: } michael@0: if (typeof(o) == "function") { michael@0: o = ostring.replace(/^\s+/, ""); michael@0: let idx = o.indexOf("{"); michael@0: if (idx != -1) { michael@0: o = o.substr(0, idx) + "{...}"; michael@0: } michael@0: } michael@0: return ostring; michael@0: }, michael@0: michael@0: waitFor: function test_waitFor(callback, test, timeout) { michael@0: this.heartbeatCallback(); michael@0: if (test()) { michael@0: callback(); michael@0: return; michael@0: } michael@0: var now = Date.now(); michael@0: var deadline = now + (typeof(timeout) == "undefined" ? this.timeout : timeout); michael@0: if (deadline <= now) { michael@0: dump("waitFor timeout: " + test.toString() + "\n"); michael@0: // the script will timeout here, so no need to raise a separate michael@0: // timeout exception michael@0: return; michael@0: } michael@0: this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, deadline - now); michael@0: }, michael@0: michael@0: runEmulatorCmd: function runEmulatorCmd(cmd, callback) { michael@0: this.heartbeatCallback(); michael@0: this.scope.runEmulatorCmd(cmd, callback); michael@0: }, michael@0: michael@0: runEmulatorShell: function runEmulatorShell(args, callback) { michael@0: this.heartbeatCallback(); michael@0: this.scope.runEmulatorShell(args, callback); michael@0: }, michael@0: michael@0: }; michael@0: