/* 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/. */ // This file expects utils.js to be included in its scope /* import-globals-from ./util.js */ var MOCHITEST = false; function Test(name, test) { this.name = name; this.startTime = null; this.endTime = null; this.result = null; this.row = null; this.run = function() { // Note the start time this.startTime = new Date(); // Run the test try { test.call(this); } catch (e) { console.log(e); console.log(e.stack); this.complete(false); } }; this.memcmp_complete = function(x, y) { var passfail = util.memcmp(x, y); if (!passfail) { console.log("expected: " + util.abv2hex(x)); console.log(" got: " + util.abv2hex(y)); } this.complete(passfail); }; this.complete = function(result) { if (MOCHITEST) { ok(result, this.name); } // Note the end time this.endTime = new Date(); // Set result this.result = result; // Re-draw the row this.draw(); this.next(); }; this.next = function() { if (this.oncomplete) { this.oncomplete(); } }; this.setRow = function(id) { this.row = document.getElementById(id).getElementsByTagName("td"); }; this.draw = function() { if (!this.row) { return; } // Print the name of the test if (this.name) { this.row[0].textContent = this.name; var that = this; this.row[0].onclick = function() { that.run(); }; } else { this.row[0] = ""; } // Print the result of the test if (this.result === true) { this.row[1].className = "pass"; this.row[1].innerHTML = "PASS"; } else if (this.result === false) { this.row[1].className = "fail"; this.row[1].innerHTML = "FAIL"; } else { // this.row[1].innerHTML = ""; this.row[1].textContent = this.result; } // Print the elapsed time, if known if (this.startTime && this.endTime) { this.row[2].textContent = this.endTime - this.startTime + " ms"; } else { this.row[2].innerHTML = ""; } }; } function WorkerTest(worker, name, test) { this.name = `${name} (Worker)`; this.startTime = null; this.endTime = null; this.result = null; this.row = null; this.run = function() { // Note the start time this.startTime = new Date(); // Send the test code to the worker. worker.postMessage(test.toString()); // We expect only boolean responses from the worker script. worker.onmessage = e => this.complete(e.data); worker.onerror = e => this.complete(false); }; var base = new Test(name, test); // Inherit what we need from the |Test| class. We can't simply use its // prototype as Test is just a function that can be used like a constructor. for (var method of ["draw", "setRow", "next", "complete"]) { this[method] = base[method].bind(this); } } var TestArray = { tests: [], table: null, passSpan: null, failSpan: null, pendingSpan: null, pass: 0, fail: 0, pending: 0, currTest: 0, worker: new Worker("test-worker.js"), addTest(name, testFn) { // Give it a reference to the array var test = new Test(name, testFn); test.ta = this; // Add test to tests this.tests.push(test); // Run the test in a worker too. this.tests.push(new WorkerTest(this.worker, name, testFn)); }, updateSummary() { this.pass = this.fail = this.pending = 0; for (var i = 0; i < this.tests.length; ++i) { if (this.tests[i].result === true) { this.pass++; } if (this.tests[i].result === false) { this.fail++; } if (this.tests[i].result == null) { this.pending++; } } this.passSpan.textContent = this.pass; this.failSpan.textContent = this.fail; this.pendingSpan.textContent = this.pending; }, load() { // Grab reference to table and summary numbers this.table = document.getElementById("results"); this.passSpan = document.getElementById("passN"); this.failSpan = document.getElementById("failN"); this.pendingSpan = document.getElementById("pendingN"); // Populate everything initially this.updateSummary(); for (var i = 0; i < this.tests.length; ++i) { var tr = document.createElement("tr"); tr.id = "test" + i; tr.appendChild(document.createElement("td")); tr.appendChild(document.createElement("td")); tr.appendChild(document.createElement("td")); this.table.appendChild(tr); this.tests[i].setRow(tr.id); this.tests[i].draw(); } }, run() { this.currTest = 0; this.runNextTest(); }, runNextTest() { this.updateSummary(); var i = this.currTest++; if (i >= this.tests.length) { if (MOCHITEST) { SimpleTest.finish(); } return; } var self = this; this.tests[i].oncomplete = function() { self.runNextTest(); }; this.tests[i].run(); }, }; if (window.addEventListener) { window.addEventListener("load", function() { TestArray.load(); }); } else { window.attachEvent("onload", function() { TestArray.load(); }); } function start() { TestArray.run(); } MOCHITEST = "SimpleTest" in window; if (MOCHITEST) { SimpleTest.waitForExplicitFinish(); SimpleTest.requestLongerTimeout(2); window.addEventListener("load", function() { SimpleTest.waitForFocus(start); }); } function error(test) { return function(x) { console.log("ERROR :: " + x); test.complete(false); throw x; }; } function complete(test, valid) { return function(x) { console.log("COMPLETE"); console.log(x); if (valid) { test.complete(valid(x)); } else { test.complete(true); } }; } function memcmp_complete(test, value) { return function(x) { console.log("COMPLETE"); console.log(x); test.memcmp_complete(value, x); }; }