services/sync/tps/extensions/mozmill/resource/modules/assertions.js

Wed, 31 Dec 2014 07:53:36 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:53:36 +0100
branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
permissions
-rw-r--r--

Correct small whitespace inconsistency, lost while renaming variables.

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 var EXPORTED_SYMBOLS = ['Assert', 'Expect'];
michael@0 6
michael@0 7 const Cu = Components.utils;
michael@0 8
michael@0 9 Cu.import("resource://gre/modules/Services.jsm");
michael@0 10
michael@0 11 var broker = {}; Cu.import('resource://mozmill/driver/msgbroker.js', broker);
michael@0 12 var errors = {}; Cu.import('resource://mozmill/modules/errors.js', errors);
michael@0 13 var stack = {}; Cu.import('resource://mozmill/modules/stack.js', stack);
michael@0 14
michael@0 15 /**
michael@0 16 * @name assertions
michael@0 17 * @namespace Defines expect and assert methods to be used for assertions.
michael@0 18 */
michael@0 19
michael@0 20 /**
michael@0 21 * The Assert class implements fatal assertions, and can be used in cases
michael@0 22 * when a failing test has to directly abort the current test function. All
michael@0 23 * remaining tasks will not be performed.
michael@0 24 *
michael@0 25 */
michael@0 26 var Assert = function () {}
michael@0 27
michael@0 28 Assert.prototype = {
michael@0 29
michael@0 30 // The following deepEquals implementation is from Narwhal under this license:
michael@0 31
michael@0 32 // http://wiki.commonjs.org/wiki/Unit_Testing/1.0
michael@0 33 //
michael@0 34 // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
michael@0 35 //
michael@0 36 // Originally from narwhal.js (http://narwhaljs.org)
michael@0 37 // Copyright (c) 2009 Thomas Robinson <280north.com>
michael@0 38 //
michael@0 39 // Permission is hereby granted, free of charge, to any person obtaining a copy
michael@0 40 // of this software and associated documentation files (the 'Software'), to
michael@0 41 // deal in the Software without restriction, including without limitation the
michael@0 42 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
michael@0 43 // sell copies of the Software, and to permit persons to whom the Software is
michael@0 44 // furnished to do so, subject to the following conditions:
michael@0 45 //
michael@0 46 // The above copyright notice and this permission notice shall be included in
michael@0 47 // all copies or substantial portions of the Software.
michael@0 48 //
michael@0 49 // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
michael@0 50 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
michael@0 51 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
michael@0 52 // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
michael@0 53 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
michael@0 54 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
michael@0 55
michael@0 56 _deepEqual: function (actual, expected) {
michael@0 57 // 7.1. All identical values are equivalent, as determined by ===.
michael@0 58 if (actual === expected) {
michael@0 59 return true;
michael@0 60
michael@0 61 // 7.2. If the expected value is a Date object, the actual value is
michael@0 62 // equivalent if it is also a Date object that refers to the same time.
michael@0 63 } else if (actual instanceof Date && expected instanceof Date) {
michael@0 64 return actual.getTime() === expected.getTime();
michael@0 65
michael@0 66 // 7.3. Other pairs that do not both pass typeof value == 'object',
michael@0 67 // equivalence is determined by ==.
michael@0 68 } else if (typeof actual != 'object' && typeof expected != 'object') {
michael@0 69 return actual == expected;
michael@0 70
michael@0 71 // 7.4. For all other Object pairs, including Array objects, equivalence is
michael@0 72 // determined by having the same number of owned properties (as verified
michael@0 73 // with Object.prototype.hasOwnProperty.call), the same set of keys
michael@0 74 // (although not necessarily the same order), equivalent values for every
michael@0 75 // corresponding key, and an identical 'prototype' property. Note: this
michael@0 76 // accounts for both named and indexed properties on Arrays.
michael@0 77 } else {
michael@0 78 return this._objEquiv(actual, expected);
michael@0 79 }
michael@0 80 },
michael@0 81
michael@0 82 _objEquiv: function (a, b) {
michael@0 83 if (a == null || a == undefined || b == null || b == undefined)
michael@0 84 return false;
michael@0 85 // an identical 'prototype' property.
michael@0 86 if (a.prototype !== b.prototype) return false;
michael@0 87
michael@0 88 function isArguments(object) {
michael@0 89 return Object.prototype.toString.call(object) == '[object Arguments]';
michael@0 90 }
michael@0 91
michael@0 92 //~~~I've managed to break Object.keys through screwy arguments passing.
michael@0 93 // Converting to array solves the problem.
michael@0 94 if (isArguments(a)) {
michael@0 95 if (!isArguments(b)) {
michael@0 96 return false;
michael@0 97 }
michael@0 98 a = pSlice.call(a);
michael@0 99 b = pSlice.call(b);
michael@0 100 return _deepEqual(a, b);
michael@0 101 }
michael@0 102 try {
michael@0 103 var ka = Object.keys(a),
michael@0 104 kb = Object.keys(b),
michael@0 105 key, i;
michael@0 106 } catch (e) {//happens when one is a string literal and the other isn't
michael@0 107 return false;
michael@0 108 }
michael@0 109 // having the same number of owned properties (keys incorporates
michael@0 110 // hasOwnProperty)
michael@0 111 if (ka.length != kb.length)
michael@0 112 return false;
michael@0 113 //the same set of keys (although not necessarily the same order),
michael@0 114 ka.sort();
michael@0 115 kb.sort();
michael@0 116 //~~~cheap key test
michael@0 117 for (i = ka.length - 1; i >= 0; i--) {
michael@0 118 if (ka[i] != kb[i])
michael@0 119 return false;
michael@0 120 }
michael@0 121 //equivalent values for every corresponding key, and
michael@0 122 //~~~possibly expensive deep test
michael@0 123 for (i = ka.length - 1; i >= 0; i--) {
michael@0 124 key = ka[i];
michael@0 125 if (!this._deepEqual(a[key], b[key])) return false;
michael@0 126 }
michael@0 127 return true;
michael@0 128 },
michael@0 129
michael@0 130 _expectedException : function Assert__expectedException(actual, expected) {
michael@0 131 if (!actual || !expected) {
michael@0 132 return false;
michael@0 133 }
michael@0 134
michael@0 135 if (expected instanceof RegExp) {
michael@0 136 return expected.test(actual);
michael@0 137 } else if (actual instanceof expected) {
michael@0 138 return true;
michael@0 139 } else if (expected.call({}, actual) === true) {
michael@0 140 return true;
michael@0 141 } else if (actual.name === expected.name) {
michael@0 142 return true;
michael@0 143 }
michael@0 144
michael@0 145 return false;
michael@0 146 },
michael@0 147
michael@0 148 /**
michael@0 149 * Log a test as failing by throwing an AssertionException.
michael@0 150 *
michael@0 151 * @param {object} aResult
michael@0 152 * Test result details used for reporting.
michael@0 153 * <dl>
michael@0 154 * <dd>fileName</dd>
michael@0 155 * <dt>Name of the file in which the assertion failed.</dt>
michael@0 156 * <dd>functionName</dd>
michael@0 157 * <dt>Function in which the assertion failed.</dt>
michael@0 158 * <dd>lineNumber</dd>
michael@0 159 * <dt>Line number of the file in which the assertion failed.</dt>
michael@0 160 * <dd>message</dd>
michael@0 161 * <dt>Message why the assertion failed.</dt>
michael@0 162 * </dl>
michael@0 163 * @throws {errors.AssertionError}
michael@0 164 *
michael@0 165 */
michael@0 166 _logFail: function Assert__logFail(aResult) {
michael@0 167 throw new errors.AssertionError(aResult.message,
michael@0 168 aResult.fileName,
michael@0 169 aResult.lineNumber,
michael@0 170 aResult.functionName,
michael@0 171 aResult.name);
michael@0 172 },
michael@0 173
michael@0 174 /**
michael@0 175 * Log a test as passing by adding a pass frame.
michael@0 176 *
michael@0 177 * @param {object} aResult
michael@0 178 * Test result details used for reporting.
michael@0 179 * <dl>
michael@0 180 * <dd>fileName</dd>
michael@0 181 * <dt>Name of the file in which the assertion failed.</dt>
michael@0 182 * <dd>functionName</dd>
michael@0 183 * <dt>Function in which the assertion failed.</dt>
michael@0 184 * <dd>lineNumber</dd>
michael@0 185 * <dt>Line number of the file in which the assertion failed.</dt>
michael@0 186 * <dd>message</dd>
michael@0 187 * <dt>Message why the assertion failed.</dt>
michael@0 188 * </dl>
michael@0 189 */
michael@0 190 _logPass: function Assert__logPass(aResult) {
michael@0 191 broker.pass({pass: aResult});
michael@0 192 },
michael@0 193
michael@0 194 /**
michael@0 195 * Test the condition and mark test as passed or failed
michael@0 196 *
michael@0 197 * @param {boolean} aCondition
michael@0 198 * Condition to test.
michael@0 199 * @param {string} aMessage
michael@0 200 * Message to show for the test result
michael@0 201 * @param {string} aDiagnosis
michael@0 202 * Diagnose message to show for the test result
michael@0 203 * @throws {errors.AssertionError}
michael@0 204 *
michael@0 205 * @returns {boolean} Result of the test.
michael@0 206 */
michael@0 207 _test: function Assert__test(aCondition, aMessage, aDiagnosis) {
michael@0 208 let diagnosis = aDiagnosis || "";
michael@0 209 let message = aMessage || "";
michael@0 210
michael@0 211 if (diagnosis)
michael@0 212 message = aMessage ? message + " - " + diagnosis : diagnosis;
michael@0 213
michael@0 214 // Build result data
michael@0 215 let frame = stack.findCallerFrame(Components.stack);
michael@0 216
michael@0 217 let result = {
michael@0 218 'fileName' : frame.filename.replace(/(.*)-> /, ""),
michael@0 219 'functionName' : frame.name,
michael@0 220 'lineNumber' : frame.lineNumber,
michael@0 221 'message' : message
michael@0 222 };
michael@0 223
michael@0 224 // Log test result
michael@0 225 if (aCondition) {
michael@0 226 this._logPass(result);
michael@0 227 }
michael@0 228 else {
michael@0 229 result.stack = Components.stack;
michael@0 230 this._logFail(result);
michael@0 231 }
michael@0 232
michael@0 233 return aCondition;
michael@0 234 },
michael@0 235
michael@0 236 /**
michael@0 237 * Perform an always passing test
michael@0 238 *
michael@0 239 * @param {string} aMessage
michael@0 240 * Message to show for the test result.
michael@0 241 * @returns {boolean} Always returns true.
michael@0 242 */
michael@0 243 pass: function Assert_pass(aMessage) {
michael@0 244 return this._test(true, aMessage, undefined);
michael@0 245 },
michael@0 246
michael@0 247 /**
michael@0 248 * Perform an always failing test
michael@0 249 *
michael@0 250 * @param {string} aMessage
michael@0 251 * Message to show for the test result.
michael@0 252 * @throws {errors.AssertionError}
michael@0 253 *
michael@0 254 * @returns {boolean} Always returns false.
michael@0 255 */
michael@0 256 fail: function Assert_fail(aMessage) {
michael@0 257 return this._test(false, aMessage, undefined);
michael@0 258 },
michael@0 259
michael@0 260 /**
michael@0 261 * Test if the value pass
michael@0 262 *
michael@0 263 * @param {boolean|string|number|object} aValue
michael@0 264 * Value to test.
michael@0 265 * @param {string} aMessage
michael@0 266 * Message to show for the test result.
michael@0 267 * @throws {errors.AssertionError}
michael@0 268 *
michael@0 269 * @returns {boolean} Result of the test.
michael@0 270 */
michael@0 271 ok: function Assert_ok(aValue, aMessage) {
michael@0 272 let condition = !!aValue;
michael@0 273 let diagnosis = "got '" + aValue + "'";
michael@0 274
michael@0 275 return this._test(condition, aMessage, diagnosis);
michael@0 276 },
michael@0 277
michael@0 278 /**
michael@0 279 * Test if both specified values are identical.
michael@0 280 *
michael@0 281 * @param {boolean|string|number|object} aValue
michael@0 282 * Value to test.
michael@0 283 * @param {boolean|string|number|object} aExpected
michael@0 284 * Value to strictly compare with.
michael@0 285 * @param {string} aMessage
michael@0 286 * Message to show for the test result
michael@0 287 * @throws {errors.AssertionError}
michael@0 288 *
michael@0 289 * @returns {boolean} Result of the test.
michael@0 290 */
michael@0 291 equal: function Assert_equal(aValue, aExpected, aMessage) {
michael@0 292 let condition = (aValue === aExpected);
michael@0 293 let diagnosis = "'" + aValue + "' should equal '" + aExpected + "'";
michael@0 294
michael@0 295 return this._test(condition, aMessage, diagnosis);
michael@0 296 },
michael@0 297
michael@0 298 /**
michael@0 299 * Test if both specified values are not identical.
michael@0 300 *
michael@0 301 * @param {boolean|string|number|object} aValue
michael@0 302 * Value to test.
michael@0 303 * @param {boolean|string|number|object} aExpected
michael@0 304 * Value to strictly compare with.
michael@0 305 * @param {string} aMessage
michael@0 306 * Message to show for the test result
michael@0 307 * @throws {errors.AssertionError}
michael@0 308 *
michael@0 309 * @returns {boolean} Result of the test.
michael@0 310 */
michael@0 311 notEqual: function Assert_notEqual(aValue, aExpected, aMessage) {
michael@0 312 let condition = (aValue !== aExpected);
michael@0 313 let diagnosis = "'" + aValue + "' should not equal '" + aExpected + "'";
michael@0 314
michael@0 315 return this._test(condition, aMessage, diagnosis);
michael@0 316 },
michael@0 317
michael@0 318 /**
michael@0 319 * Test if an object equals another object
michael@0 320 *
michael@0 321 * @param {object} aValue
michael@0 322 * The object to test.
michael@0 323 * @param {object} aExpected
michael@0 324 * The object to strictly compare with.
michael@0 325 * @param {string} aMessage
michael@0 326 * Message to show for the test result
michael@0 327 * @throws {errors.AssertionError}
michael@0 328 *
michael@0 329 * @returns {boolean} Result of the test.
michael@0 330 */
michael@0 331 deepEqual: function equal(aValue, aExpected, aMessage) {
michael@0 332 let condition = this._deepEqual(aValue, aExpected);
michael@0 333 try {
michael@0 334 var aValueString = JSON.stringify(aValue);
michael@0 335 } catch (e) {
michael@0 336 var aValueString = String(aValue);
michael@0 337 }
michael@0 338 try {
michael@0 339 var aExpectedString = JSON.stringify(aExpected);
michael@0 340 } catch (e) {
michael@0 341 var aExpectedString = String(aExpected);
michael@0 342 }
michael@0 343
michael@0 344 let diagnosis = "'" + aValueString + "' should equal '" +
michael@0 345 aExpectedString + "'";
michael@0 346
michael@0 347 return this._test(condition, aMessage, diagnosis);
michael@0 348 },
michael@0 349
michael@0 350 /**
michael@0 351 * Test if an object does not equal another object
michael@0 352 *
michael@0 353 * @param {object} aValue
michael@0 354 * The object to test.
michael@0 355 * @param {object} aExpected
michael@0 356 * The object to strictly compare with.
michael@0 357 * @param {string} aMessage
michael@0 358 * Message to show for the test result
michael@0 359 * @throws {errors.AssertionError}
michael@0 360 *
michael@0 361 * @returns {boolean} Result of the test.
michael@0 362 */
michael@0 363 notDeepEqual: function notEqual(aValue, aExpected, aMessage) {
michael@0 364 let condition = !this._deepEqual(aValue, aExpected);
michael@0 365 try {
michael@0 366 var aValueString = JSON.stringify(aValue);
michael@0 367 } catch (e) {
michael@0 368 var aValueString = String(aValue);
michael@0 369 }
michael@0 370 try {
michael@0 371 var aExpectedString = JSON.stringify(aExpected);
michael@0 372 } catch (e) {
michael@0 373 var aExpectedString = String(aExpected);
michael@0 374 }
michael@0 375
michael@0 376 let diagnosis = "'" + aValueString + "' should not equal '" +
michael@0 377 aExpectedString + "'";
michael@0 378
michael@0 379 return this._test(condition, aMessage, diagnosis);
michael@0 380 },
michael@0 381
michael@0 382 /**
michael@0 383 * Test if the regular expression matches the string.
michael@0 384 *
michael@0 385 * @param {string} aString
michael@0 386 * String to test.
michael@0 387 * @param {RegEx} aRegex
michael@0 388 * Regular expression to use for testing that a match exists.
michael@0 389 * @param {string} aMessage
michael@0 390 * Message to show for the test result
michael@0 391 * @throws {errors.AssertionError}
michael@0 392 *
michael@0 393 * @returns {boolean} Result of the test.
michael@0 394 */
michael@0 395 match: function Assert_match(aString, aRegex, aMessage) {
michael@0 396 // XXX Bug 634948
michael@0 397 // Regex objects are transformed to strings when evaluated in a sandbox
michael@0 398 // For now lets re-create the regex from its string representation
michael@0 399 let pattern = flags = "";
michael@0 400 try {
michael@0 401 let matches = aRegex.toString().match(/\/(.*)\/(.*)/);
michael@0 402
michael@0 403 pattern = matches[1];
michael@0 404 flags = matches[2];
michael@0 405 } catch (e) {
michael@0 406 }
michael@0 407
michael@0 408 let regex = new RegExp(pattern, flags);
michael@0 409 let condition = (aString.match(regex) !== null);
michael@0 410 let diagnosis = "'" + regex + "' matches for '" + aString + "'";
michael@0 411
michael@0 412 return this._test(condition, aMessage, diagnosis);
michael@0 413 },
michael@0 414
michael@0 415 /**
michael@0 416 * Test if the regular expression does not match the string.
michael@0 417 *
michael@0 418 * @param {string} aString
michael@0 419 * String to test.
michael@0 420 * @param {RegEx} aRegex
michael@0 421 * Regular expression to use for testing that a match does not exist.
michael@0 422 * @param {string} aMessage
michael@0 423 * Message to show for the test result
michael@0 424 * @throws {errors.AssertionError}
michael@0 425 *
michael@0 426 * @returns {boolean} Result of the test.
michael@0 427 */
michael@0 428 notMatch: function Assert_notMatch(aString, aRegex, aMessage) {
michael@0 429 // XXX Bug 634948
michael@0 430 // Regex objects are transformed to strings when evaluated in a sandbox
michael@0 431 // For now lets re-create the regex from its string representation
michael@0 432 let pattern = flags = "";
michael@0 433 try {
michael@0 434 let matches = aRegex.toString().match(/\/(.*)\/(.*)/);
michael@0 435
michael@0 436 pattern = matches[1];
michael@0 437 flags = matches[2];
michael@0 438 } catch (e) {
michael@0 439 }
michael@0 440
michael@0 441 let regex = new RegExp(pattern, flags);
michael@0 442 let condition = (aString.match(regex) === null);
michael@0 443 let diagnosis = "'" + regex + "' doesn't match for '" + aString + "'";
michael@0 444
michael@0 445 return this._test(condition, aMessage, diagnosis);
michael@0 446 },
michael@0 447
michael@0 448
michael@0 449 /**
michael@0 450 * Test if a code block throws an exception.
michael@0 451 *
michael@0 452 * @param {string} block
michael@0 453 * function to call to test for exception
michael@0 454 * @param {RegEx} error
michael@0 455 * the expected error class
michael@0 456 * @param {string} message
michael@0 457 * message to present if assertion fails
michael@0 458 * @throws {errors.AssertionError}
michael@0 459 *
michael@0 460 * @returns {boolean} Result of the test.
michael@0 461 */
michael@0 462 throws : function Assert_throws(block, /*optional*/error, /*optional*/message) {
michael@0 463 return this._throws.apply(this, [true].concat(Array.prototype.slice.call(arguments)));
michael@0 464 },
michael@0 465
michael@0 466 /**
michael@0 467 * Test if a code block doesn't throw an exception.
michael@0 468 *
michael@0 469 * @param {string} block
michael@0 470 * function to call to test for exception
michael@0 471 * @param {RegEx} error
michael@0 472 * the expected error class
michael@0 473 * @param {string} message
michael@0 474 * message to present if assertion fails
michael@0 475 * @throws {errors.AssertionError}
michael@0 476 *
michael@0 477 * @returns {boolean} Result of the test.
michael@0 478 */
michael@0 479 doesNotThrow : function Assert_doesNotThrow(block, /*optional*/error, /*optional*/message) {
michael@0 480 return this._throws.apply(this, [false].concat(Array.prototype.slice.call(arguments)));
michael@0 481 },
michael@0 482
michael@0 483 /* Tests whether a code block throws the expected exception
michael@0 484 class. helper for throws() and doesNotThrow()
michael@0 485
michael@0 486 adapted from node.js's assert._throws()
michael@0 487 https://github.com/joyent/node/blob/master/lib/assert.js
michael@0 488 */
michael@0 489 _throws : function Assert__throws(shouldThrow, block, expected, message) {
michael@0 490 var actual;
michael@0 491
michael@0 492 if (typeof expected === 'string') {
michael@0 493 message = expected;
michael@0 494 expected = null;
michael@0 495 }
michael@0 496
michael@0 497 try {
michael@0 498 block();
michael@0 499 } catch (e) {
michael@0 500 actual = e;
michael@0 501 }
michael@0 502
michael@0 503 message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
michael@0 504 (message ? ' ' + message : '.');
michael@0 505
michael@0 506 if (shouldThrow && !actual) {
michael@0 507 return this._test(false, message, 'Missing expected exception');
michael@0 508 }
michael@0 509
michael@0 510 if (!shouldThrow && this._expectedException(actual, expected)) {
michael@0 511 return this._test(false, message, 'Got unwanted exception');
michael@0 512 }
michael@0 513
michael@0 514 if ((shouldThrow && actual && expected &&
michael@0 515 !this._expectedException(actual, expected)) || (!shouldThrow && actual)) {
michael@0 516 throw actual;
michael@0 517 }
michael@0 518
michael@0 519 return this._test(true, message);
michael@0 520 },
michael@0 521
michael@0 522 /**
michael@0 523 * Test if the string contains the pattern.
michael@0 524 *
michael@0 525 * @param {String} aString String to test.
michael@0 526 * @param {String} aPattern Pattern to look for in the string
michael@0 527 * @param {String} aMessage Message to show for the test result
michael@0 528 * @throws {errors.AssertionError}
michael@0 529 *
michael@0 530 * @returns {Boolean} Result of the test.
michael@0 531 */
michael@0 532 contain: function Assert_contain(aString, aPattern, aMessage) {
michael@0 533 let condition = (aString.indexOf(aPattern) !== -1);
michael@0 534 let diagnosis = "'" + aString + "' should contain '" + aPattern + "'";
michael@0 535
michael@0 536 return this._test(condition, aMessage, diagnosis);
michael@0 537 },
michael@0 538
michael@0 539 /**
michael@0 540 * Test if the string does not contain the pattern.
michael@0 541 *
michael@0 542 * @param {String} aString String to test.
michael@0 543 * @param {String} aPattern Pattern to look for in the string
michael@0 544 * @param {String} aMessage Message to show for the test result
michael@0 545 * @throws {errors.AssertionError}
michael@0 546 *
michael@0 547 * @returns {Boolean} Result of the test.
michael@0 548 */
michael@0 549 notContain: function Assert_notContain(aString, aPattern, aMessage) {
michael@0 550 let condition = (aString.indexOf(aPattern) === -1);
michael@0 551 let diagnosis = "'" + aString + "' should not contain '" + aPattern + "'";
michael@0 552
michael@0 553 return this._test(condition, aMessage, diagnosis);
michael@0 554 },
michael@0 555
michael@0 556 /**
michael@0 557 * Waits for the callback evaluates to true
michael@0 558 *
michael@0 559 * @param {Function} aCallback
michael@0 560 * Callback for evaluation
michael@0 561 * @param {String} aMessage
michael@0 562 * Message to show for result
michael@0 563 * @param {Number} aTimeout
michael@0 564 * Timeout in waiting for evaluation
michael@0 565 * @param {Number} aInterval
michael@0 566 * Interval between evaluation attempts
michael@0 567 * @param {Object} aThisObject
michael@0 568 * this object
michael@0 569 * @throws {errors.AssertionError}
michael@0 570 *
michael@0 571 * @returns {Boolean} Result of the test.
michael@0 572 */
michael@0 573 waitFor: function Assert_waitFor(aCallback, aMessage, aTimeout, aInterval, aThisObject) {
michael@0 574 var timeout = aTimeout || 5000;
michael@0 575 var interval = aInterval || 100;
michael@0 576
michael@0 577 var self = {
michael@0 578 timeIsUp: false,
michael@0 579 result: aCallback.call(aThisObject)
michael@0 580 };
michael@0 581 var deadline = Date.now() + timeout;
michael@0 582
michael@0 583 function wait() {
michael@0 584 if (self.result !== true) {
michael@0 585 self.result = aCallback.call(aThisObject);
michael@0 586 self.timeIsUp = Date.now() > deadline;
michael@0 587 }
michael@0 588 }
michael@0 589
michael@0 590 var hwindow = Services.appShell.hiddenDOMWindow;
michael@0 591 var timeoutInterval = hwindow.setInterval(wait, interval);
michael@0 592 var thread = Services.tm.currentThread;
michael@0 593
michael@0 594 while (self.result !== true && !self.timeIsUp) {
michael@0 595 thread.processNextEvent(true);
michael@0 596
michael@0 597 let type = typeof(self.result);
michael@0 598 if (type !== 'boolean')
michael@0 599 throw TypeError("waitFor() callback has to return a boolean" +
michael@0 600 " instead of '" + type + "'");
michael@0 601 }
michael@0 602
michael@0 603 hwindow.clearInterval(timeoutInterval);
michael@0 604
michael@0 605 if (self.result !== true && self.timeIsUp) {
michael@0 606 aMessage = aMessage || arguments.callee.name + ": Timeout exceeded for '" + aCallback + "'";
michael@0 607 throw new errors.TimeoutError(aMessage);
michael@0 608 }
michael@0 609
michael@0 610 broker.pass({'function':'assert.waitFor()'});
michael@0 611 return true;
michael@0 612 }
michael@0 613 }
michael@0 614
michael@0 615 /* non-fatal assertions */
michael@0 616 var Expect = function () {}
michael@0 617
michael@0 618 Expect.prototype = new Assert();
michael@0 619
michael@0 620 /**
michael@0 621 * Log a test as failing by adding a fail frame.
michael@0 622 *
michael@0 623 * @param {object} aResult
michael@0 624 * Test result details used for reporting.
michael@0 625 * <dl>
michael@0 626 * <dd>fileName</dd>
michael@0 627 * <dt>Name of the file in which the assertion failed.</dt>
michael@0 628 * <dd>functionName</dd>
michael@0 629 * <dt>Function in which the assertion failed.</dt>
michael@0 630 * <dd>lineNumber</dd>
michael@0 631 * <dt>Line number of the file in which the assertion failed.</dt>
michael@0 632 * <dd>message</dd>
michael@0 633 * <dt>Message why the assertion failed.</dt>
michael@0 634 * </dl>
michael@0 635 */
michael@0 636 Expect.prototype._logFail = function Expect__logFail(aResult) {
michael@0 637 broker.fail({fail: aResult});
michael@0 638 }
michael@0 639
michael@0 640 /**
michael@0 641 * Waits for the callback evaluates to true
michael@0 642 *
michael@0 643 * @param {Function} aCallback
michael@0 644 * Callback for evaluation
michael@0 645 * @param {String} aMessage
michael@0 646 * Message to show for result
michael@0 647 * @param {Number} aTimeout
michael@0 648 * Timeout in waiting for evaluation
michael@0 649 * @param {Number} aInterval
michael@0 650 * Interval between evaluation attempts
michael@0 651 * @param {Object} aThisObject
michael@0 652 * this object
michael@0 653 */
michael@0 654 Expect.prototype.waitFor = function Expect_waitFor(aCallback, aMessage, aTimeout, aInterval, aThisObject) {
michael@0 655 let condition = true;
michael@0 656 let message = aMessage;
michael@0 657
michael@0 658 try {
michael@0 659 Assert.prototype.waitFor.apply(this, arguments);
michael@0 660 }
michael@0 661 catch (ex if ex instanceof errors.AssertionError) {
michael@0 662 message = ex.message;
michael@0 663 condition = false;
michael@0 664 }
michael@0 665
michael@0 666 return this._test(condition, message);
michael@0 667 }

mercurial