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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/services/sync/tps/extensions/mozmill/resource/modules/assertions.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,667 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +var EXPORTED_SYMBOLS = ['Assert', 'Expect'];
     1.9 +
    1.10 +const Cu = Components.utils;
    1.11 +
    1.12 +Cu.import("resource://gre/modules/Services.jsm");
    1.13 +
    1.14 +var broker = {}; Cu.import('resource://mozmill/driver/msgbroker.js', broker);
    1.15 +var errors = {}; Cu.import('resource://mozmill/modules/errors.js', errors);
    1.16 +var stack = {}; Cu.import('resource://mozmill/modules/stack.js', stack);
    1.17 +
    1.18 +/**
    1.19 + * @name assertions
    1.20 + * @namespace Defines expect and assert methods to be used for assertions.
    1.21 + */
    1.22 +
    1.23 +/**
    1.24 + * The Assert class implements fatal assertions, and can be used in cases
    1.25 + * when a failing test has to directly abort the current test function. All
    1.26 + * remaining tasks will not be performed.
    1.27 + *
    1.28 + */
    1.29 +var Assert = function () {}
    1.30 +
    1.31 +Assert.prototype = {
    1.32 +
    1.33 +  // The following deepEquals implementation is from Narwhal under this license:
    1.34 +
    1.35 +  // http://wiki.commonjs.org/wiki/Unit_Testing/1.0
    1.36 +  //
    1.37 +  // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
    1.38 +  //
    1.39 +  // Originally from narwhal.js (http://narwhaljs.org)
    1.40 +  // Copyright (c) 2009 Thomas Robinson <280north.com>
    1.41 +  //
    1.42 +  // Permission is hereby granted, free of charge, to any person obtaining a copy
    1.43 +  // of this software and associated documentation files (the 'Software'), to
    1.44 +  // deal in the Software without restriction, including without limitation the
    1.45 +  // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    1.46 +  // sell copies of the Software, and to permit persons to whom the Software is
    1.47 +  // furnished to do so, subject to the following conditions:
    1.48 +  //
    1.49 +  // The above copyright notice and this permission notice shall be included in
    1.50 +  // all copies or substantial portions of the Software.
    1.51 +  //
    1.52 +  // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    1.53 +  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    1.54 +  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    1.55 +  // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
    1.56 +  // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    1.57 +  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    1.58 +
    1.59 +  _deepEqual: function (actual, expected) {
    1.60 +    // 7.1. All identical values are equivalent, as determined by ===.
    1.61 +    if (actual === expected) {
    1.62 +      return true;
    1.63 +
    1.64 +    // 7.2. If the expected value is a Date object, the actual value is
    1.65 +    // equivalent if it is also a Date object that refers to the same time.
    1.66 +    } else if (actual instanceof Date && expected instanceof Date) {
    1.67 +      return actual.getTime() === expected.getTime();
    1.68 +
    1.69 +    // 7.3. Other pairs that do not both pass typeof value == 'object',
    1.70 +    // equivalence is determined by ==.
    1.71 +    } else if (typeof actual != 'object' && typeof expected != 'object') {
    1.72 +      return actual == expected;
    1.73 +
    1.74 +    // 7.4. For all other Object pairs, including Array objects, equivalence is
    1.75 +    // determined by having the same number of owned properties (as verified
    1.76 +    // with Object.prototype.hasOwnProperty.call), the same set of keys
    1.77 +    // (although not necessarily the same order), equivalent values for every
    1.78 +    // corresponding key, and an identical 'prototype' property. Note: this
    1.79 +    // accounts for both named and indexed properties on Arrays.
    1.80 +    } else {
    1.81 +      return this._objEquiv(actual, expected);
    1.82 +    }
    1.83 +  },
    1.84 +
    1.85 +  _objEquiv: function (a, b) {
    1.86 +    if (a == null || a == undefined || b == null || b == undefined)
    1.87 +      return false;
    1.88 +    // an identical 'prototype' property.
    1.89 +    if (a.prototype !== b.prototype) return false;
    1.90 +
    1.91 +    function isArguments(object) {
    1.92 +      return Object.prototype.toString.call(object) == '[object Arguments]';
    1.93 +    }
    1.94 +
    1.95 +    //~~~I've managed to break Object.keys through screwy arguments passing.
    1.96 +    // Converting to array solves the problem.
    1.97 +    if (isArguments(a)) {
    1.98 +      if (!isArguments(b)) {
    1.99 +        return false;
   1.100 +      }
   1.101 +      a = pSlice.call(a);
   1.102 +      b = pSlice.call(b);
   1.103 +      return _deepEqual(a, b);
   1.104 +    }
   1.105 +    try {
   1.106 +      var ka = Object.keys(a),
   1.107 +          kb = Object.keys(b),
   1.108 +          key, i;
   1.109 +    } catch (e) {//happens when one is a string literal and the other isn't
   1.110 +      return false;
   1.111 +    }
   1.112 +    // having the same number of owned properties (keys incorporates
   1.113 +    // hasOwnProperty)
   1.114 +    if (ka.length != kb.length)
   1.115 +      return false;
   1.116 +    //the same set of keys (although not necessarily the same order),
   1.117 +    ka.sort();
   1.118 +    kb.sort();
   1.119 +    //~~~cheap key test
   1.120 +    for (i = ka.length - 1; i >= 0; i--) {
   1.121 +      if (ka[i] != kb[i])
   1.122 +        return false;
   1.123 +    }
   1.124 +    //equivalent values for every corresponding key, and
   1.125 +    //~~~possibly expensive deep test
   1.126 +    for (i = ka.length - 1; i >= 0; i--) {
   1.127 +      key = ka[i];
   1.128 +      if (!this._deepEqual(a[key], b[key])) return false;
   1.129 +    }
   1.130 +    return true;
   1.131 +  },
   1.132 +
   1.133 +  _expectedException : function Assert__expectedException(actual, expected) {
   1.134 +    if (!actual || !expected) {
   1.135 +      return false;
   1.136 +    }
   1.137 +
   1.138 +    if (expected instanceof RegExp) {
   1.139 +      return expected.test(actual);
   1.140 +    } else if (actual instanceof expected) {
   1.141 +      return true;
   1.142 +    } else if (expected.call({}, actual) === true) {
   1.143 +      return true;
   1.144 +    } else if (actual.name === expected.name) {
   1.145 +      return true;
   1.146 +    }
   1.147 +
   1.148 +    return false;
   1.149 +  },
   1.150 +
   1.151 +  /**
   1.152 +   * Log a test as failing by throwing an AssertionException.
   1.153 +   *
   1.154 +   * @param {object} aResult
   1.155 +   *   Test result details used for reporting.
   1.156 +   *   <dl>
   1.157 +   *     <dd>fileName</dd>
   1.158 +   *     <dt>Name of the file in which the assertion failed.</dt>
   1.159 +   *     <dd>functionName</dd>
   1.160 +   *     <dt>Function in which the assertion failed.</dt>
   1.161 +   *     <dd>lineNumber</dd>
   1.162 +   *     <dt>Line number of the file in which the assertion failed.</dt>
   1.163 +   *     <dd>message</dd>
   1.164 +   *     <dt>Message why the assertion failed.</dt>
   1.165 +   *   </dl>
   1.166 +   * @throws {errors.AssertionError}
   1.167 +   *
   1.168 +   */
   1.169 +  _logFail: function Assert__logFail(aResult) {
   1.170 +    throw new errors.AssertionError(aResult.message,
   1.171 +                                    aResult.fileName,
   1.172 +                                    aResult.lineNumber,
   1.173 +                                    aResult.functionName,
   1.174 +                                    aResult.name);
   1.175 +  },
   1.176 +
   1.177 +  /**
   1.178 +   * Log a test as passing by adding a pass frame.
   1.179 +   *
   1.180 +   * @param {object} aResult
   1.181 +   *   Test result details used for reporting.
   1.182 +   *   <dl>
   1.183 +   *     <dd>fileName</dd>
   1.184 +   *     <dt>Name of the file in which the assertion failed.</dt>
   1.185 +   *     <dd>functionName</dd>
   1.186 +   *     <dt>Function in which the assertion failed.</dt>
   1.187 +   *     <dd>lineNumber</dd>
   1.188 +   *     <dt>Line number of the file in which the assertion failed.</dt>
   1.189 +   *     <dd>message</dd>
   1.190 +   *     <dt>Message why the assertion failed.</dt>
   1.191 +   *   </dl>
   1.192 +   */
   1.193 +  _logPass: function Assert__logPass(aResult) {
   1.194 +    broker.pass({pass: aResult});
   1.195 +  },
   1.196 +
   1.197 +  /**
   1.198 +   * Test the condition and mark test as passed or failed
   1.199 +   *
   1.200 +   * @param {boolean} aCondition
   1.201 +   *   Condition to test.
   1.202 +   * @param {string} aMessage
   1.203 +   *   Message to show for the test result
   1.204 +   * @param {string} aDiagnosis
   1.205 +   *   Diagnose message to show for the test result
   1.206 +   * @throws {errors.AssertionError}
   1.207 +   *
   1.208 +   * @returns {boolean} Result of the test.
   1.209 +   */
   1.210 +  _test: function Assert__test(aCondition, aMessage, aDiagnosis) {
   1.211 +    let diagnosis = aDiagnosis || "";
   1.212 +    let message = aMessage || "";
   1.213 +
   1.214 +    if (diagnosis)
   1.215 +      message = aMessage ? message + " - " + diagnosis : diagnosis;
   1.216 +
   1.217 +    // Build result data
   1.218 +    let frame = stack.findCallerFrame(Components.stack);
   1.219 +
   1.220 +    let result = {
   1.221 +      'fileName'     : frame.filename.replace(/(.*)-> /, ""),
   1.222 +      'functionName' : frame.name,
   1.223 +      'lineNumber'   : frame.lineNumber,
   1.224 +      'message'      : message
   1.225 +    };
   1.226 +
   1.227 +    // Log test result
   1.228 +    if (aCondition) {
   1.229 +      this._logPass(result);
   1.230 +    }
   1.231 +    else {
   1.232 +      result.stack = Components.stack;
   1.233 +      this._logFail(result);
   1.234 +    }
   1.235 +
   1.236 +    return aCondition;
   1.237 +  },
   1.238 +
   1.239 +  /**
   1.240 +   * Perform an always passing test
   1.241 +   *
   1.242 +   * @param {string} aMessage
   1.243 +   *   Message to show for the test result.
   1.244 +   * @returns {boolean} Always returns true.
   1.245 +   */
   1.246 +  pass: function Assert_pass(aMessage) {
   1.247 +    return this._test(true, aMessage, undefined);
   1.248 +  },
   1.249 +
   1.250 +  /**
   1.251 +   * Perform an always failing test
   1.252 +   *
   1.253 +   * @param {string} aMessage
   1.254 +   *   Message to show for the test result.
   1.255 +   * @throws {errors.AssertionError}
   1.256 +   *
   1.257 +   * @returns {boolean} Always returns false.
   1.258 +   */
   1.259 +  fail: function Assert_fail(aMessage) {
   1.260 +    return this._test(false, aMessage, undefined);
   1.261 +  },
   1.262 +
   1.263 +  /**
   1.264 +   * Test if the value pass
   1.265 +   *
   1.266 +   * @param {boolean|string|number|object} aValue
   1.267 +   *   Value to test.
   1.268 +   * @param {string} aMessage
   1.269 +   *   Message to show for the test result.
   1.270 +   * @throws {errors.AssertionError}
   1.271 +   *
   1.272 +   * @returns {boolean} Result of the test.
   1.273 +   */
   1.274 +  ok: function Assert_ok(aValue, aMessage) {
   1.275 +    let condition = !!aValue;
   1.276 +    let diagnosis = "got '" + aValue + "'";
   1.277 +
   1.278 +    return this._test(condition, aMessage, diagnosis);
   1.279 +  },
   1.280 +
   1.281 + /**
   1.282 +   * Test if both specified values are identical.
   1.283 +   *
   1.284 +   * @param {boolean|string|number|object} aValue
   1.285 +   *   Value to test.
   1.286 +   * @param {boolean|string|number|object} aExpected
   1.287 +   *   Value to strictly compare with.
   1.288 +   * @param {string} aMessage
   1.289 +   *   Message to show for the test result
   1.290 +   * @throws {errors.AssertionError}
   1.291 +   *
   1.292 +   * @returns {boolean} Result of the test.
   1.293 +   */
   1.294 +  equal: function Assert_equal(aValue, aExpected, aMessage) {
   1.295 +    let condition = (aValue === aExpected);
   1.296 +    let diagnosis = "'" + aValue + "' should equal '" + aExpected + "'";
   1.297 +
   1.298 +    return this._test(condition, aMessage, diagnosis);
   1.299 +  },
   1.300 +
   1.301 + /**
   1.302 +   * Test if both specified values are not identical.
   1.303 +   *
   1.304 +   * @param {boolean|string|number|object} aValue
   1.305 +   *   Value to test.
   1.306 +   * @param {boolean|string|number|object} aExpected
   1.307 +   *   Value to strictly compare with.
   1.308 +   * @param {string} aMessage
   1.309 +   *   Message to show for the test result
   1.310 +   * @throws {errors.AssertionError}
   1.311 +   *
   1.312 +   * @returns {boolean} Result of the test.
   1.313 +   */
   1.314 +  notEqual: function Assert_notEqual(aValue, aExpected, aMessage) {
   1.315 +    let condition = (aValue !== aExpected);
   1.316 +    let diagnosis = "'" + aValue + "' should not equal '" + aExpected + "'";
   1.317 +
   1.318 +    return this._test(condition, aMessage, diagnosis);
   1.319 +  },
   1.320 +
   1.321 +  /**
   1.322 +   * Test if an object equals another object
   1.323 +   *
   1.324 +   * @param {object} aValue
   1.325 +   *   The object to test.
   1.326 +   * @param {object} aExpected
   1.327 +   *   The object to strictly compare with.
   1.328 +   * @param {string} aMessage
   1.329 +   *   Message to show for the test result
   1.330 +   * @throws {errors.AssertionError}
   1.331 +   *
   1.332 +   * @returns {boolean} Result of the test.
   1.333 +   */
   1.334 +  deepEqual: function equal(aValue, aExpected, aMessage) {
   1.335 +    let condition = this._deepEqual(aValue, aExpected);
   1.336 +    try {
   1.337 +      var aValueString = JSON.stringify(aValue);
   1.338 +    } catch (e) {
   1.339 +      var aValueString = String(aValue);
   1.340 +    }
   1.341 +    try {
   1.342 +      var aExpectedString = JSON.stringify(aExpected);
   1.343 +    } catch (e) {
   1.344 +      var aExpectedString = String(aExpected);
   1.345 +    }
   1.346 +
   1.347 +    let diagnosis = "'" + aValueString + "' should equal '" +
   1.348 +                    aExpectedString + "'";
   1.349 +
   1.350 +    return this._test(condition, aMessage, diagnosis);
   1.351 +  },
   1.352 +
   1.353 +  /**
   1.354 +   * Test if an object does not equal another object
   1.355 +   *
   1.356 +   * @param {object} aValue
   1.357 +   *   The object to test.
   1.358 +   * @param {object} aExpected
   1.359 +   *   The object to strictly compare with.
   1.360 +   * @param {string} aMessage
   1.361 +   *   Message to show for the test result
   1.362 +   * @throws {errors.AssertionError}
   1.363 +   *
   1.364 +   * @returns {boolean} Result of the test.
   1.365 +   */
   1.366 +  notDeepEqual: function notEqual(aValue, aExpected, aMessage) {
   1.367 +     let condition = !this._deepEqual(aValue, aExpected);
   1.368 +     try {
   1.369 +       var aValueString = JSON.stringify(aValue);
   1.370 +     } catch (e) {
   1.371 +       var aValueString = String(aValue);
   1.372 +     }
   1.373 +     try {
   1.374 +       var aExpectedString = JSON.stringify(aExpected);
   1.375 +     } catch (e) {
   1.376 +       var aExpectedString = String(aExpected);
   1.377 +     }
   1.378 +
   1.379 +     let diagnosis = "'" + aValueString + "' should not equal '" +
   1.380 +                     aExpectedString + "'";
   1.381 +
   1.382 +     return this._test(condition, aMessage, diagnosis);
   1.383 +  },
   1.384 +
   1.385 +  /**
   1.386 +   * Test if the regular expression matches the string.
   1.387 +   *
   1.388 +   * @param {string} aString
   1.389 +   *   String to test.
   1.390 +   * @param {RegEx} aRegex
   1.391 +   *   Regular expression to use for testing that a match exists.
   1.392 +   * @param {string} aMessage
   1.393 +   *   Message to show for the test result
   1.394 +   * @throws {errors.AssertionError}
   1.395 +   *
   1.396 +   * @returns {boolean} Result of the test.
   1.397 +   */
   1.398 +  match: function Assert_match(aString, aRegex, aMessage) {
   1.399 +    // XXX Bug 634948
   1.400 +    // Regex objects are transformed to strings when evaluated in a sandbox
   1.401 +    // For now lets re-create the regex from its string representation
   1.402 +    let pattern = flags = "";
   1.403 +    try {
   1.404 +      let matches = aRegex.toString().match(/\/(.*)\/(.*)/);
   1.405 +
   1.406 +      pattern = matches[1];
   1.407 +      flags = matches[2];
   1.408 +    } catch (e) {
   1.409 +    }
   1.410 +
   1.411 +    let regex = new RegExp(pattern, flags);
   1.412 +    let condition = (aString.match(regex) !== null);
   1.413 +    let diagnosis = "'" + regex + "' matches for '" + aString + "'";
   1.414 +
   1.415 +    return this._test(condition, aMessage, diagnosis);
   1.416 +  },
   1.417 +
   1.418 +  /**
   1.419 +   * Test if the regular expression does not match the string.
   1.420 +   *
   1.421 +   * @param {string} aString
   1.422 +   *   String to test.
   1.423 +   * @param {RegEx} aRegex
   1.424 +   *   Regular expression to use for testing that a match does not exist.
   1.425 +   * @param {string} aMessage
   1.426 +   *   Message to show for the test result
   1.427 +   * @throws {errors.AssertionError}
   1.428 +   *
   1.429 +   * @returns {boolean} Result of the test.
   1.430 +   */
   1.431 +  notMatch: function Assert_notMatch(aString, aRegex, aMessage) {
   1.432 +    // XXX Bug 634948
   1.433 +    // Regex objects are transformed to strings when evaluated in a sandbox
   1.434 +    // For now lets re-create the regex from its string representation
   1.435 +    let pattern = flags = "";
   1.436 +    try {
   1.437 +      let matches = aRegex.toString().match(/\/(.*)\/(.*)/);
   1.438 +
   1.439 +      pattern = matches[1];
   1.440 +      flags = matches[2];
   1.441 +    } catch (e) {
   1.442 +    }
   1.443 +
   1.444 +    let regex = new RegExp(pattern, flags);
   1.445 +    let condition = (aString.match(regex) === null);
   1.446 +    let diagnosis = "'" + regex + "' doesn't match for '" + aString + "'";
   1.447 +
   1.448 +    return this._test(condition, aMessage, diagnosis);
   1.449 +  },
   1.450 +
   1.451 +
   1.452 +  /**
   1.453 +   * Test if a code block throws an exception.
   1.454 +   *
   1.455 +   * @param {string} block
   1.456 +   *   function to call to test for exception
   1.457 +   * @param {RegEx} error
   1.458 +   *   the expected error class
   1.459 +   * @param {string} message
   1.460 +   *   message to present if assertion fails
   1.461 +   * @throws {errors.AssertionError}
   1.462 +   *
   1.463 +   * @returns {boolean} Result of the test.
   1.464 +   */
   1.465 +  throws : function Assert_throws(block, /*optional*/error, /*optional*/message) {
   1.466 +    return this._throws.apply(this, [true].concat(Array.prototype.slice.call(arguments)));
   1.467 +  },
   1.468 +
   1.469 +  /**
   1.470 +   * Test if a code block doesn't throw an exception.
   1.471 +   *
   1.472 +   * @param {string} block
   1.473 +   *   function to call to test for exception
   1.474 +   * @param {RegEx} error
   1.475 +   *   the expected error class
   1.476 +   * @param {string} message
   1.477 +   *   message to present if assertion fails
   1.478 +   * @throws {errors.AssertionError}
   1.479 +   *
   1.480 +   * @returns {boolean} Result of the test.
   1.481 +   */
   1.482 +  doesNotThrow : function Assert_doesNotThrow(block, /*optional*/error, /*optional*/message) {
   1.483 +    return this._throws.apply(this, [false].concat(Array.prototype.slice.call(arguments)));
   1.484 +  },
   1.485 +
   1.486 +  /* Tests whether a code block throws the expected exception
   1.487 +     class. helper for throws() and doesNotThrow()
   1.488 +
   1.489 +     adapted from node.js's assert._throws()
   1.490 +     https://github.com/joyent/node/blob/master/lib/assert.js
   1.491 +  */
   1.492 +  _throws : function Assert__throws(shouldThrow, block, expected, message) {
   1.493 +    var actual;
   1.494 +
   1.495 +    if (typeof expected === 'string') {
   1.496 +      message = expected;
   1.497 +      expected = null;
   1.498 +    }
   1.499 +
   1.500 +    try {
   1.501 +      block();
   1.502 +    } catch (e) {
   1.503 +      actual = e;
   1.504 +    }
   1.505 +
   1.506 +    message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
   1.507 +              (message ? ' ' + message : '.');
   1.508 +
   1.509 +    if (shouldThrow && !actual) {
   1.510 +      return this._test(false, message, 'Missing expected exception');
   1.511 +    }
   1.512 +
   1.513 +    if (!shouldThrow && this._expectedException(actual, expected)) {
   1.514 +      return this._test(false, message, 'Got unwanted exception');
   1.515 +    }
   1.516 +
   1.517 +    if ((shouldThrow && actual && expected &&
   1.518 +        !this._expectedException(actual, expected)) || (!shouldThrow && actual)) {
   1.519 +      throw actual;
   1.520 +    }
   1.521 +
   1.522 +    return this._test(true, message);
   1.523 +  },
   1.524 +
   1.525 +  /**
   1.526 +   * Test if the string contains the pattern.
   1.527 +   *
   1.528 +   * @param {String} aString String to test.
   1.529 +   * @param {String} aPattern Pattern to look for in the string
   1.530 +   * @param {String} aMessage Message to show for the test result
   1.531 +   * @throws {errors.AssertionError}
   1.532 +   *
   1.533 +   * @returns {Boolean} Result of the test.
   1.534 +   */
   1.535 +  contain: function Assert_contain(aString, aPattern, aMessage) {
   1.536 +    let condition = (aString.indexOf(aPattern) !== -1);
   1.537 +    let diagnosis = "'" + aString + "' should contain '" + aPattern + "'";
   1.538 +
   1.539 +    return this._test(condition, aMessage, diagnosis);
   1.540 +  },
   1.541 +
   1.542 +  /**
   1.543 +   * Test if the string does not contain the pattern.
   1.544 +   *
   1.545 +   * @param {String} aString String to test.
   1.546 +   * @param {String} aPattern Pattern to look for in the string
   1.547 +   * @param {String} aMessage Message to show for the test result
   1.548 +   * @throws {errors.AssertionError}
   1.549 +   *
   1.550 +   * @returns {Boolean} Result of the test.
   1.551 +   */
   1.552 +  notContain: function Assert_notContain(aString, aPattern, aMessage) {
   1.553 +    let condition = (aString.indexOf(aPattern) === -1);
   1.554 +    let diagnosis = "'" + aString + "' should not contain '" + aPattern + "'";
   1.555 +
   1.556 +    return this._test(condition, aMessage, diagnosis);
   1.557 +  },
   1.558 +
   1.559 +  /**
   1.560 +   * Waits for the callback evaluates to true
   1.561 +   *
   1.562 +   * @param {Function} aCallback
   1.563 +   *        Callback for evaluation
   1.564 +   * @param {String} aMessage
   1.565 +   *        Message to show for result
   1.566 +   * @param {Number} aTimeout
   1.567 +   *        Timeout in waiting for evaluation
   1.568 +   * @param {Number} aInterval
   1.569 +   *        Interval between evaluation attempts
   1.570 +   * @param {Object} aThisObject
   1.571 +   *        this object
   1.572 +   * @throws {errors.AssertionError}
   1.573 +   *
   1.574 +   * @returns {Boolean} Result of the test.
   1.575 +   */
   1.576 +  waitFor: function Assert_waitFor(aCallback, aMessage, aTimeout, aInterval, aThisObject) {
   1.577 +    var timeout = aTimeout || 5000;
   1.578 +    var interval = aInterval || 100;
   1.579 +
   1.580 +    var self = {
   1.581 +      timeIsUp: false,
   1.582 +      result: aCallback.call(aThisObject)
   1.583 +    };
   1.584 +    var deadline = Date.now() + timeout;
   1.585 +
   1.586 +    function wait() {
   1.587 +      if (self.result !== true) {
   1.588 +        self.result = aCallback.call(aThisObject);
   1.589 +        self.timeIsUp = Date.now() > deadline;
   1.590 +      }
   1.591 +    }
   1.592 +
   1.593 +    var hwindow = Services.appShell.hiddenDOMWindow;
   1.594 +    var timeoutInterval = hwindow.setInterval(wait, interval);
   1.595 +    var thread = Services.tm.currentThread;
   1.596 +
   1.597 +    while (self.result !== true && !self.timeIsUp) {
   1.598 +      thread.processNextEvent(true);
   1.599 +
   1.600 +      let type = typeof(self.result);
   1.601 +      if (type !== 'boolean')
   1.602 +        throw TypeError("waitFor() callback has to return a boolean" +
   1.603 +                        " instead of '" + type + "'");
   1.604 +    }
   1.605 +
   1.606 +    hwindow.clearInterval(timeoutInterval);
   1.607 +
   1.608 +    if (self.result !== true && self.timeIsUp) {
   1.609 +      aMessage = aMessage || arguments.callee.name + ": Timeout exceeded for '" + aCallback + "'";
   1.610 +      throw new errors.TimeoutError(aMessage);
   1.611 +    }
   1.612 +
   1.613 +    broker.pass({'function':'assert.waitFor()'});
   1.614 +    return true;
   1.615 +  }
   1.616 +}
   1.617 +
   1.618 +/* non-fatal assertions */
   1.619 +var Expect = function () {}
   1.620 +
   1.621 +Expect.prototype = new Assert();
   1.622 +
   1.623 +/**
   1.624 + * Log a test as failing by adding a fail frame.
   1.625 + *
   1.626 + * @param {object} aResult
   1.627 + *   Test result details used for reporting.
   1.628 + *   <dl>
   1.629 + *     <dd>fileName</dd>
   1.630 + *     <dt>Name of the file in which the assertion failed.</dt>
   1.631 + *     <dd>functionName</dd>
   1.632 + *     <dt>Function in which the assertion failed.</dt>
   1.633 + *     <dd>lineNumber</dd>
   1.634 + *     <dt>Line number of the file in which the assertion failed.</dt>
   1.635 + *     <dd>message</dd>
   1.636 + *     <dt>Message why the assertion failed.</dt>
   1.637 + *   </dl>
   1.638 + */
   1.639 +Expect.prototype._logFail = function Expect__logFail(aResult) {
   1.640 +  broker.fail({fail: aResult});
   1.641 +}
   1.642 +
   1.643 +/**
   1.644 + * Waits for the callback evaluates to true
   1.645 + *
   1.646 + * @param {Function} aCallback
   1.647 + *        Callback for evaluation
   1.648 + * @param {String} aMessage
   1.649 + *        Message to show for result
   1.650 + * @param {Number} aTimeout
   1.651 + *        Timeout in waiting for evaluation
   1.652 + * @param {Number} aInterval
   1.653 + *        Interval between evaluation attempts
   1.654 + * @param {Object} aThisObject
   1.655 + *        this object
   1.656 + */
   1.657 +Expect.prototype.waitFor = function Expect_waitFor(aCallback, aMessage, aTimeout, aInterval, aThisObject) {
   1.658 +  let condition = true;
   1.659 +  let message = aMessage;
   1.660 +
   1.661 +  try {
   1.662 +    Assert.prototype.waitFor.apply(this, arguments);
   1.663 +  }
   1.664 +  catch (ex if ex instanceof errors.AssertionError) {
   1.665 +    message = ex.message;
   1.666 +    condition = false;
   1.667 +  }
   1.668 +
   1.669 +  return this._test(condition, message);
   1.670 +}

mercurial