addon-sdk/source/lib/sdk/deprecated/unit-test.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 module.metadata = {
michael@0 8 "stability": "deprecated"
michael@0 9 };
michael@0 10
michael@0 11 const memory = require('./memory');
michael@0 12 var timer = require("../timers");
michael@0 13 var cfxArgs = require("@test/options");
michael@0 14
michael@0 15 exports.findAndRunTests = function findAndRunTests(options) {
michael@0 16 var TestFinder = require("./unit-test-finder").TestFinder;
michael@0 17 var finder = new TestFinder({
michael@0 18 filter: options.filter,
michael@0 19 testInProcess: options.testInProcess,
michael@0 20 testOutOfProcess: options.testOutOfProcess
michael@0 21 });
michael@0 22 var runner = new TestRunner({fs: options.fs});
michael@0 23 finder.findTests(
michael@0 24 function (tests) {
michael@0 25 runner.startMany({tests: tests,
michael@0 26 stopOnError: options.stopOnError,
michael@0 27 onDone: options.onDone});
michael@0 28 });
michael@0 29 };
michael@0 30
michael@0 31 var TestRunner = exports.TestRunner = function TestRunner(options) {
michael@0 32 if (options) {
michael@0 33 this.fs = options.fs;
michael@0 34 }
michael@0 35 this.console = (options && "console" in options) ? options.console : console;
michael@0 36 memory.track(this);
michael@0 37 this.passed = 0;
michael@0 38 this.failed = 0;
michael@0 39 this.testRunSummary = [];
michael@0 40 this.expectFailNesting = 0;
michael@0 41 };
michael@0 42
michael@0 43 TestRunner.prototype = {
michael@0 44 toString: function toString() "[object TestRunner]",
michael@0 45
michael@0 46 DEFAULT_PAUSE_TIMEOUT: 5*60000,
michael@0 47 PAUSE_DELAY: 500,
michael@0 48
michael@0 49 _logTestFailed: function _logTestFailed(why) {
michael@0 50 if (!(why in this.test.errors))
michael@0 51 this.test.errors[why] = 0;
michael@0 52 this.test.errors[why]++;
michael@0 53 },
michael@0 54
michael@0 55 pass: function pass(message) {
michael@0 56 if(!this.expectFailure) {
michael@0 57 if ("testMessage" in this.console)
michael@0 58 this.console.testMessage(true, true, this.test.name, message);
michael@0 59 else
michael@0 60 this.console.info("pass:", message);
michael@0 61 this.passed++;
michael@0 62 this.test.passed++;
michael@0 63 }
michael@0 64 else {
michael@0 65 this.expectFailure = false;
michael@0 66 this._logTestFailed("failure");
michael@0 67 if ("testMessage" in this.console) {
michael@0 68 this.console.testMessage(true, false, this.test.name, message);
michael@0 69 }
michael@0 70 else {
michael@0 71 this.console.error("fail:", 'Failure Expected: ' + message)
michael@0 72 this.console.trace();
michael@0 73 }
michael@0 74 this.failed++;
michael@0 75 this.test.failed++;
michael@0 76 }
michael@0 77 },
michael@0 78
michael@0 79 fail: function fail(message) {
michael@0 80 if(!this.expectFailure) {
michael@0 81 this._logTestFailed("failure");
michael@0 82 if ("testMessage" in this.console) {
michael@0 83 this.console.testMessage(false, false, this.test.name, message);
michael@0 84 }
michael@0 85 else {
michael@0 86 this.console.error("fail:", message)
michael@0 87 this.console.trace();
michael@0 88 }
michael@0 89 this.failed++;
michael@0 90 this.test.failed++;
michael@0 91 }
michael@0 92 else {
michael@0 93 this.expectFailure = false;
michael@0 94 if ("testMessage" in this.console)
michael@0 95 this.console.testMessage(false, true, this.test.name, message);
michael@0 96 else
michael@0 97 this.console.info("pass:", message);
michael@0 98 this.passed++;
michael@0 99 this.test.passed++;
michael@0 100 }
michael@0 101 },
michael@0 102
michael@0 103 expectFail: function(callback) {
michael@0 104 this.expectFailure = true;
michael@0 105 callback();
michael@0 106 this.expectFailure = false;
michael@0 107 },
michael@0 108
michael@0 109 exception: function exception(e) {
michael@0 110 this._logTestFailed("exception");
michael@0 111 if (cfxArgs.parseable)
michael@0 112 this.console.print("TEST-UNEXPECTED-FAIL | " + this.test.name + " | " + e + "\n");
michael@0 113 this.console.exception(e);
michael@0 114 this.failed++;
michael@0 115 this.test.failed++;
michael@0 116 },
michael@0 117
michael@0 118 assertMatches: function assertMatches(string, regexp, message) {
michael@0 119 if (regexp.test(string)) {
michael@0 120 if (!message)
michael@0 121 message = uneval(string) + " matches " + uneval(regexp);
michael@0 122 this.pass(message);
michael@0 123 } else {
michael@0 124 var no = uneval(string) + " doesn't match " + uneval(regexp);
michael@0 125 if (!message)
michael@0 126 message = no;
michael@0 127 else
michael@0 128 message = message + " (" + no + ")";
michael@0 129 this.fail(message);
michael@0 130 }
michael@0 131 },
michael@0 132
michael@0 133 assertRaises: function assertRaises(func, predicate, message) {
michael@0 134 try {
michael@0 135 func();
michael@0 136 if (message)
michael@0 137 this.fail(message + " (no exception thrown)");
michael@0 138 else
michael@0 139 this.fail("function failed to throw exception");
michael@0 140 } catch (e) {
michael@0 141 var errorMessage;
michael@0 142 if (typeof(e) == "string")
michael@0 143 errorMessage = e;
michael@0 144 else
michael@0 145 errorMessage = e.message;
michael@0 146 if (typeof(predicate) == "string")
michael@0 147 this.assertEqual(errorMessage, predicate, message);
michael@0 148 else
michael@0 149 this.assertMatches(errorMessage, predicate, message);
michael@0 150 }
michael@0 151 },
michael@0 152
michael@0 153 assert: function assert(a, message) {
michael@0 154 if (!a) {
michael@0 155 if (!message)
michael@0 156 message = "assertion failed, value is " + a;
michael@0 157 this.fail(message);
michael@0 158 } else
michael@0 159 this.pass(message || "assertion successful");
michael@0 160 },
michael@0 161
michael@0 162 assertNotEqual: function assertNotEqual(a, b, message) {
michael@0 163 if (a != b) {
michael@0 164 if (!message)
michael@0 165 message = "a != b != " + uneval(a);
michael@0 166 this.pass(message);
michael@0 167 } else {
michael@0 168 var equality = uneval(a) + " == " + uneval(b);
michael@0 169 if (!message)
michael@0 170 message = equality;
michael@0 171 else
michael@0 172 message += " (" + equality + ")";
michael@0 173 this.fail(message);
michael@0 174 }
michael@0 175 },
michael@0 176
michael@0 177 assertEqual: function assertEqual(a, b, message) {
michael@0 178 if (a == b) {
michael@0 179 if (!message)
michael@0 180 message = "a == b == " + uneval(a);
michael@0 181 this.pass(message);
michael@0 182 } else {
michael@0 183 var inequality = uneval(a) + " != " + uneval(b);
michael@0 184 if (!message)
michael@0 185 message = inequality;
michael@0 186 else
michael@0 187 message += " (" + inequality + ")";
michael@0 188 this.fail(message);
michael@0 189 }
michael@0 190 },
michael@0 191
michael@0 192 assertNotStrictEqual: function assertNotStrictEqual(a, b, message) {
michael@0 193 if (a !== b) {
michael@0 194 if (!message)
michael@0 195 message = "a !== b !== " + uneval(a);
michael@0 196 this.pass(message);
michael@0 197 } else {
michael@0 198 var equality = uneval(a) + " === " + uneval(b);
michael@0 199 if (!message)
michael@0 200 message = equality;
michael@0 201 else
michael@0 202 message += " (" + equality + ")";
michael@0 203 this.fail(message);
michael@0 204 }
michael@0 205 },
michael@0 206
michael@0 207 assertStrictEqual: function assertStrictEqual(a, b, message) {
michael@0 208 if (a === b) {
michael@0 209 if (!message)
michael@0 210 message = "a === b === " + uneval(a);
michael@0 211 this.pass(message);
michael@0 212 } else {
michael@0 213 var inequality = uneval(a) + " !== " + uneval(b);
michael@0 214 if (!message)
michael@0 215 message = inequality;
michael@0 216 else
michael@0 217 message += " (" + inequality + ")";
michael@0 218 this.fail(message);
michael@0 219 }
michael@0 220 },
michael@0 221
michael@0 222 assertFunction: function assertFunction(a, message) {
michael@0 223 this.assertStrictEqual('function', typeof a, message);
michael@0 224 },
michael@0 225
michael@0 226 assertUndefined: function(a, message) {
michael@0 227 this.assertStrictEqual('undefined', typeof a, message);
michael@0 228 },
michael@0 229
michael@0 230 assertNotUndefined: function(a, message) {
michael@0 231 this.assertNotStrictEqual('undefined', typeof a, message);
michael@0 232 },
michael@0 233
michael@0 234 assertNull: function(a, message) {
michael@0 235 this.assertStrictEqual(null, a, message);
michael@0 236 },
michael@0 237
michael@0 238 assertNotNull: function(a, message) {
michael@0 239 this.assertNotStrictEqual(null, a, message);
michael@0 240 },
michael@0 241
michael@0 242 assertObject: function(a, message) {
michael@0 243 this.assertStrictEqual('[object Object]', Object.prototype.toString.apply(a), message);
michael@0 244 },
michael@0 245
michael@0 246 assertString: function(a, message) {
michael@0 247 this.assertStrictEqual('[object String]', Object.prototype.toString.apply(a), message);
michael@0 248 },
michael@0 249
michael@0 250 assertArray: function(a, message) {
michael@0 251 this.assertStrictEqual('[object Array]', Object.prototype.toString.apply(a), message);
michael@0 252 },
michael@0 253
michael@0 254 assertNumber: function(a, message) {
michael@0 255 this.assertStrictEqual('[object Number]', Object.prototype.toString.apply(a), message);
michael@0 256 },
michael@0 257
michael@0 258 done: function done() {
michael@0 259 if (!this.isDone) {
michael@0 260 this.isDone = true;
michael@0 261 if(this.test.teardown) {
michael@0 262 this.test.teardown(this);
michael@0 263 }
michael@0 264 if (this.waitTimeout !== null) {
michael@0 265 timer.clearTimeout(this.waitTimeout);
michael@0 266 this.waitTimeout = null;
michael@0 267 }
michael@0 268 // Do not leave any callback set when calling to `waitUntil`
michael@0 269 this.waitUntilCallback = null;
michael@0 270 if (this.test.passed == 0 && this.test.failed == 0) {
michael@0 271 this._logTestFailed("empty test");
michael@0 272 if ("testMessage" in this.console) {
michael@0 273 this.console.testMessage(false, false, this.test.name, "Empty test");
michael@0 274 }
michael@0 275 else {
michael@0 276 this.console.error("fail:", "Empty test")
michael@0 277 }
michael@0 278 this.failed++;
michael@0 279 this.test.failed++;
michael@0 280 }
michael@0 281
michael@0 282 this.testRunSummary.push({
michael@0 283 name: this.test.name,
michael@0 284 passed: this.test.passed,
michael@0 285 failed: this.test.failed,
michael@0 286 errors: [error for (error in this.test.errors)].join(", ")
michael@0 287 });
michael@0 288
michael@0 289 if (this.onDone !== null) {
michael@0 290 var onDone = this.onDone;
michael@0 291 var self = this;
michael@0 292 this.onDone = null;
michael@0 293 timer.setTimeout(function() { onDone(self); }, 0);
michael@0 294 }
michael@0 295 }
michael@0 296 },
michael@0 297
michael@0 298 // Set of assertion functions to wait for an assertion to become true
michael@0 299 // These functions take the same arguments as the TestRunner.assert* methods.
michael@0 300 waitUntil: function waitUntil() {
michael@0 301 return this._waitUntil(this.assert, arguments);
michael@0 302 },
michael@0 303
michael@0 304 waitUntilNotEqual: function waitUntilNotEqual() {
michael@0 305 return this._waitUntil(this.assertNotEqual, arguments);
michael@0 306 },
michael@0 307
michael@0 308 waitUntilEqual: function waitUntilEqual() {
michael@0 309 return this._waitUntil(this.assertEqual, arguments);
michael@0 310 },
michael@0 311
michael@0 312 waitUntilMatches: function waitUntilMatches() {
michael@0 313 return this._waitUntil(this.assertMatches, arguments);
michael@0 314 },
michael@0 315
michael@0 316 /**
michael@0 317 * Internal function that waits for an assertion to become true.
michael@0 318 * @param {Function} assertionMethod
michael@0 319 * Reference to a TestRunner assertion method like test.assert,
michael@0 320 * test.assertEqual, ...
michael@0 321 * @param {Array} args
michael@0 322 * List of arguments to give to the previous assertion method.
michael@0 323 * All functions in this list are going to be called to retrieve current
michael@0 324 * assertion values.
michael@0 325 */
michael@0 326 _waitUntil: function waitUntil(assertionMethod, args) {
michael@0 327 let count = 0;
michael@0 328 let maxCount = this.DEFAULT_PAUSE_TIMEOUT / this.PAUSE_DELAY;
michael@0 329
michael@0 330 // We need to ensure that test is asynchronous
michael@0 331 if (!this.waitTimeout)
michael@0 332 this.waitUntilDone(this.DEFAULT_PAUSE_TIMEOUT);
michael@0 333
michael@0 334 let callback = null;
michael@0 335 let finished = false;
michael@0 336
michael@0 337 let test = this;
michael@0 338
michael@0 339 // capture a traceback before we go async.
michael@0 340 let traceback = require("../console/traceback");
michael@0 341 let stack = traceback.get();
michael@0 342 stack.splice(-2, 2);
michael@0 343 let currentWaitStack = traceback.format(stack);
michael@0 344 let timeout = null;
michael@0 345
michael@0 346 function loop(stopIt) {
michael@0 347 timeout = null;
michael@0 348
michael@0 349 // Build a mockup object to fake TestRunner API and intercept calls to
michael@0 350 // pass and fail methods, in order to retrieve nice error messages
michael@0 351 // and assertion result
michael@0 352 let mock = {
michael@0 353 pass: function (msg) {
michael@0 354 test.pass(msg);
michael@0 355 test.waitUntilCallback = null;
michael@0 356 if (callback && !stopIt)
michael@0 357 callback();
michael@0 358 finished = true;
michael@0 359 },
michael@0 360 fail: function (msg) {
michael@0 361 // If we are called on test timeout, we stop the loop
michael@0 362 // and print which test keeps failing:
michael@0 363 if (stopIt) {
michael@0 364 test.console.error("test assertion never became true:\n",
michael@0 365 msg + "\n",
michael@0 366 currentWaitStack);
michael@0 367 if (timeout)
michael@0 368 timer.clearTimeout(timeout);
michael@0 369 return;
michael@0 370 }
michael@0 371 timeout = timer.setTimeout(loop, test.PAUSE_DELAY);
michael@0 372 }
michael@0 373 };
michael@0 374
michael@0 375 // Automatically call args closures in order to build arguments for
michael@0 376 // assertion function
michael@0 377 let appliedArgs = [];
michael@0 378 for (let i = 0, l = args.length; i < l; i++) {
michael@0 379 let a = args[i];
michael@0 380 if (typeof a == "function") {
michael@0 381 try {
michael@0 382 a = a();
michael@0 383 }
michael@0 384 catch(e) {
michael@0 385 test.fail("Exception when calling asynchronous assertion: " + e +
michael@0 386 "\n" + e.stack);
michael@0 387 finished = true;
michael@0 388 return;
michael@0 389 }
michael@0 390 }
michael@0 391 appliedArgs.push(a);
michael@0 392 }
michael@0 393
michael@0 394 // Finally call assertion function with current assertion values
michael@0 395 assertionMethod.apply(mock, appliedArgs);
michael@0 396 }
michael@0 397 loop();
michael@0 398 this.waitUntilCallback = loop;
michael@0 399
michael@0 400 // Return an object with `then` method, to offer a way to execute
michael@0 401 // some code when the assertion passed or failed
michael@0 402 return {
michael@0 403 then: function (c) {
michael@0 404 callback = c;
michael@0 405
michael@0 406 // In case of immediate positive result, we need to execute callback
michael@0 407 // immediately here:
michael@0 408 if (finished)
michael@0 409 callback();
michael@0 410 }
michael@0 411 };
michael@0 412 },
michael@0 413
michael@0 414 waitUntilDone: function waitUntilDone(ms) {
michael@0 415 if (ms === undefined)
michael@0 416 ms = this.DEFAULT_PAUSE_TIMEOUT;
michael@0 417
michael@0 418 var self = this;
michael@0 419
michael@0 420 function tiredOfWaiting() {
michael@0 421 self._logTestFailed("timed out");
michael@0 422 if ("testMessage" in self.console) {
michael@0 423 self.console.testMessage(false, false, self.test.name, "Timed out");
michael@0 424 }
michael@0 425 else {
michael@0 426 self.console.error("fail:", "Timed out")
michael@0 427 }
michael@0 428 if (self.waitUntilCallback) {
michael@0 429 self.waitUntilCallback(true);
michael@0 430 self.waitUntilCallback = null;
michael@0 431 }
michael@0 432 self.failed++;
michael@0 433 self.test.failed++;
michael@0 434 self.done();
michael@0 435 }
michael@0 436
michael@0 437 // We may already have registered a timeout callback
michael@0 438 if (this.waitTimeout)
michael@0 439 timer.clearTimeout(this.waitTimeout);
michael@0 440
michael@0 441 this.waitTimeout = timer.setTimeout(tiredOfWaiting, ms);
michael@0 442 },
michael@0 443
michael@0 444 startMany: function startMany(options) {
michael@0 445 function runNextTest(self) {
michael@0 446 var test = options.tests.shift();
michael@0 447 if (options.stopOnError && self.test && self.test.failed) {
michael@0 448 self.console.error("aborted: test failed and --stop-on-error was specified");
michael@0 449 options.onDone(self);
michael@0 450 } else if (test) {
michael@0 451 self.start({test: test, onDone: runNextTest});
michael@0 452 } else {
michael@0 453 options.onDone(self);
michael@0 454 }
michael@0 455 }
michael@0 456 runNextTest(this);
michael@0 457 },
michael@0 458
michael@0 459 start: function start(options) {
michael@0 460 this.test = options.test;
michael@0 461 this.test.passed = 0;
michael@0 462 this.test.failed = 0;
michael@0 463 this.test.errors = {};
michael@0 464
michael@0 465 this.isDone = false;
michael@0 466 this.onDone = function(self) {
michael@0 467 if (cfxArgs.parseable)
michael@0 468 self.console.print("TEST-END | " + self.test.name + "\n");
michael@0 469 options.onDone(self);
michael@0 470 }
michael@0 471 this.waitTimeout = null;
michael@0 472
michael@0 473 try {
michael@0 474 if (cfxArgs.parseable)
michael@0 475 this.console.print("TEST-START | " + this.test.name + "\n");
michael@0 476 else
michael@0 477 this.console.info("executing '" + this.test.name + "'");
michael@0 478
michael@0 479 if(this.test.setup) {
michael@0 480 this.test.setup(this);
michael@0 481 }
michael@0 482 this.test.testFunction(this);
michael@0 483 } catch (e) {
michael@0 484 this.exception(e);
michael@0 485 }
michael@0 486 if (this.waitTimeout === null)
michael@0 487 this.done();
michael@0 488 }
michael@0 489 };

mercurial