/ vendor / jasmine.js
jasmine.js
   1  // Modified line
   2  // - var isCommonJS = typeof window == "undefined" && typeof exports == "object";
   3  // + var isCommonJS = typeof exports == "object";
   4  //
   5  // Modified method jasmine.WaitsForBlock.prototype.execute
   6  
   7  var isCommonJS = typeof exports == "object";
   8  
   9  /**
  10   * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
  11   *
  12   * @namespace
  13   */
  14  var jasmine = {};
  15  if (isCommonJS) exports.jasmine = jasmine;
  16  /**
  17   * @private
  18   */
  19  jasmine.unimplementedMethod_ = function() {
  20    throw new Error("unimplemented method");
  21  };
  22  
  23  /**
  24   * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
  25   * a plain old variable and may be redefined by somebody else.
  26   *
  27   * @private
  28   */
  29  jasmine.undefined = jasmine.___undefined___;
  30  
  31  /**
  32   * Show diagnostic messages in the console if set to true
  33   *
  34   */
  35  jasmine.VERBOSE = false;
  36  
  37  /**
  38   * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
  39   *
  40   */
  41  jasmine.DEFAULT_UPDATE_INTERVAL = 250;
  42  
  43  /**
  44   * Maximum levels of nesting that will be included when an object is pretty-printed
  45   */
  46  jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
  47  
  48  /**
  49   * Default timeout interval in milliseconds for waitsFor() blocks.
  50   */
  51  jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
  52  
  53  /**
  54   * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite.
  55   * Set to false to let the exception bubble up in the browser.
  56   *
  57   */
  58  jasmine.CATCH_EXCEPTIONS = true;
  59  
  60  jasmine.getGlobal = function() {
  61    function getGlobal() {
  62      return window;
  63    }
  64  
  65    return getGlobal();
  66  };
  67  
  68  /**
  69   * Allows for bound functions to be compared.  Internal use only.
  70   *
  71   * @ignore
  72   * @private
  73   * @param base {Object} bound 'this' for the function
  74   * @param name {Function} function to find
  75   */
  76  jasmine.bindOriginal_ = function(base, name) {
  77    var original = base[name];
  78    if (original.apply) {
  79      return function() {
  80        return original.apply(base, arguments);
  81      };
  82    } else {
  83      // IE support
  84      return jasmine.getGlobal()[name];
  85    }
  86  };
  87  
  88  jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
  89  jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
  90  jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
  91  jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
  92  
  93  jasmine.MessageResult = function(values) {
  94    this.type = 'log';
  95    this.values = values;
  96    this.trace = new Error(); // todo: test better
  97  };
  98  
  99  jasmine.MessageResult.prototype.toString = function() {
 100    var text = "";
 101    for (var i = 0; i < this.values.length; i++) {
 102      if (i > 0) text += " ";
 103      if (jasmine.isString_(this.values[i])) {
 104        text += this.values[i];
 105      } else {
 106        text += jasmine.pp(this.values[i]);
 107      }
 108    }
 109    return text;
 110  };
 111  
 112  jasmine.ExpectationResult = function(params) {
 113    this.type = 'expect';
 114    this.matcherName = params.matcherName;
 115    this.passed_ = params.passed;
 116    this.expected = params.expected;
 117    this.actual = params.actual;
 118    this.message = this.passed_ ? 'Passed.' : params.message;
 119  
 120    var trace = (params.trace || new Error(this.message));
 121    this.trace = this.passed_ ? '' : trace;
 122  };
 123  
 124  jasmine.ExpectationResult.prototype.toString = function () {
 125    return this.message;
 126  };
 127  
 128  jasmine.ExpectationResult.prototype.passed = function () {
 129    return this.passed_;
 130  };
 131  
 132  /**
 133   * Getter for the Jasmine environment. Ensures one gets created
 134   */
 135  jasmine.getEnv = function() {
 136    var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
 137    return env;
 138  };
 139  
 140  /**
 141   * @ignore
 142   * @private
 143   * @param value
 144   * @returns {Boolean}
 145   */
 146  jasmine.isArray_ = function(value) {
 147    return jasmine.isA_("Array", value);
 148  };
 149  
 150  /**
 151   * @ignore
 152   * @private
 153   * @param value
 154   * @returns {Boolean}
 155   */
 156  jasmine.isString_ = function(value) {
 157    return jasmine.isA_("String", value);
 158  };
 159  
 160  /**
 161   * @ignore
 162   * @private
 163   * @param value
 164   * @returns {Boolean}
 165   */
 166  jasmine.isNumber_ = function(value) {
 167    return jasmine.isA_("Number", value);
 168  };
 169  
 170  /**
 171   * @ignore
 172   * @private
 173   * @param {String} typeName
 174   * @param value
 175   * @returns {Boolean}
 176   */
 177  jasmine.isA_ = function(typeName, value) {
 178    return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
 179  };
 180  
 181  /**
 182   * Pretty printer for expecations.  Takes any object and turns it into a human-readable string.
 183   *
 184   * @param value {Object} an object to be outputted
 185   * @returns {String}
 186   */
 187  jasmine.pp = function(value) {
 188    var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
 189    stringPrettyPrinter.format(value);
 190    return stringPrettyPrinter.string;
 191  };
 192  
 193  /**
 194   * Returns true if the object is a DOM Node.
 195   *
 196   * @param {Object} obj object to check
 197   * @returns {Boolean}
 198   */
 199  jasmine.isDomNode = function(obj) {
 200    return obj.nodeType > 0;
 201  };
 202  
 203  /**
 204   * Returns a matchable 'generic' object of the class type.  For use in expecations of type when values don't matter.
 205   *
 206   * @example
 207   * // don't care about which function is passed in, as long as it's a function
 208   * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
 209   *
 210   * @param {Class} clazz
 211   * @returns matchable object of the type clazz
 212   */
 213  jasmine.any = function(clazz) {
 214    return new jasmine.Matchers.Any(clazz);
 215  };
 216  
 217  /**
 218   * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
 219   * attributes on the object.
 220   *
 221   * @example
 222   * // don't care about any other attributes than foo.
 223   * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
 224   *
 225   * @param sample {Object} sample
 226   * @returns matchable object for the sample
 227   */
 228  jasmine.objectContaining = function (sample) {
 229      return new jasmine.Matchers.ObjectContaining(sample);
 230  };
 231  
 232  /**
 233   * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
 234   *
 235   * Spies should be created in test setup, before expectations.  They can then be checked, using the standard Jasmine
 236   * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
 237   *
 238   * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
 239   *
 240   * Spies are torn down at the end of every spec.
 241   *
 242   * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
 243   *
 244   * @example
 245   * // a stub
 246   * var myStub = jasmine.createSpy('myStub');  // can be used anywhere
 247   *
 248   * // spy example
 249   * var foo = {
 250   *   not: function(bool) { return !bool; }
 251   * }
 252   *
 253   * // actual foo.not will not be called, execution stops
 254   * spyOn(foo, 'not');
 255  
 256   // foo.not spied upon, execution will continue to implementation
 257   * spyOn(foo, 'not').andCallThrough();
 258   *
 259   * // fake example
 260   * var foo = {
 261   *   not: function(bool) { return !bool; }
 262   * }
 263   *
 264   * // foo.not(val) will return val
 265   * spyOn(foo, 'not').andCallFake(function(value) {return value;});
 266   *
 267   * // mock example
 268   * foo.not(7 == 7);
 269   * expect(foo.not).toHaveBeenCalled();
 270   * expect(foo.not).toHaveBeenCalledWith(true);
 271   *
 272   * @constructor
 273   * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
 274   * @param {String} name
 275   */
 276  jasmine.Spy = function(name) {
 277    /**
 278     * The name of the spy, if provided.
 279     */
 280    this.identity = name || 'unknown';
 281    /**
 282     *  Is this Object a spy?
 283     */
 284    this.isSpy = true;
 285    /**
 286     * The actual function this spy stubs.
 287     */
 288    this.plan = function() {
 289    };
 290    /**
 291     * Tracking of the most recent call to the spy.
 292     * @example
 293     * var mySpy = jasmine.createSpy('foo');
 294     * mySpy(1, 2);
 295     * mySpy.mostRecentCall.args = [1, 2];
 296     */
 297    this.mostRecentCall = {};
 298  
 299    /**
 300     * Holds arguments for each call to the spy, indexed by call count
 301     * @example
 302     * var mySpy = jasmine.createSpy('foo');
 303     * mySpy(1, 2);
 304     * mySpy(7, 8);
 305     * mySpy.mostRecentCall.args = [7, 8];
 306     * mySpy.argsForCall[0] = [1, 2];
 307     * mySpy.argsForCall[1] = [7, 8];
 308     */
 309    this.argsForCall = [];
 310    this.calls = [];
 311  };
 312  
 313  /**
 314   * Tells a spy to call through to the actual implemenatation.
 315   *
 316   * @example
 317   * var foo = {
 318   *   bar: function() { // do some stuff }
 319   * }
 320   *
 321   * // defining a spy on an existing property: foo.bar
 322   * spyOn(foo, 'bar').andCallThrough();
 323   */
 324  jasmine.Spy.prototype.andCallThrough = function() {
 325    this.plan = this.originalValue;
 326    return this;
 327  };
 328  
 329  /**
 330   * For setting the return value of a spy.
 331   *
 332   * @example
 333   * // defining a spy from scratch: foo() returns 'baz'
 334   * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
 335   *
 336   * // defining a spy on an existing property: foo.bar() returns 'baz'
 337   * spyOn(foo, 'bar').andReturn('baz');
 338   *
 339   * @param {Object} value
 340   */
 341  jasmine.Spy.prototype.andReturn = function(value) {
 342    this.plan = function() {
 343      return value;
 344    };
 345    return this;
 346  };
 347  
 348  /**
 349   * For throwing an exception when a spy is called.
 350   *
 351   * @example
 352   * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
 353   * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
 354   *
 355   * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
 356   * spyOn(foo, 'bar').andThrow('baz');
 357   *
 358   * @param {String} exceptionMsg
 359   */
 360  jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
 361    this.plan = function() {
 362      throw exceptionMsg;
 363    };
 364    return this;
 365  };
 366  
 367  /**
 368   * Calls an alternate implementation when a spy is called.
 369   *
 370   * @example
 371   * var baz = function() {
 372   *   // do some stuff, return something
 373   * }
 374   * // defining a spy from scratch: foo() calls the function baz
 375   * var foo = jasmine.createSpy('spy on foo').andCall(baz);
 376   *
 377   * // defining a spy on an existing property: foo.bar() calls an anonymnous function
 378   * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
 379   *
 380   * @param {Function} fakeFunc
 381   */
 382  jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
 383    this.plan = fakeFunc;
 384    return this;
 385  };
 386  
 387  /**
 388   * Resets all of a spy's the tracking variables so that it can be used again.
 389   *
 390   * @example
 391   * spyOn(foo, 'bar');
 392   *
 393   * foo.bar();
 394   *
 395   * expect(foo.bar.callCount).toEqual(1);
 396   *
 397   * foo.bar.reset();
 398   *
 399   * expect(foo.bar.callCount).toEqual(0);
 400   */
 401  jasmine.Spy.prototype.reset = function() {
 402    this.wasCalled = false;
 403    this.callCount = 0;
 404    this.argsForCall = [];
 405    this.calls = [];
 406    this.mostRecentCall = {};
 407  };
 408  
 409  jasmine.createSpy = function(name) {
 410  
 411    var spyObj = function() {
 412      spyObj.wasCalled = true;
 413      spyObj.callCount++;
 414      var args = jasmine.util.argsToArray(arguments);
 415      spyObj.mostRecentCall.object = this;
 416      spyObj.mostRecentCall.args = args;
 417      spyObj.argsForCall.push(args);
 418      spyObj.calls.push({object: this, args: args});
 419      return spyObj.plan.apply(this, arguments);
 420    };
 421  
 422    var spy = new jasmine.Spy(name);
 423  
 424    for (var prop in spy) {
 425      spyObj[prop] = spy[prop];
 426    }
 427  
 428    spyObj.reset();
 429  
 430    return spyObj;
 431  };
 432  
 433  /**
 434   * Determines whether an object is a spy.
 435   *
 436   * @param {jasmine.Spy|Object} putativeSpy
 437   * @returns {Boolean}
 438   */
 439  jasmine.isSpy = function(putativeSpy) {
 440    return putativeSpy && putativeSpy.isSpy;
 441  };
 442  
 443  /**
 444   * Creates a more complicated spy: an Object that has every property a function that is a spy.  Used for stubbing something
 445   * large in one call.
 446   *
 447   * @param {String} baseName name of spy class
 448   * @param {Array} methodNames array of names of methods to make spies
 449   */
 450  jasmine.createSpyObj = function(baseName, methodNames) {
 451    if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
 452      throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
 453    }
 454    var obj = {};
 455    for (var i = 0; i < methodNames.length; i++) {
 456      obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
 457    }
 458    return obj;
 459  };
 460  
 461  /**
 462   * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
 463   *
 464   * Be careful not to leave calls to <code>jasmine.log</code> in production code.
 465   */
 466  jasmine.log = function() {
 467    var spec = jasmine.getEnv().currentSpec;
 468    spec.log.apply(spec, arguments);
 469  };
 470  
 471  /**
 472   * Function that installs a spy on an existing object's method name.  Used within a Spec to create a spy.
 473   *
 474   * @example
 475   * // spy example
 476   * var foo = {
 477   *   not: function(bool) { return !bool; }
 478   * }
 479   * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
 480   *
 481   * @see jasmine.createSpy
 482   * @param obj
 483   * @param methodName
 484   * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods
 485   */
 486  var spyOn = function(obj, methodName) {
 487    return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
 488  };
 489  if (isCommonJS) exports.spyOn = spyOn;
 490  
 491  /**
 492   * Creates a Jasmine spec that will be added to the current suite.
 493   *
 494   * // TODO: pending tests
 495   *
 496   * @example
 497   * it('should be true', function() {
 498   *   expect(true).toEqual(true);
 499   * });
 500   *
 501   * @param {String} desc description of this specification
 502   * @param {Function} func defines the preconditions and expectations of the spec
 503   */
 504  var it = function(desc, func) {
 505    return jasmine.getEnv().it(desc, func);
 506  };
 507  if (isCommonJS) exports.it = it;
 508  
 509  /**
 510   * Creates a <em>disabled</em> Jasmine spec.
 511   *
 512   * A convenience method that allows existing specs to be disabled temporarily during development.
 513   *
 514   * @param {String} desc description of this specification
 515   * @param {Function} func defines the preconditions and expectations of the spec
 516   */
 517  var xit = function(desc, func) {
 518    return jasmine.getEnv().xit(desc, func);
 519  };
 520  if (isCommonJS) exports.xit = xit;
 521  
 522  /**
 523   * Starts a chain for a Jasmine expectation.
 524   *
 525   * It is passed an Object that is the actual value and should chain to one of the many
 526   * jasmine.Matchers functions.
 527   *
 528   * @param {Object} actual Actual value to test against and expected value
 529   * @return {jasmine.Matchers}
 530   */
 531  var expect = function(actual) {
 532    return jasmine.getEnv().currentSpec.expect(actual);
 533  };
 534  if (isCommonJS) exports.expect = expect;
 535  
 536  /**
 537   * Defines part of a jasmine spec.  Used in cominbination with waits or waitsFor in asynchrnous specs.
 538   *
 539   * @param {Function} func Function that defines part of a jasmine spec.
 540   */
 541  var runs = function(func) {
 542    jasmine.getEnv().currentSpec.runs(func);
 543  };
 544  if (isCommonJS) exports.runs = runs;
 545  
 546  /**
 547   * Waits a fixed time period before moving to the next block.
 548   *
 549   * @deprecated Use waitsFor() instead
 550   * @param {Number} timeout milliseconds to wait
 551   */
 552  var waits = function(timeout) {
 553    jasmine.getEnv().currentSpec.waits(timeout);
 554  };
 555  if (isCommonJS) exports.waits = waits;
 556  
 557  /**
 558   * Waits for the latchFunction to return true before proceeding to the next block.
 559   *
 560   * @param {Function} latchFunction
 561   * @param {String} optional_timeoutMessage
 562   * @param {Number} optional_timeout
 563   */
 564  var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
 565    jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
 566  };
 567  if (isCommonJS) exports.waitsFor = waitsFor;
 568  
 569  /**
 570   * A function that is called before each spec in a suite.
 571   *
 572   * Used for spec setup, including validating assumptions.
 573   *
 574   * @param {Function} beforeEachFunction
 575   */
 576  var beforeEach = function(beforeEachFunction) {
 577    jasmine.getEnv().beforeEach(beforeEachFunction);
 578  };
 579  if (isCommonJS) exports.beforeEach = beforeEach;
 580  
 581  /**
 582   * A function that is called after each spec in a suite.
 583   *
 584   * Used for restoring any state that is hijacked during spec execution.
 585   *
 586   * @param {Function} afterEachFunction
 587   */
 588  var afterEach = function(afterEachFunction) {
 589    jasmine.getEnv().afterEach(afterEachFunction);
 590  };
 591  if (isCommonJS) exports.afterEach = afterEach;
 592  
 593  /**
 594   * Defines a suite of specifications.
 595   *
 596   * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
 597   * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
 598   * of setup in some tests.
 599   *
 600   * @example
 601   * // TODO: a simple suite
 602   *
 603   * // TODO: a simple suite with a nested describe block
 604   *
 605   * @param {String} description A string, usually the class under test.
 606   * @param {Function} specDefinitions function that defines several specs.
 607   */
 608  var describe = function(description, specDefinitions) {
 609    return jasmine.getEnv().describe(description, specDefinitions);
 610  };
 611  if (isCommonJS) exports.describe = describe;
 612  
 613  /**
 614   * Disables a suite of specifications.  Used to disable some suites in a file, or files, temporarily during development.
 615   *
 616   * @param {String} description A string, usually the class under test.
 617   * @param {Function} specDefinitions function that defines several specs.
 618   */
 619  var xdescribe = function(description, specDefinitions) {
 620    return jasmine.getEnv().xdescribe(description, specDefinitions);
 621  };
 622  if (isCommonJS) exports.xdescribe = xdescribe;
 623  
 624  
 625  // Provide the XMLHttpRequest class for IE 5.x-6.x:
 626  jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
 627    function tryIt(f) {
 628      try {
 629        return f();
 630      } catch(e) {
 631      }
 632      return null;
 633    }
 634  
 635    var xhr = tryIt(function() {
 636      return new ActiveXObject("Msxml2.XMLHTTP.6.0");
 637    }) ||
 638      tryIt(function() {
 639        return new ActiveXObject("Msxml2.XMLHTTP.3.0");
 640      }) ||
 641      tryIt(function() {
 642        return new ActiveXObject("Msxml2.XMLHTTP");
 643      }) ||
 644      tryIt(function() {
 645        return new ActiveXObject("Microsoft.XMLHTTP");
 646      });
 647  
 648    if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
 649  
 650    return xhr;
 651  } : XMLHttpRequest;
 652  /**
 653   * @namespace
 654   */
 655  jasmine.util = {};
 656  
 657  /**
 658   * Declare that a child class inherit it's prototype from the parent class.
 659   *
 660   * @private
 661   * @param {Function} childClass
 662   * @param {Function} parentClass
 663   */
 664  jasmine.util.inherit = function(childClass, parentClass) {
 665    /**
 666     * @private
 667     */
 668    var subclass = function() {
 669    };
 670    subclass.prototype = parentClass.prototype;
 671    childClass.prototype = new subclass();
 672  };
 673  
 674  jasmine.util.formatException = function(e) {
 675    var lineNumber;
 676    if (e.line) {
 677      lineNumber = e.line;
 678    }
 679    else if (e.lineNumber) {
 680      lineNumber = e.lineNumber;
 681    }
 682  
 683    var file;
 684  
 685    if (e.sourceURL) {
 686      file = e.sourceURL;
 687    }
 688    else if (e.fileName) {
 689      file = e.fileName;
 690    }
 691  
 692    var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
 693  
 694    if (file && lineNumber) {
 695      message += ' in ' + file + ' (line ' + lineNumber + ')';
 696    }
 697  
 698    return message;
 699  };
 700  
 701  jasmine.util.htmlEscape = function(str) {
 702    if (!str) return str;
 703    return str.replace(/&/g, '&amp;')
 704      .replace(/</g, '&lt;')
 705      .replace(/>/g, '&gt;');
 706  };
 707  
 708  jasmine.util.argsToArray = function(args) {
 709    var arrayOfArgs = [];
 710    for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
 711    return arrayOfArgs;
 712  };
 713  
 714  jasmine.util.extend = function(destination, source) {
 715    for (var property in source) destination[property] = source[property];
 716    return destination;
 717  };
 718  
 719  /**
 720   * Environment for Jasmine
 721   *
 722   * @constructor
 723   */
 724  jasmine.Env = function() {
 725    this.currentSpec = null;
 726    this.currentSuite = null;
 727    this.currentRunner_ = new jasmine.Runner(this);
 728  
 729    this.reporter = new jasmine.MultiReporter();
 730  
 731    this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
 732    this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
 733    this.lastUpdate = 0;
 734    this.specFilter = function() {
 735      return true;
 736    };
 737  
 738    this.nextSpecId_ = 0;
 739    this.nextSuiteId_ = 0;
 740    this.equalityTesters_ = [];
 741  
 742    // wrap matchers
 743    this.matchersClass = function() {
 744      jasmine.Matchers.apply(this, arguments);
 745    };
 746    jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
 747  
 748    jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
 749  };
 750  
 751  
 752  jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
 753  jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
 754  jasmine.Env.prototype.setInterval = jasmine.setInterval;
 755  jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
 756  
 757  /**
 758   * @returns an object containing jasmine version build info, if set.
 759   */
 760  jasmine.Env.prototype.version = function () {
 761    if (jasmine.version_) {
 762      return jasmine.version_;
 763    } else {
 764      throw new Error('Version not set');
 765    }
 766  };
 767  
 768  /**
 769   * @returns string containing jasmine version build info, if set.
 770   */
 771  jasmine.Env.prototype.versionString = function() {
 772    if (!jasmine.version_) {
 773      return "version unknown";
 774    }
 775  
 776    var version = this.version();
 777    var versionString = version.major + "." + version.minor + "." + version.build;
 778    if (version.release_candidate) {
 779      versionString += ".rc" + version.release_candidate;
 780    }
 781    versionString += " revision " + version.revision;
 782    return versionString;
 783  };
 784  
 785  /**
 786   * @returns a sequential integer starting at 0
 787   */
 788  jasmine.Env.prototype.nextSpecId = function () {
 789    return this.nextSpecId_++;
 790  };
 791  
 792  /**
 793   * @returns a sequential integer starting at 0
 794   */
 795  jasmine.Env.prototype.nextSuiteId = function () {
 796    return this.nextSuiteId_++;
 797  };
 798  
 799  /**
 800   * Register a reporter to receive status updates from Jasmine.
 801   * @param {jasmine.Reporter} reporter An object which will receive status updates.
 802   */
 803  jasmine.Env.prototype.addReporter = function(reporter) {
 804    this.reporter.addReporter(reporter);
 805  };
 806  
 807  jasmine.Env.prototype.execute = function() {
 808    this.currentRunner_.execute();
 809  };
 810  
 811  jasmine.Env.prototype.describe = function(description, specDefinitions) {
 812    var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
 813  
 814    var parentSuite = this.currentSuite;
 815    if (parentSuite) {
 816      parentSuite.add(suite);
 817    } else {
 818      this.currentRunner_.add(suite);
 819    }
 820  
 821    this.currentSuite = suite;
 822  
 823    var declarationError = null;
 824    try {
 825      specDefinitions.call(suite);
 826    } catch(e) {
 827      declarationError = e;
 828    }
 829  
 830    if (declarationError) {
 831      this.it("encountered a declaration exception", function() {
 832        throw declarationError;
 833      });
 834    }
 835  
 836    this.currentSuite = parentSuite;
 837  
 838    return suite;
 839  };
 840  
 841  jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
 842    if (this.currentSuite) {
 843      this.currentSuite.beforeEach(beforeEachFunction);
 844    } else {
 845      this.currentRunner_.beforeEach(beforeEachFunction);
 846    }
 847  };
 848  
 849  jasmine.Env.prototype.currentRunner = function () {
 850    return this.currentRunner_;
 851  };
 852  
 853  jasmine.Env.prototype.afterEach = function(afterEachFunction) {
 854    if (this.currentSuite) {
 855      this.currentSuite.afterEach(afterEachFunction);
 856    } else {
 857      this.currentRunner_.afterEach(afterEachFunction);
 858    }
 859  
 860  };
 861  
 862  jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
 863    return {
 864      execute: function() {
 865      }
 866    };
 867  };
 868  
 869  jasmine.Env.prototype.it = function(description, func) {
 870    var spec = new jasmine.Spec(this, this.currentSuite, description);
 871    this.currentSuite.add(spec);
 872    this.currentSpec = spec;
 873  
 874    if (func) {
 875      spec.runs(func);
 876    }
 877  
 878    return spec;
 879  };
 880  
 881  jasmine.Env.prototype.xit = function(desc, func) {
 882    return {
 883      id: this.nextSpecId(),
 884      runs: function() {
 885      }
 886    };
 887  };
 888  
 889  jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
 890    if (a.source != b.source)
 891      mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
 892  
 893    if (a.ignoreCase != b.ignoreCase)
 894      mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
 895  
 896    if (a.global != b.global)
 897      mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
 898  
 899    if (a.multiline != b.multiline)
 900      mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
 901  
 902    if (a.sticky != b.sticky)
 903      mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
 904  
 905    return (mismatchValues.length === 0);
 906  };
 907  
 908  jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
 909    if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
 910      return true;
 911    }
 912  
 913    a.__Jasmine_been_here_before__ = b;
 914    b.__Jasmine_been_here_before__ = a;
 915  
 916    var hasKey = function(obj, keyName) {
 917      return obj !== null && obj[keyName] !== jasmine.undefined;
 918    };
 919  
 920    for (var property in b) {
 921      if (!hasKey(a, property) && hasKey(b, property)) {
 922        mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
 923      }
 924    }
 925    for (property in a) {
 926      if (!hasKey(b, property) && hasKey(a, property)) {
 927        mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
 928      }
 929    }
 930    for (property in b) {
 931      if (property == '__Jasmine_been_here_before__') continue;
 932      if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
 933        mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
 934      }
 935    }
 936  
 937    if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
 938      mismatchValues.push("arrays were not the same length");
 939    }
 940  
 941    delete a.__Jasmine_been_here_before__;
 942    delete b.__Jasmine_been_here_before__;
 943    return (mismatchKeys.length === 0 && mismatchValues.length === 0);
 944  };
 945  
 946  jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
 947    mismatchKeys = mismatchKeys || [];
 948    mismatchValues = mismatchValues || [];
 949  
 950    for (var i = 0; i < this.equalityTesters_.length; i++) {
 951      var equalityTester = this.equalityTesters_[i];
 952      var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
 953      if (result !== jasmine.undefined) return result;
 954    }
 955  
 956    if (a === b) return true;
 957  
 958    if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
 959      return (a == jasmine.undefined && b == jasmine.undefined);
 960    }
 961  
 962    if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
 963      return a === b;
 964    }
 965  
 966    if (a instanceof Date && b instanceof Date) {
 967      return a.getTime() == b.getTime();
 968    }
 969  
 970    if (a.jasmineMatches) {
 971      return a.jasmineMatches(b);
 972    }
 973  
 974    if (b.jasmineMatches) {
 975      return b.jasmineMatches(a);
 976    }
 977  
 978    if (a instanceof jasmine.Matchers.ObjectContaining) {
 979      return a.matches(b);
 980    }
 981  
 982    if (b instanceof jasmine.Matchers.ObjectContaining) {
 983      return b.matches(a);
 984    }
 985  
 986    if (jasmine.isString_(a) && jasmine.isString_(b)) {
 987      return (a == b);
 988    }
 989  
 990    if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
 991      return (a == b);
 992    }
 993  
 994    if (a instanceof RegExp && b instanceof RegExp) {
 995      return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
 996    }
 997  
 998    if (typeof a === "object" && typeof b === "object") {
 999      return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
1000    }
1001  
1002    //Straight check
1003    return (a === b);
1004  };
1005  
1006  jasmine.Env.prototype.contains_ = function(haystack, needle) {
1007    if (jasmine.isArray_(haystack)) {
1008      for (var i = 0; i < haystack.length; i++) {
1009        if (this.equals_(haystack[i], needle)) return true;
1010      }
1011      return false;
1012    }
1013    return haystack.indexOf(needle) >= 0;
1014  };
1015  
1016  jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
1017    this.equalityTesters_.push(equalityTester);
1018  };
1019  /** No-op base class for Jasmine reporters.
1020   *
1021   * @constructor
1022   */
1023  jasmine.Reporter = function() {
1024  };
1025  
1026  //noinspection JSUnusedLocalSymbols
1027  jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
1028  };
1029  
1030  //noinspection JSUnusedLocalSymbols
1031  jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
1032  };
1033  
1034  //noinspection JSUnusedLocalSymbols
1035  jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
1036  };
1037  
1038  //noinspection JSUnusedLocalSymbols
1039  jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
1040  };
1041  
1042  //noinspection JSUnusedLocalSymbols
1043  jasmine.Reporter.prototype.reportSpecResults = function(spec) {
1044  };
1045  
1046  //noinspection JSUnusedLocalSymbols
1047  jasmine.Reporter.prototype.log = function(str) {
1048  };
1049  
1050  /**
1051   * Blocks are functions with executable code that make up a spec.
1052   *
1053   * @constructor
1054   * @param {jasmine.Env} env
1055   * @param {Function} func
1056   * @param {jasmine.Spec} spec
1057   */
1058  jasmine.Block = function(env, func, spec) {
1059    this.env = env;
1060    this.func = func;
1061    this.spec = spec;
1062  };
1063  
1064  jasmine.Block.prototype.execute = function(onComplete) {
1065    if (!jasmine.CATCH_EXCEPTIONS) {
1066      this.func.apply(this.spec);
1067    }
1068    else {
1069      try {
1070        this.func.apply(this.spec);
1071      } catch (e) {
1072        this.spec.fail(e);
1073      }
1074    }
1075    onComplete();
1076  };
1077  /** JavaScript API reporter.
1078   *
1079   * @constructor
1080   */
1081  jasmine.JsApiReporter = function() {
1082    this.started = false;
1083    this.finished = false;
1084    this.suites_ = [];
1085    this.results_ = {};
1086  };
1087  
1088  jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
1089    this.started = true;
1090    var suites = runner.topLevelSuites();
1091    for (var i = 0; i < suites.length; i++) {
1092      var suite = suites[i];
1093      this.suites_.push(this.summarize_(suite));
1094    }
1095  };
1096  
1097  jasmine.JsApiReporter.prototype.suites = function() {
1098    return this.suites_;
1099  };
1100  
1101  jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
1102    var isSuite = suiteOrSpec instanceof jasmine.Suite;
1103    var summary = {
1104      id: suiteOrSpec.id,
1105      name: suiteOrSpec.description,
1106      type: isSuite ? 'suite' : 'spec',
1107      children: []
1108    };
1109  
1110    if (isSuite) {
1111      var children = suiteOrSpec.children();
1112      for (var i = 0; i < children.length; i++) {
1113        summary.children.push(this.summarize_(children[i]));
1114      }
1115    }
1116    return summary;
1117  };
1118  
1119  jasmine.JsApiReporter.prototype.results = function() {
1120    return this.results_;
1121  };
1122  
1123  jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
1124    return this.results_[specId];
1125  };
1126  
1127  //noinspection JSUnusedLocalSymbols
1128  jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
1129    this.finished = true;
1130  };
1131  
1132  //noinspection JSUnusedLocalSymbols
1133  jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
1134  };
1135  
1136  //noinspection JSUnusedLocalSymbols
1137  jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
1138    this.results_[spec.id] = {
1139      messages: spec.results().getItems(),
1140      result: spec.results().failedCount > 0 ? "failed" : "passed"
1141    };
1142  };
1143  
1144  //noinspection JSUnusedLocalSymbols
1145  jasmine.JsApiReporter.prototype.log = function(str) {
1146  };
1147  
1148  jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
1149    var results = {};
1150    for (var i = 0; i < specIds.length; i++) {
1151      var specId = specIds[i];
1152      results[specId] = this.summarizeResult_(this.results_[specId]);
1153    }
1154    return results;
1155  };
1156  
1157  jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
1158    var summaryMessages = [];
1159    var messagesLength = result.messages.length;
1160    for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
1161      var resultMessage = result.messages[messageIndex];
1162      summaryMessages.push({
1163        text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
1164        passed: resultMessage.passed ? resultMessage.passed() : true,
1165        type: resultMessage.type,
1166        message: resultMessage.message,
1167        trace: {
1168          stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
1169        }
1170      });
1171    }
1172  
1173    return {
1174      result : result.result,
1175      messages : summaryMessages
1176    };
1177  };
1178  
1179  /**
1180   * @constructor
1181   * @param {jasmine.Env} env
1182   * @param actual
1183   * @param {jasmine.Spec} spec
1184   */
1185  jasmine.Matchers = function(env, actual, spec, opt_isNot) {
1186    this.env = env;
1187    this.actual = actual;
1188    this.spec = spec;
1189    this.isNot = opt_isNot || false;
1190    this.reportWasCalled_ = false;
1191  };
1192  
1193  // todo: @deprecated as of Jasmine 0.11, remove soon [xw]
1194  jasmine.Matchers.pp = function(str) {
1195    throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
1196  };
1197  
1198  // todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
1199  jasmine.Matchers.prototype.report = function(result, failing_message, details) {
1200    throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
1201  };
1202  
1203  jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
1204    for (var methodName in prototype) {
1205      if (methodName == 'report') continue;
1206      var orig = prototype[methodName];
1207      matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
1208    }
1209  };
1210  
1211  jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
1212    return function() {
1213      var matcherArgs = jasmine.util.argsToArray(arguments);
1214      var result = matcherFunction.apply(this, arguments);
1215  
1216      if (this.isNot) {
1217        result = !result;
1218      }
1219  
1220      if (this.reportWasCalled_) return result;
1221  
1222      var message;
1223      if (!result) {
1224        if (this.message) {
1225          message = this.message.apply(this, arguments);
1226          if (jasmine.isArray_(message)) {
1227            message = message[this.isNot ? 1 : 0];
1228          }
1229        } else {
1230          var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
1231          message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
1232          if (matcherArgs.length > 0) {
1233            for (var i = 0; i < matcherArgs.length; i++) {
1234              if (i > 0) message += ",";
1235              message += " " + jasmine.pp(matcherArgs[i]);
1236            }
1237          }
1238          message += ".";
1239        }
1240      }
1241      var expectationResult = new jasmine.ExpectationResult({
1242        matcherName: matcherName,
1243        passed: result,
1244        expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
1245        actual: this.actual,
1246        message: message
1247      });
1248      this.spec.addMatcherResult(expectationResult);
1249      return jasmine.undefined;
1250    };
1251  };
1252  
1253  
1254  
1255  
1256  /**
1257   * toBe: compares the actual to the expected using ===
1258   * @param expected
1259   */
1260  jasmine.Matchers.prototype.toBe = function(expected) {
1261    return this.actual === expected;
1262  };
1263  
1264  /**
1265   * toNotBe: compares the actual to the expected using !==
1266   * @param expected
1267   * @deprecated as of 1.0. Use not.toBe() instead.
1268   */
1269  jasmine.Matchers.prototype.toNotBe = function(expected) {
1270    return this.actual !== expected;
1271  };
1272  
1273  /**
1274   * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
1275   *
1276   * @param expected
1277   */
1278  jasmine.Matchers.prototype.toEqual = function(expected) {
1279    return this.env.equals_(this.actual, expected);
1280  };
1281  
1282  /**
1283   * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
1284   * @param expected
1285   * @deprecated as of 1.0. Use not.toEqual() instead.
1286   */
1287  jasmine.Matchers.prototype.toNotEqual = function(expected) {
1288    return !this.env.equals_(this.actual, expected);
1289  };
1290  
1291  /**
1292   * Matcher that compares the actual to the expected using a regular expression.  Constructs a RegExp, so takes
1293   * a pattern or a String.
1294   *
1295   * @param expected
1296   */
1297  jasmine.Matchers.prototype.toMatch = function(expected) {
1298    return new RegExp(expected).test(this.actual);
1299  };
1300  
1301  /**
1302   * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
1303   * @param expected
1304   * @deprecated as of 1.0. Use not.toMatch() instead.
1305   */
1306  jasmine.Matchers.prototype.toNotMatch = function(expected) {
1307    return !(new RegExp(expected).test(this.actual));
1308  };
1309  
1310  /**
1311   * Matcher that compares the actual to jasmine.undefined.
1312   */
1313  jasmine.Matchers.prototype.toBeDefined = function() {
1314    return (this.actual !== jasmine.undefined);
1315  };
1316  
1317  /**
1318   * Matcher that compares the actual to jasmine.undefined.
1319   */
1320  jasmine.Matchers.prototype.toBeUndefined = function() {
1321    return (this.actual === jasmine.undefined);
1322  };
1323  
1324  /**
1325   * Matcher that compares the actual to null.
1326   */
1327  jasmine.Matchers.prototype.toBeNull = function() {
1328    return (this.actual === null);
1329  };
1330  
1331  /**
1332   * Matcher that compares the actual to NaN.
1333   */
1334  jasmine.Matchers.prototype.toBeNaN = function() {
1335  	this.message = function() {
1336  		return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
1337  	};
1338  
1339  	return (this.actual !== this.actual);
1340  };
1341  
1342  /**
1343   * Matcher that boolean not-nots the actual.
1344   */
1345  jasmine.Matchers.prototype.toBeTruthy = function() {
1346    return !!this.actual;
1347  };
1348  
1349  
1350  /**
1351   * Matcher that boolean nots the actual.
1352   */
1353  jasmine.Matchers.prototype.toBeFalsy = function() {
1354    return !this.actual;
1355  };
1356  
1357  
1358  /**
1359   * Matcher that checks to see if the actual, a Jasmine spy, was called.
1360   */
1361  jasmine.Matchers.prototype.toHaveBeenCalled = function() {
1362    if (arguments.length > 0) {
1363      throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
1364    }
1365  
1366    if (!jasmine.isSpy(this.actual)) {
1367      throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1368    }
1369  
1370    this.message = function() {
1371      return [
1372        "Expected spy " + this.actual.identity + " to have been called.",
1373        "Expected spy " + this.actual.identity + " not to have been called."
1374      ];
1375    };
1376  
1377    return this.actual.wasCalled;
1378  };
1379  
1380  /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
1381  jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
1382  
1383  /**
1384   * Matcher that checks to see if the actual, a Jasmine spy, was not called.
1385   *
1386   * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
1387   */
1388  jasmine.Matchers.prototype.wasNotCalled = function() {
1389    if (arguments.length > 0) {
1390      throw new Error('wasNotCalled does not take arguments');
1391    }
1392  
1393    if (!jasmine.isSpy(this.actual)) {
1394      throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1395    }
1396  
1397    this.message = function() {
1398      return [
1399        "Expected spy " + this.actual.identity + " to not have been called.",
1400        "Expected spy " + this.actual.identity + " to have been called."
1401      ];
1402    };
1403  
1404    return !this.actual.wasCalled;
1405  };
1406  
1407  /**
1408   * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
1409   *
1410   * @example
1411   *
1412   */
1413  jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
1414    var expectedArgs = jasmine.util.argsToArray(arguments);
1415    if (!jasmine.isSpy(this.actual)) {
1416      throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1417    }
1418    this.message = function() {
1419      var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
1420      var positiveMessage = "";
1421      if (this.actual.callCount === 0) {
1422        positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
1423      } else {
1424        positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '')
1425      }
1426      return [positiveMessage, invertedMessage];
1427    };
1428  
1429    return this.env.contains_(this.actual.argsForCall, expectedArgs);
1430  };
1431  
1432  /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
1433  jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
1434  
1435  /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
1436  jasmine.Matchers.prototype.wasNotCalledWith = function() {
1437    var expectedArgs = jasmine.util.argsToArray(arguments);
1438    if (!jasmine.isSpy(this.actual)) {
1439      throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1440    }
1441  
1442    this.message = function() {
1443      return [
1444        "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
1445        "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
1446      ];
1447    };
1448  
1449    return !this.env.contains_(this.actual.argsForCall, expectedArgs);
1450  };
1451  
1452  /**
1453   * Matcher that checks that the expected item is an element in the actual Array.
1454   *
1455   * @param {Object} expected
1456   */
1457  jasmine.Matchers.prototype.toContain = function(expected) {
1458    return this.env.contains_(this.actual, expected);
1459  };
1460  
1461  /**
1462   * Matcher that checks that the expected item is NOT an element in the actual Array.
1463   *
1464   * @param {Object} expected
1465   * @deprecated as of 1.0. Use not.toContain() instead.
1466   */
1467  jasmine.Matchers.prototype.toNotContain = function(expected) {
1468    return !this.env.contains_(this.actual, expected);
1469  };
1470  
1471  jasmine.Matchers.prototype.toBeLessThan = function(expected) {
1472    return this.actual < expected;
1473  };
1474  
1475  jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
1476    return this.actual > expected;
1477  };
1478  
1479  /**
1480   * Matcher that checks that the expected item is equal to the actual item
1481   * up to a given level of decimal precision (default 2).
1482   *
1483   * @param {Number} expected
1484   * @param {Number} precision, as number of decimal places
1485   */
1486  jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
1487    if (!(precision === 0)) {
1488      precision = precision || 2;
1489    }
1490    return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
1491  };
1492  
1493  /**
1494   * Matcher that checks that the expected exception was thrown by the actual.
1495   *
1496   * @param {String} [expected]
1497   */
1498  jasmine.Matchers.prototype.toThrow = function(expected) {
1499    var result = false;
1500    var exception;
1501    if (typeof this.actual != 'function') {
1502      throw new Error('Actual is not a function');
1503    }
1504    try {
1505      this.actual();
1506    } catch (e) {
1507      exception = e;
1508    }
1509    if (exception) {
1510      result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
1511    }
1512  
1513    var not = this.isNot ? "not " : "";
1514  
1515    this.message = function() {
1516      if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
1517        return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
1518      } else {
1519        return "Expected function to throw an exception.";
1520      }
1521    };
1522  
1523    return result;
1524  };
1525  
1526  jasmine.Matchers.Any = function(expectedClass) {
1527    this.expectedClass = expectedClass;
1528  };
1529  
1530  jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
1531    if (this.expectedClass == String) {
1532      return typeof other == 'string' || other instanceof String;
1533    }
1534  
1535    if (this.expectedClass == Number) {
1536      return typeof other == 'number' || other instanceof Number;
1537    }
1538  
1539    if (this.expectedClass == Function) {
1540      return typeof other == 'function' || other instanceof Function;
1541    }
1542  
1543    if (this.expectedClass == Object) {
1544      return typeof other == 'object';
1545    }
1546  
1547    return other instanceof this.expectedClass;
1548  };
1549  
1550  jasmine.Matchers.Any.prototype.jasmineToString = function() {
1551    return '<jasmine.any(' + this.expectedClass + ')>';
1552  };
1553  
1554  jasmine.Matchers.ObjectContaining = function (sample) {
1555    this.sample = sample;
1556  };
1557  
1558  jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
1559    mismatchKeys = mismatchKeys || [];
1560    mismatchValues = mismatchValues || [];
1561  
1562    var env = jasmine.getEnv();
1563  
1564    var hasKey = function(obj, keyName) {
1565      return obj != null && obj[keyName] !== jasmine.undefined;
1566    };
1567  
1568    for (var property in this.sample) {
1569      if (!hasKey(other, property) && hasKey(this.sample, property)) {
1570        mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
1571      }
1572      else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
1573        mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
1574      }
1575    }
1576  
1577    return (mismatchKeys.length === 0 && mismatchValues.length === 0);
1578  };
1579  
1580  jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
1581    return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
1582  };
1583  // Mock setTimeout, clearTimeout
1584  // Contributed by Pivotal Computer Systems, www.pivotalsf.com
1585  
1586  jasmine.FakeTimer = function() {
1587    this.reset();
1588  
1589    var self = this;
1590    self.setTimeout = function(funcToCall, millis) {
1591      self.timeoutsMade++;
1592      self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
1593      return self.timeoutsMade;
1594    };
1595  
1596    self.setInterval = function(funcToCall, millis) {
1597      self.timeoutsMade++;
1598      self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
1599      return self.timeoutsMade;
1600    };
1601  
1602    self.clearTimeout = function(timeoutKey) {
1603      self.scheduledFunctions[timeoutKey] = jasmine.undefined;
1604    };
1605  
1606    self.clearInterval = function(timeoutKey) {
1607      self.scheduledFunctions[timeoutKey] = jasmine.undefined;
1608    };
1609  
1610  };
1611  
1612  jasmine.FakeTimer.prototype.reset = function() {
1613    this.timeoutsMade = 0;
1614    this.scheduledFunctions = {};
1615    this.nowMillis = 0;
1616  };
1617  
1618  jasmine.FakeTimer.prototype.tick = function(millis) {
1619    var oldMillis = this.nowMillis;
1620    var newMillis = oldMillis + millis;
1621    this.runFunctionsWithinRange(oldMillis, newMillis);
1622    this.nowMillis = newMillis;
1623  };
1624  
1625  jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
1626    var scheduledFunc;
1627    var funcsToRun = [];
1628    for (var timeoutKey in this.scheduledFunctions) {
1629      scheduledFunc = this.scheduledFunctions[timeoutKey];
1630      if (scheduledFunc != jasmine.undefined &&
1631          scheduledFunc.runAtMillis >= oldMillis &&
1632          scheduledFunc.runAtMillis <= nowMillis) {
1633        funcsToRun.push(scheduledFunc);
1634        this.scheduledFunctions[timeoutKey] = jasmine.undefined;
1635      }
1636    }
1637  
1638    if (funcsToRun.length > 0) {
1639      funcsToRun.sort(function(a, b) {
1640        return a.runAtMillis - b.runAtMillis;
1641      });
1642      for (var i = 0; i < funcsToRun.length; ++i) {
1643        try {
1644          var funcToRun = funcsToRun[i];
1645          this.nowMillis = funcToRun.runAtMillis;
1646          funcToRun.funcToCall();
1647          if (funcToRun.recurring) {
1648            this.scheduleFunction(funcToRun.timeoutKey,
1649                funcToRun.funcToCall,
1650                funcToRun.millis,
1651                true);
1652          }
1653        } catch(e) {
1654        }
1655      }
1656      this.runFunctionsWithinRange(oldMillis, nowMillis);
1657    }
1658  };
1659  
1660  jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
1661    this.scheduledFunctions[timeoutKey] = {
1662      runAtMillis: this.nowMillis + millis,
1663      funcToCall: funcToCall,
1664      recurring: recurring,
1665      timeoutKey: timeoutKey,
1666      millis: millis
1667    };
1668  };
1669  
1670  /**
1671   * @namespace
1672   */
1673  jasmine.Clock = {
1674    defaultFakeTimer: new jasmine.FakeTimer(),
1675  
1676    reset: function() {
1677      jasmine.Clock.assertInstalled();
1678      jasmine.Clock.defaultFakeTimer.reset();
1679    },
1680  
1681    tick: function(millis) {
1682      jasmine.Clock.assertInstalled();
1683      jasmine.Clock.defaultFakeTimer.tick(millis);
1684    },
1685  
1686    runFunctionsWithinRange: function(oldMillis, nowMillis) {
1687      jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
1688    },
1689  
1690    scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
1691      jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
1692    },
1693  
1694    useMock: function() {
1695      if (!jasmine.Clock.isInstalled()) {
1696        var spec = jasmine.getEnv().currentSpec;
1697        spec.after(jasmine.Clock.uninstallMock);
1698  
1699        jasmine.Clock.installMock();
1700      }
1701    },
1702  
1703    installMock: function() {
1704      jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
1705    },
1706  
1707    uninstallMock: function() {
1708      jasmine.Clock.assertInstalled();
1709      jasmine.Clock.installed = jasmine.Clock.real;
1710    },
1711  
1712    real: {
1713      setTimeout: jasmine.getGlobal().setTimeout,
1714      clearTimeout: jasmine.getGlobal().clearTimeout,
1715      setInterval: jasmine.getGlobal().setInterval,
1716      clearInterval: jasmine.getGlobal().clearInterval
1717    },
1718  
1719    assertInstalled: function() {
1720      if (!jasmine.Clock.isInstalled()) {
1721        throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
1722      }
1723    },
1724  
1725    isInstalled: function() {
1726      return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
1727    },
1728  
1729    installed: null
1730  };
1731  jasmine.Clock.installed = jasmine.Clock.real;
1732  
1733  //else for IE support
1734  jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
1735    if (jasmine.Clock.installed.setTimeout.apply) {
1736      return jasmine.Clock.installed.setTimeout.apply(this, arguments);
1737    } else {
1738      return jasmine.Clock.installed.setTimeout(funcToCall, millis);
1739    }
1740  };
1741  
1742  jasmine.getGlobal().setInterval = function(funcToCall, millis) {
1743    if (jasmine.Clock.installed.setInterval.apply) {
1744      return jasmine.Clock.installed.setInterval.apply(this, arguments);
1745    } else {
1746      return jasmine.Clock.installed.setInterval(funcToCall, millis);
1747    }
1748  };
1749  
1750  jasmine.getGlobal().clearTimeout = function(timeoutKey) {
1751    if (jasmine.Clock.installed.clearTimeout.apply) {
1752      return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
1753    } else {
1754      return jasmine.Clock.installed.clearTimeout(timeoutKey);
1755    }
1756  };
1757  
1758  jasmine.getGlobal().clearInterval = function(timeoutKey) {
1759    if (jasmine.Clock.installed.clearTimeout.apply) {
1760      return jasmine.Clock.installed.clearInterval.apply(this, arguments);
1761    } else {
1762      return jasmine.Clock.installed.clearInterval(timeoutKey);
1763    }
1764  };
1765  
1766  /**
1767   * @constructor
1768   */
1769  jasmine.MultiReporter = function() {
1770    this.subReporters_ = [];
1771  };
1772  jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
1773  
1774  jasmine.MultiReporter.prototype.addReporter = function(reporter) {
1775    this.subReporters_.push(reporter);
1776  };
1777  
1778  (function() {
1779    var functionNames = [
1780      "reportRunnerStarting",
1781      "reportRunnerResults",
1782      "reportSuiteResults",
1783      "reportSpecStarting",
1784      "reportSpecResults",
1785      "log"
1786    ];
1787    for (var i = 0; i < functionNames.length; i++) {
1788      var functionName = functionNames[i];
1789      jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
1790        return function() {
1791          for (var j = 0; j < this.subReporters_.length; j++) {
1792            var subReporter = this.subReporters_[j];
1793            if (subReporter[functionName]) {
1794              subReporter[functionName].apply(subReporter, arguments);
1795            }
1796          }
1797        };
1798      })(functionName);
1799    }
1800  })();
1801  /**
1802   * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
1803   *
1804   * @constructor
1805   */
1806  jasmine.NestedResults = function() {
1807    /**
1808     * The total count of results
1809     */
1810    this.totalCount = 0;
1811    /**
1812     * Number of passed results
1813     */
1814    this.passedCount = 0;
1815    /**
1816     * Number of failed results
1817     */
1818    this.failedCount = 0;
1819    /**
1820     * Was this suite/spec skipped?
1821     */
1822    this.skipped = false;
1823    /**
1824     * @ignore
1825     */
1826    this.items_ = [];
1827  };
1828  
1829  /**
1830   * Roll up the result counts.
1831   *
1832   * @param result
1833   */
1834  jasmine.NestedResults.prototype.rollupCounts = function(result) {
1835    this.totalCount += result.totalCount;
1836    this.passedCount += result.passedCount;
1837    this.failedCount += result.failedCount;
1838  };
1839  
1840  /**
1841   * Adds a log message.
1842   * @param values Array of message parts which will be concatenated later.
1843   */
1844  jasmine.NestedResults.prototype.log = function(values) {
1845    this.items_.push(new jasmine.MessageResult(values));
1846  };
1847  
1848  /**
1849   * Getter for the results: message & results.
1850   */
1851  jasmine.NestedResults.prototype.getItems = function() {
1852    return this.items_;
1853  };
1854  
1855  /**
1856   * Adds a result, tracking counts (total, passed, & failed)
1857   * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
1858   */
1859  jasmine.NestedResults.prototype.addResult = function(result) {
1860    if (result.type != 'log') {
1861      if (result.items_) {
1862        this.rollupCounts(result);
1863      } else {
1864        this.totalCount++;
1865        if (result.passed()) {
1866          this.passedCount++;
1867        } else {
1868          this.failedCount++;
1869        }
1870      }
1871    }
1872    this.items_.push(result);
1873  };
1874  
1875  /**
1876   * @returns {Boolean} True if <b>everything</b> below passed
1877   */
1878  jasmine.NestedResults.prototype.passed = function() {
1879    return this.passedCount === this.totalCount;
1880  };
1881  /**
1882   * Base class for pretty printing for expectation results.
1883   */
1884  jasmine.PrettyPrinter = function() {
1885    this.ppNestLevel_ = 0;
1886  };
1887  
1888  /**
1889   * Formats a value in a nice, human-readable string.
1890   *
1891   * @param value
1892   */
1893  jasmine.PrettyPrinter.prototype.format = function(value) {
1894    this.ppNestLevel_++;
1895    try {
1896      if (value === jasmine.undefined) {
1897        this.emitScalar('undefined');
1898      } else if (value === null) {
1899        this.emitScalar('null');
1900      } else if (value === jasmine.getGlobal()) {
1901        this.emitScalar('<global>');
1902      } else if (value.jasmineToString) {
1903        this.emitScalar(value.jasmineToString());
1904      } else if (typeof value === 'string') {
1905        this.emitString(value);
1906      } else if (jasmine.isSpy(value)) {
1907        this.emitScalar("spy on " + value.identity);
1908      } else if (value instanceof RegExp) {
1909        this.emitScalar(value.toString());
1910      } else if (typeof value === 'function') {
1911        this.emitScalar('Function');
1912      } else if (typeof value.nodeType === 'number') {
1913        this.emitScalar('HTMLNode');
1914      } else if (value instanceof Date) {
1915        this.emitScalar('Date(' + value + ')');
1916      } else if (value.__Jasmine_been_here_before__) {
1917        this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
1918      } else if (jasmine.isArray_(value) || typeof value == 'object') {
1919        value.__Jasmine_been_here_before__ = true;
1920        if (jasmine.isArray_(value)) {
1921          this.emitArray(value);
1922        } else {
1923          this.emitObject(value);
1924        }
1925        delete value.__Jasmine_been_here_before__;
1926      } else {
1927        this.emitScalar(value.toString());
1928      }
1929    } finally {
1930      this.ppNestLevel_--;
1931    }
1932  };
1933  
1934  jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
1935    for (var property in obj) {
1936      if (!obj.hasOwnProperty(property)) continue;
1937      if (property == '__Jasmine_been_here_before__') continue;
1938      fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
1939                                           obj.__lookupGetter__(property) !== null) : false);
1940    }
1941  };
1942  
1943  jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
1944  jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
1945  jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
1946  jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
1947  
1948  jasmine.StringPrettyPrinter = function() {
1949    jasmine.PrettyPrinter.call(this);
1950  
1951    this.string = '';
1952  };
1953  jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
1954  
1955  jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
1956    this.append(value);
1957  };
1958  
1959  jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
1960    this.append("'" + value + "'");
1961  };
1962  
1963  jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
1964    if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
1965      this.append("Array");
1966      return;
1967    }
1968  
1969    this.append('[ ');
1970    for (var i = 0; i < array.length; i++) {
1971      if (i > 0) {
1972        this.append(', ');
1973      }
1974      this.format(array[i]);
1975    }
1976    this.append(' ]');
1977  };
1978  
1979  jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
1980    if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
1981      this.append("Object");
1982      return;
1983    }
1984  
1985    var self = this;
1986    this.append('{ ');
1987    var first = true;
1988  
1989    this.iterateObject(obj, function(property, isGetter) {
1990      if (first) {
1991        first = false;
1992      } else {
1993        self.append(', ');
1994      }
1995  
1996      self.append(property);
1997      self.append(' : ');
1998      if (isGetter) {
1999        self.append('<getter>');
2000      } else {
2001        self.format(obj[property]);
2002      }
2003    });
2004  
2005    this.append(' }');
2006  };
2007  
2008  jasmine.StringPrettyPrinter.prototype.append = function(value) {
2009    this.string += value;
2010  };
2011  jasmine.Queue = function(env) {
2012    this.env = env;
2013  
2014    // parallel to blocks. each true value in this array means the block will
2015    // get executed even if we abort
2016    this.ensured = [];
2017    this.blocks = [];
2018    this.running = false;
2019    this.index = 0;
2020    this.offset = 0;
2021    this.abort = false;
2022  };
2023  
2024  jasmine.Queue.prototype.clone = function() {
2025    var queue = new jasmine.Queue(this.env);
2026    queue.ensured = this.ensured.slice(0)
2027    queue.blocks = this.blocks.slice(0)
2028    queue.running = this.running;
2029    queue.index = this.index;
2030    queue.offset = this.offset;
2031    queue.abort = this.abort;
2032    return queue;
2033  }
2034  
2035  jasmine.Queue.prototype.addBefore = function(block, ensure) {
2036    if (ensure === jasmine.undefined) {
2037      ensure = false;
2038    }
2039  
2040    this.blocks.unshift(block);
2041    this.ensured.unshift(ensure);
2042  };
2043  
2044  jasmine.Queue.prototype.add = function(block, ensure) {
2045    if (ensure === jasmine.undefined) {
2046      ensure = false;
2047    }
2048  
2049    this.blocks.push(block);
2050    this.ensured.push(ensure);
2051  };
2052  
2053  jasmine.Queue.prototype.insertNext = function(block, ensure) {
2054    if (ensure === jasmine.undefined) {
2055      ensure = false;
2056    }
2057  
2058    this.ensured.splice((this.index + this.offset + 1), 0, ensure);
2059    this.blocks.splice((this.index + this.offset + 1), 0, block);
2060    this.offset++;
2061  };
2062  
2063  jasmine.Queue.prototype.start = function(onComplete) {
2064    this.running = true;
2065    this.onComplete = onComplete;
2066    this.next_();
2067  };
2068  
2069  jasmine.Queue.prototype.isRunning = function() {
2070    return this.running;
2071  };
2072  
2073  jasmine.Queue.LOOP_DONT_RECURSE = true;
2074  
2075  jasmine.Queue.prototype.next_ = function() {
2076    var self = this;
2077    var goAgain = true;
2078  
2079    while (goAgain) {
2080      goAgain = false;
2081  
2082      if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
2083        var calledSynchronously = true;
2084        var completedSynchronously = false;
2085  
2086        var onComplete = function () {
2087          if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
2088            completedSynchronously = true;
2089            return;
2090          }
2091  
2092          if (self.blocks[self.index] && self.blocks[self.index].abort) {
2093            self.abort = true;
2094          }
2095  
2096          self.offset = 0;
2097          self.index++;
2098  
2099          var now = new Date().getTime();
2100          if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
2101            self.env.lastUpdate = now;
2102            self.env.setTimeout(function() {
2103              self.next_();
2104            }, 0);
2105          } else {
2106            if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
2107              goAgain = true;
2108            } else {
2109              self.next_();
2110            }
2111          }
2112        };
2113        self.blocks[self.index].execute(onComplete);
2114  
2115        calledSynchronously = false;
2116        if (completedSynchronously) {
2117          onComplete();
2118        }
2119  
2120      } else {
2121        self.running = false;
2122        if (self.onComplete) {
2123          self.onComplete();
2124        }
2125      }
2126    }
2127  };
2128  
2129  jasmine.Queue.prototype.results = function() {
2130    var results = new jasmine.NestedResults();
2131    for (var i = 0; i < this.blocks.length; i++) {
2132      if (this.blocks[i].results) {
2133        results.addResult(this.blocks[i].results());
2134      }
2135    }
2136    return results;
2137  };
2138  
2139  
2140  /**
2141   * Runner
2142   *
2143   * @constructor
2144   * @param {jasmine.Env} env
2145   */
2146  jasmine.Runner = function(env) {
2147    var self = this;
2148    self.env = env;
2149    self.queue = new jasmine.Queue(env);
2150    self.before_ = [];
2151    self.after_ = [];
2152    self.suites_ = [];
2153  };
2154  
2155  jasmine.Runner.prototype.execute = function() {
2156    var self = this;
2157    if (self.env.reporter.reportRunnerStarting) {
2158      self.env.reporter.reportRunnerStarting(this);
2159    }
2160    self.queue.start(function () {
2161      self.finishCallback();
2162    });
2163  };
2164  
2165  jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
2166    beforeEachFunction.typeName = 'beforeEach';
2167    this.before_.splice(0,0,beforeEachFunction);
2168  };
2169  
2170  jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
2171    afterEachFunction.typeName = 'afterEach';
2172    this.after_.splice(0,0,afterEachFunction);
2173  };
2174  
2175  
2176  jasmine.Runner.prototype.finishCallback = function() {
2177    this.env.reporter.reportRunnerResults(this);
2178  };
2179  
2180  jasmine.Runner.prototype.addSuite = function(suite) {
2181    this.suites_.push(suite);
2182  };
2183  
2184  jasmine.Runner.prototype.add = function(block) {
2185    if (block instanceof jasmine.Suite) {
2186      this.addSuite(block);
2187    }
2188    this.queue.add(block);
2189  };
2190  
2191  jasmine.Runner.prototype.specs = function () {
2192    var suites = this.suites();
2193    var specs = [];
2194    for (var i = 0; i < suites.length; i++) {
2195      specs = specs.concat(suites[i].specs());
2196    }
2197    return specs;
2198  };
2199  
2200  jasmine.Runner.prototype.suites = function() {
2201    return this.suites_;
2202  };
2203  
2204  jasmine.Runner.prototype.topLevelSuites = function() {
2205    var topLevelSuites = [];
2206    for (var i = 0; i < this.suites_.length; i++) {
2207      if (!this.suites_[i].parentSuite) {
2208        topLevelSuites.push(this.suites_[i]);
2209      }
2210    }
2211    return topLevelSuites;
2212  };
2213  
2214  jasmine.Runner.prototype.results = function() {
2215    return this.queue.results();
2216  };
2217  /**
2218   * Internal representation of a Jasmine specification, or test.
2219   *
2220   * @constructor
2221   * @param {jasmine.Env} env
2222   * @param {jasmine.Suite} suite
2223   * @param {String} description
2224   */
2225  jasmine.Spec = function(env, suite, description) {
2226    if (!env) {
2227      throw new Error('jasmine.Env() required');
2228    }
2229    if (!suite) {
2230      throw new Error('jasmine.Suite() required');
2231    }
2232    var spec = this;
2233    spec.id = env.nextSpecId ? env.nextSpecId() : null;
2234    spec.env = env;
2235    spec.suite = suite;
2236    spec.description = description;
2237    spec.queue = new jasmine.Queue(env);
2238  
2239    spec.afterCallbacks = [];
2240    spec.spies_ = [];
2241  
2242    spec.results_ = new jasmine.NestedResults();
2243    spec.results_.description = description;
2244    spec.matchersClass = null;
2245  };
2246  
2247  jasmine.Spec.prototype.getFullName = function() {
2248    return this.suite.getFullName() + ' ' + this.description + '.';
2249  };
2250  
2251  
2252  jasmine.Spec.prototype.results = function() {
2253    return this.results_;
2254  };
2255  
2256  /**
2257   * All parameters are pretty-printed and concatenated together, then written to the spec's output.
2258   *
2259   * Be careful not to leave calls to <code>jasmine.log</code> in production code.
2260   */
2261  jasmine.Spec.prototype.log = function() {
2262    return this.results_.log(arguments);
2263  };
2264  
2265  jasmine.Spec.prototype.runs = function (func) {
2266    var block = new jasmine.Block(this.env, func, this);
2267    this.addToQueue(block);
2268    return this;
2269  };
2270  
2271  jasmine.Spec.prototype.addToQueue = function (block) {
2272    if (this.queue.isRunning()) {
2273      this.queue.insertNext(block);
2274    } else {
2275      this.queue.add(block);
2276    }
2277  };
2278  
2279  /**
2280   * @param {jasmine.ExpectationResult} result
2281   */
2282  jasmine.Spec.prototype.addMatcherResult = function(result) {
2283    if (this.retries > 0 && !result.passed_) {
2284      this.retry();
2285    } else {
2286      this.results_.addResult(result);
2287    }
2288  };
2289  
2290  jasmine.Spec.prototype.expect = function(actual) {
2291    var positive = new (this.getMatchersClass_())(this.env, actual, this);
2292    positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
2293    return positive;
2294  };
2295  
2296  /**
2297   * Waits a fixed time period before moving to the next block.
2298   *
2299   * @deprecated Use waitsFor() instead
2300   * @param {Number} timeout milliseconds to wait
2301   */
2302  jasmine.Spec.prototype.waits = function(timeout) {
2303    var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
2304    this.addToQueue(waitsFunc);
2305    return this;
2306  };
2307  
2308  /**
2309   * Waits for the latchFunction to return true before proceeding to the next block.
2310   *
2311   * @param {Function} latchFunction
2312   * @param {String} optional_timeoutMessage
2313   * @param {Number} optional_timeout
2314   */
2315  jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
2316    var latchFunction_ = null;
2317    var optional_timeoutMessage_ = null;
2318    var optional_timeout_ = null;
2319  
2320    for (var i = 0; i < arguments.length; i++) {
2321      var arg = arguments[i];
2322      switch (typeof arg) {
2323        case 'function':
2324          latchFunction_ = arg;
2325          break;
2326        case 'string':
2327          optional_timeoutMessage_ = arg;
2328          break;
2329        case 'number':
2330          optional_timeout_ = arg;
2331          break;
2332      }
2333    }
2334  
2335    if (optional_timeoutMessage_ == null) {
2336      const objectToCaptureStack = {}
2337      Error.captureStackTrace(objectToCaptureStack, waitsFor)
2338      const stack = objectToCaptureStack.stack
2339      const line = stack.split('\n')[1]
2340      optional_timeoutMessage_ = `condition ${line}`
2341    }
2342  
2343    var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
2344    this.addToQueue(waitsForFunc);
2345    return this;
2346  };
2347  
2348  jasmine.Spec.prototype.fail = function (e, onComplete) {
2349    if (this.retries > 0) {
2350      this.retry()
2351    } else {
2352      var expectationResult = new jasmine.ExpectationResult({
2353        passed: false,
2354        message: e ? jasmine.util.formatException(e) : 'Exception',
2355        trace: { stack: e.stack }
2356      });
2357      this.results_.addResult(expectationResult);
2358    }
2359  };
2360  
2361  jasmine.Spec.prototype.getMatchersClass_ = function() {
2362    return this.matchersClass || this.env.matchersClass;
2363  };
2364  
2365  jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
2366    var parent = this.getMatchersClass_();
2367    var newMatchersClass = function() {
2368      parent.apply(this, arguments);
2369    };
2370    jasmine.util.inherit(newMatchersClass, parent);
2371    jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
2372    this.matchersClass = newMatchersClass;
2373  };
2374  
2375  jasmine.Spec.prototype.finishCallback = function() {
2376    this.env.reporter.reportSpecResults(this);
2377  };
2378  
2379  jasmine.Spec.prototype.finish = function(onComplete) {
2380    this.removeAllSpies();
2381    this.finishCallback();
2382    if (onComplete) {
2383      onComplete();
2384    }
2385  };
2386  
2387  jasmine.Spec.prototype.after = function(doAfter) {
2388    if (this.queue.isRunning()) {
2389      this.queue.add(new jasmine.Block(this.env, doAfter, this), true);
2390    } else {
2391      this.afterCallbacks.unshift(doAfter);
2392    }
2393  };
2394  
2395  jasmine.Spec.prototype.execute = function(onComplete) {
2396    var spec = this;
2397    if (!spec.env.specFilter(spec)) {
2398      spec.results_.skipped = true;
2399      spec.finish(onComplete);
2400      return;
2401    }
2402  
2403    this.env.reporter.reportSpecStarting(this);
2404  
2405    spec.env.currentSpec = spec;
2406  
2407    spec.addBeforesAndAftersToQueue();
2408  
2409    spec.queue.start(function () {
2410      spec.finish(onComplete);
2411    });
2412  };
2413  
2414  jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
2415    var runner = this.env.currentRunner();
2416    var i;
2417  
2418    for (var suite = this.suite; suite; suite = suite.parentSuite) {
2419      for (i = 0; i < suite.before_.length; i++) {
2420        this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
2421      }
2422    }
2423    for (i = 0; i < runner.before_.length; i++) {
2424      this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
2425    }
2426    for (i = 0; i < this.afterCallbacks.length; i++) {
2427      this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true);
2428    }
2429    for (suite = this.suite; suite; suite = suite.parentSuite) {
2430      for (i = 0; i < suite.after_.length; i++) {
2431        this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true);
2432      }
2433    }
2434    for (i = 0; i < runner.after_.length; i++) {
2435      this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true);
2436    }
2437  };
2438  
2439  jasmine.Spec.prototype.explodes = function() {
2440    throw 'explodes function should not have been called';
2441  };
2442  
2443  jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
2444    if (obj == jasmine.undefined) {
2445      throw "spyOn could not find an object to spy upon for " + methodName + "()";
2446    }
2447  
2448    if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
2449      throw methodName + '() method does not exist';
2450    }
2451  
2452    if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
2453      throw new Error(methodName + ' has already been spied upon');
2454    }
2455  
2456    var spyObj = jasmine.createSpy(methodName);
2457  
2458    this.spies_.push(spyObj);
2459    spyObj.baseObj = obj;
2460    spyObj.methodName = methodName;
2461    spyObj.originalValue = obj[methodName];
2462  
2463    obj[methodName] = spyObj;
2464  
2465    return spyObj;
2466  };
2467  
2468  jasmine.Spec.prototype.removeAllSpies = function() {
2469    for (var i = 0; i < this.spies_.length; i++) {
2470      var spy = this.spies_[i];
2471      spy.baseObj[spy.methodName] = spy.originalValue;
2472    }
2473    this.spies_ = [];
2474  };
2475  
2476  jasmine.Spec.prototype.RETRY_FLAKY_TEST_AND_SLOW_DOWN_THE_BUILD = function() {
2477    if (this.retries == null) {
2478      this.retries = 5;
2479      this.originalQueue = this.queue.clone();
2480    }
2481  }
2482  
2483  jasmine.Spec.prototype.retry = function() {
2484    this.retries--;
2485    this.queue = this.originalQueue.clone();
2486    this.suite.queue.insertNext(this)
2487  }
2488  
2489  /**
2490   * Internal representation of a Jasmine suite.
2491   *
2492   * @constructor
2493   * @param {jasmine.Env} env
2494   * @param {String} description
2495   * @param {Function} specDefinitions
2496   * @param {jasmine.Suite} parentSuite
2497   */
2498  jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
2499    var self = this;
2500    self.id = env.nextSuiteId ? env.nextSuiteId() : null;
2501    self.description = description;
2502    self.queue = new jasmine.Queue(env);
2503    self.parentSuite = parentSuite;
2504    self.env = env;
2505    self.before_ = [];
2506    self.after_ = [];
2507    self.children_ = [];
2508    self.suites_ = [];
2509    self.specs_ = [];
2510  };
2511  
2512  jasmine.Suite.prototype.getFullName = function() {
2513    var fullName = this.description;
2514    for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
2515      fullName = parentSuite.description + ' ' + fullName;
2516    }
2517    return fullName;
2518  };
2519  
2520  jasmine.Suite.prototype.finish = function(onComplete) {
2521    this.env.reporter.reportSuiteResults(this);
2522    this.finished = true;
2523    if (typeof(onComplete) == 'function') {
2524      onComplete();
2525    }
2526  };
2527  
2528  jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
2529    beforeEachFunction.typeName = 'beforeEach';
2530    this.before_.unshift(beforeEachFunction);
2531  };
2532  
2533  jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
2534    afterEachFunction.typeName = 'afterEach';
2535    this.after_.unshift(afterEachFunction);
2536  };
2537  
2538  jasmine.Suite.prototype.results = function() {
2539    return this.queue.results();
2540  };
2541  
2542  jasmine.Suite.prototype.add = function(suiteOrSpec) {
2543    this.children_.push(suiteOrSpec);
2544    if (suiteOrSpec instanceof jasmine.Suite) {
2545      this.suites_.push(suiteOrSpec);
2546      this.env.currentRunner().addSuite(suiteOrSpec);
2547    } else {
2548      this.specs_.push(suiteOrSpec);
2549    }
2550    this.queue.add(suiteOrSpec);
2551  };
2552  
2553  jasmine.Suite.prototype.specs = function() {
2554    return this.specs_;
2555  };
2556  
2557  jasmine.Suite.prototype.suites = function() {
2558    return this.suites_;
2559  };
2560  
2561  jasmine.Suite.prototype.children = function() {
2562    return this.children_;
2563  };
2564  
2565  jasmine.Suite.prototype.execute = function(onComplete) {
2566    var self = this;
2567    this.queue.start(function () {
2568      self.finish(onComplete);
2569    });
2570  };
2571  jasmine.WaitsBlock = function(env, timeout, spec) {
2572    this.timeout = timeout;
2573    jasmine.Block.call(this, env, null, spec);
2574  };
2575  
2576  jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
2577  
2578  jasmine.WaitsBlock.prototype.execute = function (onComplete) {
2579    if (jasmine.VERBOSE) {
2580      this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
2581    }
2582    this.env.setTimeout(function () {
2583      onComplete();
2584    }, this.timeout);
2585  };
2586  /**
2587   * A block which waits for some condition to become true, with timeout.
2588   *
2589   * @constructor
2590   * @extends jasmine.Block
2591   * @param {jasmine.Env} env The Jasmine environment.
2592   * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
2593   * @param {Function} latchFunction A function which returns true when the desired condition has been met.
2594   * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
2595   * @param {jasmine.Spec} spec The Jasmine spec.
2596   */
2597  jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
2598    this.timeout = timeout || env.defaultTimeoutInterval;
2599    this.latchFunction = latchFunction;
2600    this.message = message;
2601    this.totalTimeSpentWaitingForLatch = 0;
2602    jasmine.Block.call(this, env, null, spec);
2603  };
2604  jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
2605  
2606  jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
2607  
2608  jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
2609    if (jasmine.VERBOSE) {
2610      this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
2611    }
2612  
2613    if (this.latchFunction.length > 0) { this.waitForExplicitCompletion(onComplete); return; }
2614  
2615    var latchFunctionResult;
2616    try {
2617      latchFunctionResult = this.latchFunction.apply(this.spec);
2618    } catch (e) {
2619      this.spec.fail(e);
2620      onComplete();
2621      return;
2622    }
2623  
2624    if (latchFunctionResult) {
2625      onComplete();
2626    } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
2627      var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
2628      this.spec.fail({
2629        name: 'timeout',
2630        message: message
2631      });
2632  
2633      this.abort = true;
2634      onComplete();
2635    } else {
2636      this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
2637      var self = this;
2638      this.env.setTimeout(function() {
2639        self.execute(onComplete);
2640      }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
2641    }
2642  };
2643  
2644  jasmine.WaitsForBlock.prototype.waitForExplicitCompletion = function(onComplete) {
2645    var self = this;
2646    var timeoutHandle = this.env.setTimeout(function() {
2647      var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.message || 'something to happen');
2648      self.spec.fail({
2649        name: 'timeout',
2650        message: message
2651      });
2652      multiCompletion.cancelled = true;
2653      self.abort = true;
2654      onComplete();
2655    }, this.timeout);
2656  
2657    var multiCompletion = new jasmine.WaitsForBlock.MultiCompletion(this.latchFunction.length, this.env, onComplete, timeoutHandle);
2658  
2659    try {
2660      this.latchFunction.apply(this.spec, multiCompletion.completionFunctions);
2661    } catch (e) {
2662      this.spec.fail(e);
2663      onComplete();
2664      return;
2665    }
2666  };
2667  
2668  jasmine.WaitsForBlock.MultiCompletion = function(count, env, onComplete, timeoutHandle) {
2669    this.count = count;
2670    this.env = env;
2671    this.onComplete = onComplete;
2672    this.timeoutHandle = timeoutHandle;
2673    this.completionStatuses = [];
2674    this.completionFunctions = [];
2675  
2676    for (var i = 0; i < count; i++) {
2677      this.completionStatuses.push(false);
2678      this.completionFunctions.push(this.buildCompletionFunction(i));
2679    }
2680  };
2681  
2682  jasmine.WaitsForBlock.MultiCompletion.prototype.attemptCompletion = function() {
2683    if (this.cancelled) return;
2684    for (var j = 0; j < this.count; j++) {
2685      if (!this.completionStatuses[j]) return;
2686    }
2687    this.env.clearTimeout(this.timeoutHandle);
2688    this.onComplete();
2689  };
2690  
2691  jasmine.WaitsForBlock.MultiCompletion.prototype.buildCompletionFunction = function(i) {
2692    var self = this;
2693    var spent = false;
2694    return function() {
2695      if (spent) return;
2696      spent = true;
2697      self.completionStatuses[i] = true;
2698      self.attemptCompletion();
2699    };
2700  };
2701  
2702  jasmine.version_= {
2703    "major": 1,
2704    "minor": 3,
2705    "build": 1,
2706    "revision": 1354556913
2707  };