addon-sdk/source/lib/sdk/test/harness.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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 "use strict";
michael@0 5
michael@0 6 module.metadata = {
michael@0 7 "stability": "experimental"
michael@0 8 };
michael@0 9
michael@0 10 const { Cc, Ci, Cu } = require("chrome");
michael@0 11 const { Loader } = require('./loader');
michael@0 12 const { serializeStack, parseStack } = require("toolkit/loader");
michael@0 13 const { setTimeout } = require('../timers');
michael@0 14 const { PlainTextConsole } = require("../console/plain-text");
michael@0 15 const { when: unload } = require("../system/unload");
michael@0 16 const { format, fromException } = require("../console/traceback");
michael@0 17 const system = require("../system");
michael@0 18 const memory = require('../deprecated/memory');
michael@0 19 const { gc: gcPromise } = require('./memory');
michael@0 20 const { defer } = require('../core/promise');
michael@0 21
michael@0 22 // Trick manifest builder to make it think we need these modules ?
michael@0 23 const unit = require("../deprecated/unit-test");
michael@0 24 const test = require("../../test");
michael@0 25 const url = require("../url");
michael@0 26
michael@0 27 function emptyPromise() {
michael@0 28 let { promise, resolve } = defer();
michael@0 29 resolve();
michael@0 30 return promise;
michael@0 31 }
michael@0 32
michael@0 33 var cService = Cc['@mozilla.org/consoleservice;1'].getService()
michael@0 34 .QueryInterface(Ci.nsIConsoleService);
michael@0 35
michael@0 36 // The console used to log messages
michael@0 37 var testConsole;
michael@0 38
michael@0 39 // Cuddlefish loader in which we load and execute tests.
michael@0 40 var loader;
michael@0 41
michael@0 42 // Function to call when we're done running tests.
michael@0 43 var onDone;
michael@0 44
michael@0 45 // Function to print text to a console, w/o CR at the end.
michael@0 46 var print;
michael@0 47
michael@0 48 // How many more times to run all tests.
michael@0 49 var iterationsLeft;
michael@0 50
michael@0 51 // Whether to report memory profiling information.
michael@0 52 var profileMemory;
michael@0 53
michael@0 54 // Whether we should stop as soon as a test reports a failure.
michael@0 55 var stopOnError;
michael@0 56
michael@0 57 // Function to call to retrieve a list of tests to execute
michael@0 58 var findAndRunTests;
michael@0 59
michael@0 60 // Combined information from all test runs.
michael@0 61 var results = {
michael@0 62 passed: 0,
michael@0 63 failed: 0,
michael@0 64 testRuns: []
michael@0 65 };
michael@0 66
michael@0 67 // A list of the compartments and windows loaded after startup
michael@0 68 var startLeaks;
michael@0 69
michael@0 70 // JSON serialization of last memory usage stats; we keep it stringified
michael@0 71 // so we don't actually change the memory usage stats (in terms of objects)
michael@0 72 // of the JSRuntime we're profiling.
michael@0 73 var lastMemoryUsage;
michael@0 74
michael@0 75 function analyzeRawProfilingData(data) {
michael@0 76 var graph = data.graph;
michael@0 77 var shapes = {};
michael@0 78
michael@0 79 // Convert keys in the graph from strings to ints.
michael@0 80 // TODO: Can we get rid of this ridiculousness?
michael@0 81 var newGraph = {};
michael@0 82 for (id in graph) {
michael@0 83 newGraph[parseInt(id)] = graph[id];
michael@0 84 }
michael@0 85 graph = newGraph;
michael@0 86
michael@0 87 var modules = 0;
michael@0 88 var moduleIds = [];
michael@0 89 var moduleObjs = {UNKNOWN: 0};
michael@0 90 for (let name in data.namedObjects) {
michael@0 91 moduleObjs[name] = 0;
michael@0 92 moduleIds[data.namedObjects[name]] = name;
michael@0 93 modules++;
michael@0 94 }
michael@0 95
michael@0 96 var count = 0;
michael@0 97 for (id in graph) {
michael@0 98 var parent = graph[id].parent;
michael@0 99 while (parent) {
michael@0 100 if (parent in moduleIds) {
michael@0 101 var name = moduleIds[parent];
michael@0 102 moduleObjs[name]++;
michael@0 103 break;
michael@0 104 }
michael@0 105 if (!(parent in graph)) {
michael@0 106 moduleObjs.UNKNOWN++;
michael@0 107 break;
michael@0 108 }
michael@0 109 parent = graph[parent].parent;
michael@0 110 }
michael@0 111 count++;
michael@0 112 }
michael@0 113
michael@0 114 print("\nobject count is " + count + " in " + modules + " modules" +
michael@0 115 " (" + data.totalObjectCount + " across entire JS runtime)\n");
michael@0 116 if (lastMemoryUsage) {
michael@0 117 var last = JSON.parse(lastMemoryUsage);
michael@0 118 var diff = {
michael@0 119 moduleObjs: dictDiff(last.moduleObjs, moduleObjs),
michael@0 120 totalObjectClasses: dictDiff(last.totalObjectClasses,
michael@0 121 data.totalObjectClasses)
michael@0 122 };
michael@0 123
michael@0 124 for (let name in diff.moduleObjs)
michael@0 125 print(" " + diff.moduleObjs[name] + " in " + name + "\n");
michael@0 126 for (let name in diff.totalObjectClasses)
michael@0 127 print(" " + diff.totalObjectClasses[name] + " instances of " +
michael@0 128 name + "\n");
michael@0 129 }
michael@0 130 lastMemoryUsage = JSON.stringify(
michael@0 131 {moduleObjs: moduleObjs,
michael@0 132 totalObjectClasses: data.totalObjectClasses}
michael@0 133 );
michael@0 134 }
michael@0 135
michael@0 136 function dictDiff(last, curr) {
michael@0 137 var diff = {};
michael@0 138
michael@0 139 for (let name in last) {
michael@0 140 var result = (curr[name] || 0) - last[name];
michael@0 141 if (result)
michael@0 142 diff[name] = (result > 0 ? "+" : "") + result;
michael@0 143 }
michael@0 144 for (let name in curr) {
michael@0 145 var result = curr[name] - (last[name] || 0);
michael@0 146 if (result)
michael@0 147 diff[name] = (result > 0 ? "+" : "") + result;
michael@0 148 }
michael@0 149 return diff;
michael@0 150 }
michael@0 151
michael@0 152 function reportMemoryUsage() {
michael@0 153 if (!profileMemory) {
michael@0 154 return emptyPromise();
michael@0 155 }
michael@0 156
michael@0 157 return gcPromise().then((function () {
michael@0 158 var mgr = Cc["@mozilla.org/memory-reporter-manager;1"]
michael@0 159 .getService(Ci.nsIMemoryReporterManager);
michael@0 160 let count = 0;
michael@0 161 function logReporter(process, path, kind, units, amount, description) {
michael@0 162 print(((++count == 1) ? "\n" : "") + description + ": " + amount + "\n");
michael@0 163 }
michael@0 164 mgr.getReportsForThisProcess(logReporter, null);
michael@0 165
michael@0 166 var weakrefs = [info.weakref.get()
michael@0 167 for each (info in memory.getObjects())];
michael@0 168 weakrefs = [weakref for each (weakref in weakrefs) if (weakref)];
michael@0 169 print("Tracked memory objects in testing sandbox: " + weakrefs.length + "\n");
michael@0 170 }));
michael@0 171 }
michael@0 172
michael@0 173 var gWeakrefInfo;
michael@0 174
michael@0 175 function checkMemory() {
michael@0 176 return gcPromise().then(_ => {
michael@0 177 let leaks = getPotentialLeaks();
michael@0 178
michael@0 179 let compartmentURLs = Object.keys(leaks.compartments).filter(function(url) {
michael@0 180 return !(url in startLeaks.compartments);
michael@0 181 });
michael@0 182
michael@0 183 let windowURLs = Object.keys(leaks.windows).filter(function(url) {
michael@0 184 return !(url in startLeaks.windows);
michael@0 185 });
michael@0 186
michael@0 187 for (let url of compartmentURLs)
michael@0 188 console.warn("LEAKED", leaks.compartments[url]);
michael@0 189
michael@0 190 for (let url of windowURLs)
michael@0 191 console.warn("LEAKED", leaks.windows[url]);
michael@0 192 }).then(showResults);
michael@0 193 }
michael@0 194
michael@0 195 function showResults() {
michael@0 196 let { promise, resolve } = defer();
michael@0 197
michael@0 198 if (gWeakrefInfo) {
michael@0 199 gWeakrefInfo.forEach(
michael@0 200 function(info) {
michael@0 201 var ref = info.weakref.get();
michael@0 202 if (ref !== null) {
michael@0 203 var data = ref.__url__ ? ref.__url__ : ref;
michael@0 204 var warning = data == "[object Object]"
michael@0 205 ? "[object " + data.constructor.name + "(" +
michael@0 206 [p for (p in data)].join(", ") + ")]"
michael@0 207 : data;
michael@0 208 console.warn("LEAK", warning, info.bin);
michael@0 209 }
michael@0 210 }
michael@0 211 );
michael@0 212 }
michael@0 213
michael@0 214 onDone(results);
michael@0 215
michael@0 216 resolve();
michael@0 217 return promise;
michael@0 218 }
michael@0 219
michael@0 220 function cleanup() {
michael@0 221 let coverObject = {};
michael@0 222 try {
michael@0 223 for (let name in loader.modules)
michael@0 224 memory.track(loader.modules[name],
michael@0 225 "module global scope: " + name);
michael@0 226 memory.track(loader, "Cuddlefish Loader");
michael@0 227
michael@0 228 if (profileMemory) {
michael@0 229 gWeakrefInfo = [{ weakref: info.weakref, bin: info.bin }
michael@0 230 for each (info in memory.getObjects())];
michael@0 231 }
michael@0 232
michael@0 233 loader.unload();
michael@0 234
michael@0 235 if (loader.globals.console.errorsLogged && !results.failed) {
michael@0 236 results.failed++;
michael@0 237 console.error("warnings and/or errors were logged.");
michael@0 238 }
michael@0 239
michael@0 240 if (consoleListener.errorsLogged && !results.failed) {
michael@0 241 console.warn(consoleListener.errorsLogged + " " +
michael@0 242 "warnings or errors were logged to the " +
michael@0 243 "platform's nsIConsoleService, which could " +
michael@0 244 "be of no consequence; however, they could also " +
michael@0 245 "be indicative of aberrant behavior.");
michael@0 246 }
michael@0 247
michael@0 248 // read the code coverage object, if it exists, from CoverJS-moz
michael@0 249 if (typeof loader.globals.global == "object") {
michael@0 250 coverObject = loader.globals.global['__$coverObject'] || {};
michael@0 251 }
michael@0 252
michael@0 253 consoleListener.errorsLogged = 0;
michael@0 254 loader = null;
michael@0 255
michael@0 256 memory.gc();
michael@0 257 }
michael@0 258 catch (e) {
michael@0 259 results.failed++;
michael@0 260 console.error("unload.send() threw an exception.");
michael@0 261 console.exception(e);
michael@0 262 };
michael@0 263
michael@0 264 setTimeout(require('@test/options').checkMemory ? checkMemory : showResults, 1);
michael@0 265
michael@0 266 // dump the coverobject
michael@0 267 if (Object.keys(coverObject).length){
michael@0 268 const self = require('sdk/self');
michael@0 269 const {pathFor} = require("sdk/system");
michael@0 270 let file = require('sdk/io/file');
michael@0 271 const {env} = require('sdk/system/environment');
michael@0 272 console.log("CWD:", env.PWD);
michael@0 273 let out = file.join(env.PWD,'coverstats-'+self.id+'.json');
michael@0 274 console.log('coverstats:', out);
michael@0 275 let outfh = file.open(out,'w');
michael@0 276 outfh.write(JSON.stringify(coverObject,null,2));
michael@0 277 outfh.flush();
michael@0 278 outfh.close();
michael@0 279 }
michael@0 280 }
michael@0 281
michael@0 282 function getPotentialLeaks() {
michael@0 283 memory.gc();
michael@0 284
michael@0 285 // Things we can assume are part of the platform and so aren't leaks
michael@0 286 let WHITELIST_BASE_URLS = [
michael@0 287 "chrome://",
michael@0 288 "resource:///",
michael@0 289 "resource://app/",
michael@0 290 "resource://gre/",
michael@0 291 "resource://gre-resources/",
michael@0 292 "resource://pdf.js/",
michael@0 293 "resource://pdf.js.components/",
michael@0 294 "resource://services-common/",
michael@0 295 "resource://services-crypto/",
michael@0 296 "resource://services-sync/"
michael@0 297 ];
michael@0 298
michael@0 299 let ioService = Cc["@mozilla.org/network/io-service;1"].
michael@0 300 getService(Ci.nsIIOService);
michael@0 301 let uri = ioService.newURI("chrome://global/content/", "UTF-8", null);
michael@0 302 let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
michael@0 303 getService(Ci.nsIChromeRegistry);
michael@0 304 uri = chromeReg.convertChromeURL(uri);
michael@0 305 let spec = uri.spec;
michael@0 306 let pos = spec.indexOf("!/");
michael@0 307 WHITELIST_BASE_URLS.push(spec.substring(0, pos + 2));
michael@0 308
michael@0 309 let zoneRegExp = new RegExp("^explicit/js-non-window/zones/zone[^/]+/compartment\\((.+)\\)");
michael@0 310 let compartmentRegexp = new RegExp("^explicit/js-non-window/compartments/non-window-global/compartment\\((.+)\\)/");
michael@0 311 let compartmentDetails = new RegExp("^([^,]+)(?:, (.+?))?(?: \\(from: (.*)\\))?$");
michael@0 312 let windowRegexp = new RegExp("^explicit/window-objects/top\\((.*)\\)/active");
michael@0 313 let windowDetails = new RegExp("^(.*), id=.*$");
michael@0 314
michael@0 315 function isPossibleLeak(item) {
michael@0 316 if (!item.location)
michael@0 317 return false;
michael@0 318
michael@0 319 for (let whitelist of WHITELIST_BASE_URLS) {
michael@0 320 if (item.location.substring(0, whitelist.length) == whitelist)
michael@0 321 return false;
michael@0 322 }
michael@0 323
michael@0 324 return true;
michael@0 325 }
michael@0 326
michael@0 327 let compartments = {};
michael@0 328 let windows = {};
michael@0 329 function logReporter(process, path, kind, units, amount, description) {
michael@0 330 let matches;
michael@0 331
michael@0 332 if ((matches = compartmentRegexp.exec(path)) || (matches = zoneRegExp.exec(path))) {
michael@0 333 if (matches[1] in compartments)
michael@0 334 return;
michael@0 335
michael@0 336 let details = compartmentDetails.exec(matches[1]);
michael@0 337 if (!details) {
michael@0 338 console.error("Unable to parse compartment detail " + matches[1]);
michael@0 339 return;
michael@0 340 }
michael@0 341
michael@0 342 let item = {
michael@0 343 path: matches[1],
michael@0 344 principal: details[1],
michael@0 345 location: details[2] ? details[2].replace("\\", "/", "g") : undefined,
michael@0 346 source: details[3] ? details[3].split(" -> ").reverse() : undefined,
michael@0 347 toString: function() this.location
michael@0 348 };
michael@0 349
michael@0 350 if (!isPossibleLeak(item))
michael@0 351 return;
michael@0 352
michael@0 353 compartments[matches[1]] = item;
michael@0 354 return;
michael@0 355 }
michael@0 356
michael@0 357 if (matches = windowRegexp.exec(path)) {
michael@0 358 if (matches[1] in windows)
michael@0 359 return;
michael@0 360
michael@0 361 let details = windowDetails.exec(matches[1]);
michael@0 362 if (!details) {
michael@0 363 console.error("Unable to parse window detail " + matches[1]);
michael@0 364 return;
michael@0 365 }
michael@0 366
michael@0 367 let item = {
michael@0 368 path: matches[1],
michael@0 369 location: details[1].replace("\\", "/", "g"),
michael@0 370 source: [details[1].replace("\\", "/", "g")],
michael@0 371 toString: function() this.location
michael@0 372 };
michael@0 373
michael@0 374 if (!isPossibleLeak(item))
michael@0 375 return;
michael@0 376
michael@0 377 windows[matches[1]] = item;
michael@0 378 }
michael@0 379 }
michael@0 380
michael@0 381 Cc["@mozilla.org/memory-reporter-manager;1"]
michael@0 382 .getService(Ci.nsIMemoryReporterManager)
michael@0 383 .getReportsForThisProcess(logReporter, null);
michael@0 384
michael@0 385 return { compartments: compartments, windows: windows };
michael@0 386 }
michael@0 387
michael@0 388 function nextIteration(tests) {
michael@0 389 if (tests) {
michael@0 390 results.passed += tests.passed;
michael@0 391 results.failed += tests.failed;
michael@0 392
michael@0 393 reportMemoryUsage().then(_ => {
michael@0 394 let testRun = [];
michael@0 395 for each (let test in tests.testRunSummary) {
michael@0 396 let testCopy = {};
michael@0 397 for (let info in test) {
michael@0 398 testCopy[info] = test[info];
michael@0 399 }
michael@0 400 testRun.push(testCopy);
michael@0 401 }
michael@0 402
michael@0 403 results.testRuns.push(testRun);
michael@0 404 iterationsLeft--;
michael@0 405
michael@0 406 checkForEnd();
michael@0 407 })
michael@0 408 }
michael@0 409 else {
michael@0 410 checkForEnd();
michael@0 411 }
michael@0 412 }
michael@0 413
michael@0 414 function checkForEnd() {
michael@0 415 if (iterationsLeft && (!stopOnError || results.failed == 0)) {
michael@0 416 // Pass the loader which has a hooked console that doesn't dispatch
michael@0 417 // errors to the JS console and avoid firing false alarm in our
michael@0 418 // console listener
michael@0 419 findAndRunTests(loader, nextIteration);
michael@0 420 }
michael@0 421 else {
michael@0 422 setTimeout(cleanup, 0);
michael@0 423 }
michael@0 424 }
michael@0 425
michael@0 426 var POINTLESS_ERRORS = [
michael@0 427 'Invalid chrome URI:',
michael@0 428 'OpenGL LayerManager Initialized Succesfully.',
michael@0 429 '[JavaScript Error: "TelemetryStopwatch:',
michael@0 430 'reference to undefined property',
michael@0 431 '[JavaScript Error: "The character encoding of the HTML document was ' +
michael@0 432 'not declared.',
michael@0 433 '[Javascript Warning: "Error: Failed to preserve wrapper of wrapped ' +
michael@0 434 'native weak map key',
michael@0 435 '[JavaScript Warning: "Duplicate resource declaration for',
michael@0 436 'file: "chrome://browser/content/',
michael@0 437 'file: "chrome://global/content/',
michael@0 438 '[JavaScript Warning: "The character encoding of a framed document was ' +
michael@0 439 'not declared.'
michael@0 440 ];
michael@0 441
michael@0 442 var consoleListener = {
michael@0 443 errorsLogged: 0,
michael@0 444 observe: function(object) {
michael@0 445 if (!(object instanceof Ci.nsIScriptError))
michael@0 446 return;
michael@0 447 this.errorsLogged++;
michael@0 448 var message = object.QueryInterface(Ci.nsIConsoleMessage).message;
michael@0 449 var pointless = [err for each (err in POINTLESS_ERRORS)
michael@0 450 if (message.indexOf(err) >= 0)];
michael@0 451 if (pointless.length == 0 && message)
michael@0 452 testConsole.log(message);
michael@0 453 }
michael@0 454 };
michael@0 455
michael@0 456 function TestRunnerConsole(base, options) {
michael@0 457 this.__proto__ = {
michael@0 458 errorsLogged: 0,
michael@0 459 warn: function warn() {
michael@0 460 this.errorsLogged++;
michael@0 461 base.warn.apply(base, arguments);
michael@0 462 },
michael@0 463 error: function error() {
michael@0 464 this.errorsLogged++;
michael@0 465 base.error.apply(base, arguments);
michael@0 466 },
michael@0 467 info: function info(first) {
michael@0 468 if (options.verbose)
michael@0 469 base.info.apply(base, arguments);
michael@0 470 else
michael@0 471 if (first == "pass:")
michael@0 472 print(".");
michael@0 473 },
michael@0 474 __proto__: base
michael@0 475 };
michael@0 476 }
michael@0 477
michael@0 478 function stringify(arg) {
michael@0 479 try {
michael@0 480 return String(arg);
michael@0 481 }
michael@0 482 catch(ex) {
michael@0 483 return "<toString() error>";
michael@0 484 }
michael@0 485 }
michael@0 486
michael@0 487 function stringifyArgs(args) {
michael@0 488 return Array.map(args, stringify).join(" ");
michael@0 489 }
michael@0 490
michael@0 491 function TestRunnerTinderboxConsole(base, options) {
michael@0 492 this.base = base;
michael@0 493 this.print = options.print;
michael@0 494 this.verbose = options.verbose;
michael@0 495 this.errorsLogged = 0;
michael@0 496
michael@0 497 // Binding all the public methods to an instance so that they can be used
michael@0 498 // as callback / listener functions straightaway.
michael@0 499 this.log = this.log.bind(this);
michael@0 500 this.info = this.info.bind(this);
michael@0 501 this.warn = this.warn.bind(this);
michael@0 502 this.error = this.error.bind(this);
michael@0 503 this.debug = this.debug.bind(this);
michael@0 504 this.exception = this.exception.bind(this);
michael@0 505 this.trace = this.trace.bind(this);
michael@0 506 };
michael@0 507
michael@0 508 TestRunnerTinderboxConsole.prototype = {
michael@0 509 testMessage: function testMessage(pass, expected, test, message) {
michael@0 510 let type = "TEST-";
michael@0 511 if (expected) {
michael@0 512 if (pass)
michael@0 513 type += "PASS";
michael@0 514 else
michael@0 515 type += "KNOWN-FAIL";
michael@0 516 }
michael@0 517 else {
michael@0 518 this.errorsLogged++;
michael@0 519 if (pass)
michael@0 520 type += "UNEXPECTED-PASS";
michael@0 521 else
michael@0 522 type += "UNEXPECTED-FAIL";
michael@0 523 }
michael@0 524
michael@0 525 this.print(type + " | " + test + " | " + message + "\n");
michael@0 526 if (!expected)
michael@0 527 this.trace();
michael@0 528 },
michael@0 529
michael@0 530 log: function log() {
michael@0 531 this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n");
michael@0 532 },
michael@0 533
michael@0 534 info: function info(first) {
michael@0 535 this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n");
michael@0 536 },
michael@0 537
michael@0 538 warn: function warn() {
michael@0 539 this.errorsLogged++;
michael@0 540 this.print("TEST-UNEXPECTED-FAIL | " + stringifyArgs(arguments) + "\n");
michael@0 541 },
michael@0 542
michael@0 543 error: function error() {
michael@0 544 this.errorsLogged++;
michael@0 545 this.print("TEST-UNEXPECTED-FAIL | " + stringifyArgs(arguments) + "\n");
michael@0 546 this.base.error.apply(this.base, arguments);
michael@0 547 },
michael@0 548
michael@0 549 debug: function debug() {
michael@0 550 this.print("TEST-INFO | " + stringifyArgs(arguments) + "\n");
michael@0 551 },
michael@0 552
michael@0 553 exception: function exception(e) {
michael@0 554 this.print("An exception occurred.\n" +
michael@0 555 require("../console/traceback").format(e) + "\n" + e + "\n");
michael@0 556 },
michael@0 557
michael@0 558 trace: function trace() {
michael@0 559 var traceback = require("../console/traceback");
michael@0 560 var stack = traceback.get();
michael@0 561 stack.splice(-1, 1);
michael@0 562 this.print("TEST-INFO | " + stringify(traceback.format(stack)) + "\n");
michael@0 563 }
michael@0 564 };
michael@0 565
michael@0 566 var runTests = exports.runTests = function runTests(options) {
michael@0 567 iterationsLeft = options.iterations;
michael@0 568 profileMemory = options.profileMemory;
michael@0 569 stopOnError = options.stopOnError;
michael@0 570 onDone = options.onDone;
michael@0 571 print = options.print;
michael@0 572 findAndRunTests = options.findAndRunTests;
michael@0 573
michael@0 574 try {
michael@0 575 cService.registerListener(consoleListener);
michael@0 576 print("Running tests on " + system.name + " " + system.version +
michael@0 577 "/Gecko " + system.platformVersion + " (" +
michael@0 578 system.id + ") under " +
michael@0 579 system.platform + "/" + system.architecture + ".\n");
michael@0 580
michael@0 581 if (options.parseable)
michael@0 582 testConsole = new TestRunnerTinderboxConsole(new PlainTextConsole(), options);
michael@0 583 else
michael@0 584 testConsole = new TestRunnerConsole(new PlainTextConsole(), options);
michael@0 585
michael@0 586 loader = Loader(module, {
michael@0 587 console: testConsole,
michael@0 588 global: {} // useful for storing things like coverage testing.
michael@0 589 });
michael@0 590
michael@0 591 // Load these before getting initial leak stats as they will still be in
michael@0 592 // memory when we check later
michael@0 593 require("../deprecated/unit-test");
michael@0 594 require("../deprecated/unit-test-finder");
michael@0 595 startLeaks = getPotentialLeaks();
michael@0 596
michael@0 597 nextIteration();
michael@0 598 } catch (e) {
michael@0 599 let frames = fromException(e).reverse().reduce(function(frames, frame) {
michael@0 600 if (frame.fileName.split("/").pop() === "unit-test-finder.js")
michael@0 601 frames.done = true
michael@0 602 if (!frames.done) frames.push(frame)
michael@0 603
michael@0 604 return frames
michael@0 605 }, [])
michael@0 606
michael@0 607 let prototype = typeof(e) === "object" ? e.constructor.prototype :
michael@0 608 Error.prototype;
michael@0 609 let stack = serializeStack(frames.reverse());
michael@0 610
michael@0 611 let error = Object.create(prototype, {
michael@0 612 message: { value: e.message, writable: true, configurable: true },
michael@0 613 fileName: { value: e.fileName, writable: true, configurable: true },
michael@0 614 lineNumber: { value: e.lineNumber, writable: true, configurable: true },
michael@0 615 stack: { value: stack, writable: true, configurable: true },
michael@0 616 toString: { value: function() String(e), writable: true, configurable: true },
michael@0 617 });
michael@0 618
michael@0 619 print("Error: " + error + " \n " + format(error));
michael@0 620 onDone({passed: 0, failed: 1});
michael@0 621 }
michael@0 622 };
michael@0 623
michael@0 624 unload(function() {
michael@0 625 cService.unregisterListener(consoleListener);
michael@0 626 });
michael@0 627

mercurial