arnaucube
arnaucube/raspberryGPIOhtmlserverPublic Self-hosted repository
raspberryGPIOhtmlserver/node_modules/benchmark/test/test.js
node_modules/benchmark/test/test.jsRaw
   1;(function(window, undefined) {
   2  'use strict';
   3
   4  /** Use a single load function */
   5  var load = typeof require == 'function' ? require : window.load;
   6
   7  /** The `platform` object to check */
   8  var platform =
   9    window.platform ||
  10    load('../vendor/platform.js/platform.js') ||
  11    window.platform;
  12
  13  /** The unit testing framework */
  14  var QUnit =
  15    window.QUnit || (
  16      window.setTimeout || (window.addEventListener = window.setTimeout = / /),
  17      window.QUnit = load('../vendor/qunit/qunit/qunit' + (platform.name == 'Narwhal' ? '-1.8.0' : '') + '.js') || window.QUnit,
  18      load('../vendor/qunit-clib/qunit-clib.js'),
  19      (window.addEventListener || 0).test && delete window.addEventListener,
  20      window.QUnit
  21    );
  22
  23  /** The `Benchmark` constructor to test */
  24  var Benchmark =
  25    window.Benchmark || (
  26      Benchmark = load('../benchmark.js') || window.Benchmark,
  27      Benchmark.Benchmark || Benchmark
  28    );
  29
  30  /** API shortcut */
  31  var forOwn = Benchmark.forOwn;
  32
  33  /** Used to get property descriptors */
  34  var getDescriptor = Object.getOwnPropertyDescriptor;
  35
  36  /** Used to set property descriptors */
  37  var setDescriptor = Object.defineProperty;
  38
  39  /** Shortcut used to convert array-like objects to arrays */
  40  var slice = [].slice;
  41
  42  /** Used to resolve a value's internal [[Class]] */
  43  var toString = {}.toString;
  44
  45  /** Used to check problem JScript properties (a.k.a. the [[DontEnum]] bug) */
  46  var shadowed = {
  47    'constructor': 1,
  48    'hasOwnProperty': 2,
  49    'isPrototypeOf': 3,
  50    'propertyIsEnumerable': 4,
  51    'toLocaleString': 5,
  52    'toString': 6,
  53    'valueOf': 7
  54  };
  55
  56  /** Used to flag environments/features */
  57  var support = {
  58    'descriptors': !!function() {
  59      try {
  60        var o = {};
  61        return (setDescriptor(o, o, o), 'value' in getDescriptor(o, o));
  62      } catch(e) { }
  63    }()
  64  };
  65
  66  /*--------------------------------------------------------------------------*/
  67
  68  /**
  69   * Skips a given number of tests with a passing result.
  70   *
  71   * @private
  72   * @param {Number} [count=1] The number of tests to skip.
  73   */
  74  function skipTest(count) {
  75    count || (count = 1);
  76    while (count--) {
  77      ok(true, 'test skipped');
  78    }
  79  }
  80
  81  /*--------------------------------------------------------------------------*/
  82
  83  // init Benchmark.options.minTime
  84  Benchmark(function() { throw 0; }).run();
  85
  86  // set a shorter max time
  87  Benchmark.options.maxTime = Benchmark.options.minTime * 5;
  88
  89  // explicitly call `QUnit.module()` instead of `module()`
  90  // in case we are in a CLI environment
  91  QUnit.module('Benchmark');
  92
  93  (function() {
  94    test('has the default `Benchmark.platform` value', function() {
  95      if (window.document) {
  96        equal(String(Benchmark.platform), navigator.userAgent);
  97      } else {
  98        skipTest(1)
  99      }
 100    });
 101
 102    test('supports loading Benchmark.js as a module', function() {
 103      if (window.document && window.require) {
 104        equal((Benchmark2 || {}).version, Benchmark.version);
 105      } else {
 106        skipTest(1)
 107      }
 108    });
 109
 110    test('supports loading Platform.js as a module', function() {
 111      if (window.document && window.require) {
 112        var platform = (Benchmark2 || {}).platform || {};
 113        equal(typeof platform.name, 'string');
 114      } else {
 115        skipTest(1)
 116      }
 117    });
 118  }());
 119
 120  /*--------------------------------------------------------------------------*/
 121
 122  QUnit.module('Benchmark constructor');
 123
 124  (function() {
 125    test('creates a new instance when called without the `new` operator', function() {
 126      ok(Benchmark() instanceof Benchmark);
 127    });
 128
 129    test('supports passing an options object', function() {
 130      var bench = Benchmark({ 'name': 'foo', 'fn': function() { } });
 131      ok(bench.fn && bench.name == 'foo');
 132    });
 133
 134    test('supports passing a "name" and "fn" argument', function() {
 135      var bench = Benchmark('foo', function() { });
 136      ok(bench.fn && bench.name == 'foo');
 137    });
 138
 139    test('supports passing a "name" argument and an options object', function() {
 140      var bench = Benchmark('foo', { 'fn': function() { } });
 141      ok(bench.fn && bench.name == 'foo');
 142    });
 143
 144    test('supports passing a "name" argument and an options object', function() {
 145      var bench = Benchmark('foo', function() { }, { 'id': 'bar' });
 146      ok(bench.fn && bench.name == 'foo' && bench.id == 'bar');
 147    });
 148
 149    test('supports passing an empy string for the "fn" options property', function() {
 150      var bench = Benchmark({ 'fn': '' }).run();
 151      ok(!bench.error);
 152    });
 153
 154    test('detects dead code', function() {
 155      var bench = Benchmark(function() { }).run();
 156      ok(/setup\(\)/.test(bench.compiled) ? !bench.error : bench.error);
 157    });
 158  }());
 159
 160  /*--------------------------------------------------------------------------*/
 161
 162  QUnit.module('Benchmark compilation');
 163
 164  (function() {
 165    test('compiles using the default `Function#toString`', function() {
 166      var bench = Benchmark({
 167        'setup': function() { var a = 1; },
 168        'fn': function() { throw a; },
 169        'teardown': function() { a = 2; }
 170      }).run();
 171
 172      var compiled = bench.compiled;
 173      if (/setup\(\)/.test(compiled)) {
 174        skipTest();
 175      }
 176      else {
 177        ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled));
 178      }
 179    });
 180
 181    test('compiles using a custom "toString" method', function() {
 182      var bench = Benchmark({
 183        'setup': function() { },
 184        'fn': function() { },
 185        'teardown': function() { }
 186      });
 187
 188      bench.setup.toString = function() { return 'var a = 1;' };
 189      bench.fn.toString = function() { return 'throw a;' };
 190      bench.teardown.toString = function() { return 'a = 2;' };
 191      bench.run();
 192
 193      var compiled = bench.compiled;
 194      if (/setup\(\)/.test(compiled)) {
 195        skipTest();
 196      }
 197      else {
 198        ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled));
 199      }
 200    });
 201
 202    test('compiles using a string value', function() {
 203      var bench = Benchmark({
 204        'setup': 'var a = 1;',
 205        'fn': 'throw a;',
 206        'teardown': 'a = 2;'
 207      }).run();
 208
 209      var compiled = bench.compiled;
 210      if (/setup\(\)/.test(compiled)) {
 211        skipTest();
 212      }
 213      else {
 214        ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled));
 215      }
 216    });
 217  }());
 218
 219  /*--------------------------------------------------------------------------*/
 220
 221  QUnit.module('Benchmark test binding');
 222
 223  (function() {
 224    var count = 0;
 225
 226    var tests = {
 227      'inlined "setup", "fn", and "teardown"': (
 228        'if(/ops/.test(this))this._fn=true;'
 229      ),
 230      'called "fn" and inlined "setup"/"teardown" reached by error': function() {
 231        count++;
 232        if (/ops/.test(this)) {
 233          this._fn = true;
 234        }
 235      },
 236      'called "fn" and inlined "setup"/"teardown" reached by `return` statement': function() {
 237        if (/ops/.test(this)) {
 238          this._fn = true;
 239        }
 240        return;
 241      }
 242    };
 243
 244    forOwn(tests, function(fn, title) {
 245      test('has correct binding for ' + title, function() {
 246        var bench = Benchmark({
 247          'setup': 'if(/ops/.test(this))this._setup=true;',
 248          'fn': fn,
 249          'teardown': 'if(/ops/.test(this))this._teardown=true;',
 250          'onCycle': function() { this.abort(); }
 251        }).run();
 252
 253        var compiled = bench.compiled;
 254        if (/setup\(\)/.test(compiled)) {
 255          skipTest(3);
 256        }
 257        else {
 258          ok(bench._setup, 'correct binding for "setup"');
 259          ok(bench._fn, 'correct binding for "fn"');
 260          ok(bench._teardown, 'correct binding for "teardown"');
 261        }
 262      });
 263    });
 264  }());
 265
 266  /*--------------------------------------------------------------------------*/
 267
 268  QUnit.module('Benchmark.deepClone');
 269
 270  (function() {
 271    function createCircularObject() {
 272      var result = {
 273        'foo': { 'b': { 'foo': { 'c': { } } } },
 274        'bar': { }
 275      };
 276
 277      result.foo.b.foo.c.foo = result;
 278      result.bar.b = result.foo.b;
 279      return result;
 280    }
 281
 282    function Klass() {
 283      this.a = 1;
 284    }
 285
 286    Klass.prototype = { 'b': 1 };
 287
 288    var notCloneable = {
 289      'an arguments object': arguments,
 290      'an element': window.document && document.body,
 291      'a function': Klass,
 292      'a Klass instance': new Klass
 293    };
 294
 295    var objects = {
 296      'an array': ['a', 'b', 'c', ''],
 297      'an array-like-object': { '0': 'a', '1': 'b', '2': 'c',  '3': '', 'length': 5 },
 298      'boolean': false,
 299      'boolean object': Object(false),
 300      'an object': { 'a': 0, 'b': 1, 'c': 3 },
 301      'an object with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } },
 302      'null': null,
 303      'a number': 3,
 304      'a number object': Object(3),
 305      'a regexp': /x/gim,
 306      'a string': 'x',
 307      'a string object': Object('x'),
 308      'undefined': undefined
 309    };
 310
 311    objects['an array'].length = 5;
 312
 313    forOwn(objects, function(object, key) {
 314      test('clones ' + key + ' correctly', function() {
 315        var kind = toString.call(object),
 316            clone = Benchmark.deepClone(object);
 317
 318        if (object == null) {
 319          equal(clone, object);
 320        } else {
 321          deepEqual(clone.valueOf(), object.valueOf());
 322        }
 323        if (object === Object(object)) {
 324          ok(clone !== object);
 325        } else {
 326          skipTest();
 327        }
 328      });
 329    });
 330
 331    forOwn(notCloneable, function(object, key) {
 332      test('does not clone ' + key, function() {
 333        ok(Benchmark.deepClone(object) === object);
 334      });
 335    });
 336
 337    test('clones using Klass#deepClone', function() {
 338      var object = new Klass;
 339      Klass.prototype.deepClone = function() { return new Klass; };
 340
 341      var clone = Benchmark.deepClone(object);
 342      ok(clone !== object && clone instanceof Klass);
 343
 344      delete Klass.prototype.clone;
 345    });
 346
 347    test('clones problem JScript properties', function() {
 348      var clone = Benchmark.deepClone(shadowed);
 349      deepEqual(clone, shadowed);
 350    });
 351
 352    test('clones string object with custom property', function() {
 353      var object = new String('x');
 354      object.x = 1;
 355
 356      var clone = Benchmark.deepClone(object);
 357      ok(clone == 'x' && typeof clone == 'object' && clone.x === 1 && toString.call(clone) == '[object String]');
 358    });
 359
 360    test('clones objects with circular references', function() {
 361      var object = createCircularObject(),
 362          clone = Benchmark.deepClone(object);
 363
 364      ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object);
 365    });
 366
 367    test('clones non-extensible objects with circular references', function() {
 368      if (Object.preventExtensions) {
 369        var object = Object.preventExtensions(createCircularObject());
 370        Object.preventExtensions(object.bar.b);
 371
 372        var clone = Benchmark.deepClone(object);
 373        ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object);
 374      } else {
 375        skipTest(1)
 376      }
 377    });
 378
 379    test('clones sealed objects with circular references', function() {
 380      if (Object.seal) {
 381        var object = Object.seal(createCircularObject());
 382        Object.seal(object.bar.b);
 383
 384        var clone = Benchmark.deepClone(object);
 385        ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object);
 386      } else {
 387        skipTest(1)
 388      }
 389    });
 390
 391    test('clones frozen objects with circular references', function() {
 392      if (Object.freeze) {
 393        var object = Object.freeze(createCircularObject());
 394        Object.freeze(object.bar.b);
 395
 396        var clone = Benchmark.deepClone(object);
 397        ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object);
 398      } else {
 399        skipTest(1)
 400      }
 401    });
 402
 403    test('clones objects with custom descriptors and circular references', function() {
 404      var accessor,
 405          descriptor;
 406
 407      if (support.descriptors) {
 408        var object = setDescriptor({}, 'foo', {
 409          'configurable': true,
 410          'value': setDescriptor({}, 'b', {
 411            'writable': true,
 412            'value': setDescriptor({}, 'foo', {
 413              'get': function() { return accessor; },
 414              'set': function(value) { accessor = value; }
 415            })
 416          })
 417        });
 418
 419        setDescriptor(object, 'bar', { 'value': {} });
 420        object.foo.b.foo = { 'c': object };
 421        object.bar.b = object.foo.b;
 422
 423        var clone = Benchmark.deepClone(object);
 424        ok(clone !== object &&
 425          clone.bar.b === clone.foo.b &&
 426          clone !== clone.foo.b.foo.c.foo &&
 427          (descriptor = getDescriptor(clone, 'foo')) &&
 428          descriptor.configurable && !(descriptor.enumerable && descriptor.writable) &&
 429          (descriptor = getDescriptor(clone.foo, 'b')) &&
 430          descriptor.writable && !(descriptor.configurable && descriptor.enumerable) &&
 431          (descriptor = getDescriptor(clone.foo.b, 'foo')) &&
 432          descriptor.get && descriptor.set &&
 433          (descriptor = getDescriptor(clone.foo.b, 'foo')) &&
 434          !(descriptor.configurable && descriptor.enumerable && descriptor.writable) &&
 435          (descriptor = getDescriptor(clone, 'bar')) &&
 436          !(descriptor.configurable && descriptor.enumerable && descriptor.writable));
 437      }
 438      else {
 439        skipTest(1)
 440      }
 441    });
 442  }());
 443
 444  /*--------------------------------------------------------------------------*/
 445
 446  QUnit.module('Benchmark.each');
 447
 448  (function() {
 449    var xpathResult;
 450
 451    var objects = {
 452      'array': ['a', 'b', 'c', ''],
 453      'array-like-object': { '0': 'a', '1': 'b', '2': 'c',  '3': '', 'length': 5 },
 454      'xpath snapshot': null
 455    };
 456
 457    if (window.document && document.evaluate) {
 458      xpathResult = [document.documentElement, document.getElementsByTagName('head')[0], document.body];
 459      objects['xpath snapshot'] = document.evaluate('//*[self::html or self::head or self::body]', document, null, 7, null);
 460    }
 461
 462    objects.array.length = 5;
 463
 464    forOwn(objects, function(object, key) {
 465      test('passes the correct arguments when passing an ' + key, function() {
 466        if (object) {
 467          var args
 468          Benchmark.each(object, function() {
 469            args || (args = slice.call(arguments));
 470          });
 471
 472          if (key == 'xpath snapshot') {
 473            ok(args[0] === xpathResult[0]);
 474          } else {
 475            equal(args[0], 'a');
 476          }
 477          equal(args[1], 0);
 478          ok(args[2] === object);
 479        }
 480        else {
 481          skipTest(3);
 482        }
 483      });
 484
 485      test('returns the passed object when passing an ' + key, function() {
 486        if (object) {
 487          var actual = Benchmark.each(object, function() { });
 488          ok(actual === object);
 489        }
 490        else {
 491          skipTest();
 492        }
 493      });
 494
 495      test('iterates over all indexes when passing an ' + key, function() {
 496        if (object) {
 497          var values = [];
 498          Benchmark.each(object, function(value) {
 499            values.push(value);
 500          });
 501
 502          deepEqual(values, key == 'xpath snapshot' ? xpathResult : ['a', 'b', 'c', '']);
 503        }
 504        else {
 505          skipTest();
 506        }
 507      });
 508
 509      test('exits early when returning `false` when passing an ' + key, function() {
 510        if (object) {
 511          var values = [];
 512          Benchmark.each(object, function(value) {
 513            values.push(value);
 514            return values.length < 2;
 515          });
 516
 517          deepEqual(values, key == 'xpath snapshot' ? xpathResult.slice(0, 2) : ['a', 'b']);
 518        }
 519        else {
 520          skipTest();
 521        }
 522      });
 523    });
 524
 525    test('passes the third callback argument as an object', function() {
 526      var thirdArg;
 527      Benchmark.each('hello', function(value, index, object) {
 528        thirdArg = object;
 529      });
 530
 531      ok(thirdArg && typeof thirdArg == 'object');
 532    });
 533
 534    test('iterates over strings by index', function() {
 535      var values = [];
 536      Benchmark.each('hello', function(value) {
 537        values.push(value)
 538      });
 539
 540      deepEqual(values, ['h', 'e', 'l', 'l', 'o']);
 541    });
 542  }());
 543
 544  /*--------------------------------------------------------------------------*/
 545
 546  QUnit.module('Benchmark.extend');
 547
 548  (function() {
 549    test('allows no source argument', function() {
 550      var object = {};
 551      equal(Benchmark.extend(object), object);
 552    });
 553
 554    test('allows a single source argument', function() {
 555      var source = { 'x': 1, 'y': 1 },
 556          actual = Benchmark.extend({}, source);
 557
 558      deepEqual(Benchmark.extend({}, source), { 'x': 1, 'y': 1 });
 559    });
 560
 561    test('allows multiple source arguments', function() {
 562      var source1 = { 'x': 1, 'y': 1 },
 563          source2 = { 'y': 2, 'z': 2 },
 564          actual = Benchmark.extend({}, source1, source2);
 565
 566      deepEqual(actual, { 'x': 1, 'y': 2, 'z': 2 });
 567    });
 568
 569    test('will add inherited source properties', function() {
 570      function Source() { }
 571      Source.prototype.x = 1;
 572      deepEqual(Benchmark.extend({}, new Source), { 'x': 1 });
 573    });
 574
 575    test('will add problem JScript properties', function() {
 576      deepEqual(Benchmark.extend({}, shadowed), shadowed);
 577    });
 578  }());
 579
 580  /*--------------------------------------------------------------------------*/
 581
 582  QUnit.module('Benchmark.filter');
 583
 584  (function() {
 585    var objects = {
 586      'array': ['a', 'b', 'c', ''],
 587      'array-like-object': { '0': 'a', '1': 'b', '2': 'c',  '3': '', 'length': 5 }
 588    };
 589
 590    objects.array.length = 5;
 591
 592    forOwn(objects, function(object, key) {
 593      test('passes the correct arguments when passing an ' + key, function() {
 594        var args;
 595        Benchmark.filter(object, function() {
 596          args || (args = slice.call(arguments));
 597        });
 598
 599        deepEqual(args, ['a', 0, object]);
 600      });
 601
 602      test('produces the correct result when passing an ' + key, function() {
 603        var actual = Benchmark.filter(object, function(value, index) {
 604          return index > 0;
 605        });
 606
 607        deepEqual(actual, ['b', 'c', '']);
 608      });
 609
 610      test('iterates over sparse ' + key + 's correctly', function() {
 611        var actual = Benchmark.filter(object, function(value) {
 612          return value === undefined;
 613        });
 614
 615        deepEqual(actual, []);
 616      });
 617    });
 618  }());
 619
 620  /*--------------------------------------------------------------------------*/
 621
 622  QUnit.module('Benchmark.forOwn');
 623
 624  (function() {
 625    function fn() {
 626      // no-op
 627    }
 628
 629    function KlassA() {
 630      this.a = 1;
 631      this.b = 2;
 632      this.c = 3;
 633    }
 634
 635    function KlassB() {
 636      this.a = 1;
 637      this.constructor = 2;
 638      this.hasOwnProperty = 3;
 639      this.isPrototypeOf = 4;
 640      this.propertyIsEnumerable = 5;
 641      this.toLocaleString = 6;
 642      this.toString = 7;
 643      this.valueOf = 8;
 644    }
 645
 646    function KlassC() {
 647      // no-op
 648    }
 649
 650    fn.a = 1;
 651    fn.b = 2;
 652    fn.c = 3;
 653
 654    KlassC.prototype.a = 1;
 655    KlassC.prototype.b = 2;
 656    KlassC.prototype.c = 3;
 657
 658    var objects = {
 659      'an arguments object': arguments,
 660      'a function': fn,
 661      'an object': new KlassA,
 662      'an object shadowing properties on Object.prototype': new KlassB,
 663      'a prototype object': KlassC.prototype,
 664      'a string': 'abc'
 665    };
 666
 667    forOwn(objects, function(object, key) {
 668      test('passes the correct arguments when passing ' + key, function() {
 669        var args;
 670        Benchmark.forOwn(object, function() {
 671          args || (args = slice.call(arguments));
 672        });
 673
 674        equal(typeof args[0], key == 'a string' ? 'string' : 'number');
 675        equal(typeof args[1], 'string');
 676        equal(args[2] && typeof args[2], key == 'a function' ? 'function' : 'object');
 677      });
 678
 679      test('returns the passed object when passing ' + key, function() {
 680        var actual = Benchmark.forOwn(object, function() { });
 681        deepEqual(actual, object);
 682      });
 683
 684      test('iterates over own properties when passing ' + key, function() {
 685        var values = [];
 686        Benchmark.forOwn(object, function(value) {
 687          values.push(value);
 688        });
 689
 690        if (object instanceof KlassB) {
 691          deepEqual(values.sort(), [1, 2, 3, 4, 5, 6, 7, 8]);
 692        } else if (key == 'a string') {
 693          deepEqual(values, ['a', 'b', 'c']);
 694        } else {
 695          deepEqual(values.sort(), [1, 2, 3]);
 696        }
 697      });
 698
 699      test('exits early when returning `false` when passing ' + key, function() {
 700        var values = [];
 701        Benchmark.forOwn(object, function(value) {
 702          values.push(value);
 703          return false;
 704        });
 705
 706        equal(values.length, 1);
 707      });
 708
 709      if (object instanceof KlassB) {
 710        test('exits correctly when transitioning to the JScript [[DontEnum]] fix', function() {
 711          var values = [];
 712          Benchmark.forOwn(object, function(value) {
 713            values.push(value);
 714            return values.length < 2;
 715          });
 716
 717          equal(values.length, 2);
 718        });
 719      }
 720    });
 721  }(1, 2, 3));
 722
 723  /*--------------------------------------------------------------------------*/
 724
 725  QUnit.module('Benchmark.formatNumber');
 726
 727  (function() {
 728    test('formats a million correctly', function() {
 729      equal(Benchmark.formatNumber(1e6), '1,000,000');
 730    });
 731
 732    test('formats less than 100 correctly', function() {
 733      equal(Benchmark.formatNumber(23), '23');
 734    });
 735
 736    test('formats numbers with decimal values correctly', function() {
 737      equal(Benchmark.formatNumber(1234.56), '1,234.56');
 738    });
 739
 740    test('formats negative numbers correctly', function() {
 741      equal(Benchmark.formatNumber(-1234.56), '-1,234.56');
 742    });
 743  }());
 744
 745  /*--------------------------------------------------------------------------*/
 746
 747  QUnit.module('Benchmark.hasKey');
 748
 749  (function() {
 750    test('returns `true` for own properties', function() {
 751      var object = { 'x': 1 };
 752      equal(Benchmark.hasKey(object, 'x'), true);
 753    });
 754
 755    test('returns `false` for inherited properties', function() {
 756      equal(Benchmark.hasKey({}, 'toString'), false);
 757    });
 758
 759    test('doesn\'t use an object\'s `hasOwnProperty` method', function() {
 760      var object = { 'hasOwnProperty': function() { return true; } };
 761      equal(Benchmark.hasKey(object, 'x'), false);
 762    });
 763  }());
 764
 765  /*--------------------------------------------------------------------------*/
 766
 767  QUnit.module('Benchmark.indexOf');
 768
 769  (function() {
 770    var objects = {
 771      'array': ['a', 'b', 'c', ''],
 772      'array-like-object': { '0': 'a', '1': 'b', '2': 'c',  '3': '', 'length': 5 }
 773    };
 774
 775    objects.array.length = 5;
 776
 777    forOwn(objects, function(object, key) {
 778      test('produces the correct result when passing an ' + key, function() {
 779        equal(Benchmark.indexOf(object, 'b'), 1);
 780      });
 781
 782      test('matches values by strict equality when passing an ' + key, function() {
 783        equal(Benchmark.indexOf(object, new String('b')), -1);
 784      });
 785
 786      test('iterates over sparse ' + key + 's correctly', function() {
 787        equal(Benchmark.indexOf(object, undefined), -1);
 788      });
 789    });
 790
 791    test('searches from the given `fromIndex`', function() {
 792      var array = ['a', 'b', 'c', 'a'];
 793      equal(Benchmark.indexOf(array, 'a', 1), 3);
 794    });
 795
 796    test('handles extreme negative `fromIndex` values correctly', function() {
 797      var array = ['a'];
 798      array['-1'] = 'z';
 799      equal(Benchmark.indexOf(array, 'z', -2), -1);
 800    });
 801
 802    test('handles extreme positive `fromIndex` values correctly', function() {
 803      var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 2 };
 804      equal(Benchmark.indexOf(object, 'c', 2), -1);
 805    });
 806  }());
 807
 808  /*--------------------------------------------------------------------------*/
 809
 810  QUnit.module('Benchmark.interpolate');
 811
 812  (function() {
 813    test('replaces tokens correctly', function() {
 814      var actual = Benchmark.interpolate('#{greeting} #{location}.', {
 815        'greeting': 'Hello',
 816        'location': 'world'
 817      });
 818
 819      equal(actual, 'Hello world.');
 820    });
 821
 822    test('ignores inherited object properties', function() {
 823      var actual = Benchmark.interpolate('x#{toString}', {});
 824      equal(actual, 'x#{toString}');
 825    });
 826
 827    test('allows for no template object', function() {
 828      var actual = Benchmark.interpolate('x');
 829      equal(actual, 'x');
 830    });
 831
 832    test('replaces duplicate tokens', function() {
 833      var actual = Benchmark.interpolate('#{x}#{x}#{x}', { 'x': 'a' });
 834      equal(actual, 'aaa');
 835    });
 836
 837    test('handles keys containing RegExp special characters', function() {
 838      var actual = Benchmark.interpolate('#{.*+?^=!:${}()|[]\\/}', { '.*+?^=!:${}()|[]\\/': 'x' });
 839      equal(actual, 'x');
 840    });
 841  }());
 842
 843  /*--------------------------------------------------------------------------*/
 844
 845  QUnit.module('Benchmark.invoke');
 846
 847  (function() {
 848    var objects = {
 849      'array': ['a', ['b'], 'c', null],
 850      'array-like-object': { '0': 'a', '1': ['b'], '2': 'c',  '3': null, 'length': 5 }
 851    };
 852
 853    objects.array.length = 5;
 854
 855    forOwn(objects, function(object, key) {
 856      test('produces the correct result when passing an ' + key, function() {
 857        var actual = Benchmark.invoke(object, 'concat');
 858        deepEqual(actual, ['a', ['b'], 'c', undefined, undefined]);
 859        equal('4' in actual, false);
 860      });
 861
 862      test('passes the correct arguments to the invoked method when passing an ' + key, function() {
 863        var actual = Benchmark.invoke(object, 'concat', 'x', 'y', 'z');
 864        deepEqual(actual, ['axyz', ['b', 'x', 'y', 'z'], 'cxyz', undefined, undefined]);
 865        equal('4' in actual, false);
 866      });
 867
 868      test('handles options object with callbacks correctly when passing an ' + key, function() {
 869        function callback() {
 870          callbacks.push(slice.call(arguments));
 871        }
 872
 873        var callbacks = [];
 874        var actual = Benchmark.invoke(object, {
 875          'name': 'concat',
 876          'args': ['x', 'y', 'z'],
 877          'onStart': callback,
 878          'onCycle': callback,
 879          'onComplete': callback
 880        });
 881
 882        deepEqual(actual, ['axyz', ['b', 'x', 'y', 'z'], 'cxyz', undefined, undefined]);
 883        equal('4' in actual, false);
 884
 885        equal(callbacks[0].length, 1);
 886        equal(callbacks[0][0].target, 'a');
 887        deepEqual(callbacks[0][0].currentTarget, object);
 888        equal(callbacks[0][0].type, 'start');
 889        equal(callbacks[1][0].type, 'cycle');
 890        equal(callbacks[5][0].type, 'complete');
 891      });
 892
 893      test('supports queuing when passing an ' + key, function() {
 894        var lengths = [];
 895        var actual = Benchmark.invoke(object, {
 896          'name': 'concat',
 897          'queued': true,
 898          'args': 'x',
 899          'onCycle': function() {
 900            lengths.push(object.length);
 901          }
 902        });
 903
 904        deepEqual(lengths, [5, 4, 3, 2]);
 905        deepEqual(actual, ['ax', ['b', 'x'], 'cx', undefined, undefined]);
 906      });
 907    });
 908  }());
 909
 910  /*--------------------------------------------------------------------------*/
 911
 912  QUnit.module('Benchmark.join');
 913
 914  (function() {
 915    var objects = {
 916      'array': ['a', 'b', ''],
 917      'array-like-object': { '0': 'a', '1': 'b', '2': '', 'length': 4 },
 918      'object': { 'a': '0', 'b': '1', '': '2' }
 919    };
 920
 921    objects.array.length = 4;
 922
 923    forOwn(objects, function(object, key) {
 924      test('joins correctly using the default separator when passing an ' + key, function() {
 925        equal(Benchmark.join(object), key == 'object' ? 'a: 0,b: 1,: 2' : 'a,b,');
 926      });
 927
 928      test('joins correctly using a custom separator when passing an ' + key, function() {
 929        equal(Benchmark.join(object, '+', '@'), key == 'object' ? 'a@0+b@1+@2' :  'a+b+');
 930      });
 931    });
 932  }());
 933
 934  /*--------------------------------------------------------------------------*/
 935
 936  QUnit.module('Benchmark.map');
 937
 938  (function() {
 939    var objects = {
 940      'array': ['a', 'b', 'c', ''],
 941      'array-like-object': { '0': 'a', '1': 'b', '2': 'c',  '3': '', 'length': 5 }
 942    };
 943
 944    objects.array.length = 5;
 945
 946    forOwn(objects, function(object, key) {
 947      test('passes the correct arguments when passing an ' + key, function() {
 948        var args;
 949        Benchmark.map(object, function() {
 950          args || (args = slice.call(arguments));
 951        });
 952
 953        deepEqual(args, ['a', 0, object]);
 954      });
 955
 956      test('produces the correct result when passing an ' + key, function() {
 957        var actual = Benchmark.map(object, function(value, index) {
 958          return value + index;
 959        });
 960
 961        deepEqual(actual, ['a0', 'b1', 'c2', '3', undefined]);
 962        equal('4' in actual, false);
 963      });
 964
 965      test('produces an array of the correct length for sparse ' + key + 's', function() {
 966        equal(Benchmark.map(object, function() { }).length, 5);
 967      });
 968    });
 969  }());
 970
 971  /*--------------------------------------------------------------------------*/
 972
 973  QUnit.module('Benchmark.pluck');
 974
 975  (function() {
 976    var objects = {
 977      'array': [{ '_': 'a' }, { '_': 'b' }, { '_': 'c' }, null],
 978      'array-like-object': { '0': { '_': 'a' }, '1': { '_': 'b' }, '2': { '_': 'c' },  '3': null, 'length': 5 }
 979    };
 980
 981    objects.array.length = 5;
 982
 983    forOwn(objects, function(object, key) {
 984      test('produces the correct result when passing an ' + key, function() {
 985        var actual = Benchmark.pluck(object, '_');
 986        deepEqual(actual, ['a', 'b', 'c', undefined, undefined]);
 987        equal('4' in actual, false);
 988      });
 989
 990      test('produces the correct result for non-existent keys when passing an ' + key, function() {
 991        var actual = Benchmark.pluck(object, 'non-existent');
 992        deepEqual(actual, [undefined, undefined, undefined, undefined, undefined]);
 993        equal('4' in actual, false);
 994      });
 995    });
 996  }());
 997
 998  /*--------------------------------------------------------------------------*/
 999
1000  QUnit.module('Benchmark.reduce');
1001
1002  (function() {
1003    var objects = {
1004      'array': ['b', 'c', ''],
1005      'array-like-object': { '0': 'b', '1': 'c',  '2': '', 'length': 4 }
1006    };
1007
1008    objects.array.length = 4;
1009
1010    forOwn(objects, function(object, key) {
1011      test('passes the correct arguments when passing an ' + key, function() {
1012        var args;
1013        Benchmark.reduce(object, function() {
1014          args || (args = slice.call(arguments));
1015        }, 'a');
1016
1017        deepEqual(args, ['a', 'b', 0, object]);
1018      });
1019
1020      test('accumulates correctly when passing an ' + key, function() {
1021        var actual = Benchmark.reduce(object, function(string, value) {
1022          return string + value;
1023        }, 'a');
1024
1025        equal(actual, 'abc');
1026      });
1027
1028      test('handles arguments with no initial value correctly when passing an ' + key, function() {
1029        var args;
1030        Benchmark.reduce(object, function() {
1031          args || (args = slice.call(arguments));
1032        });
1033
1034        deepEqual(args, ['b', 'c', 1, object]);
1035      });
1036    });
1037  }());
1038
1039  /*--------------------------------------------------------------------------*/
1040
1041  QUnit.module('Benchmark#clone');
1042
1043  (function() {
1044    var bench = Benchmark(function() { this.count += 0; }).run();
1045
1046    test('produces the correct result passing no arguments', function() {
1047      var clone = bench.clone();
1048      deepEqual(clone, bench);
1049      ok(clone.stats != bench.stats && clone.times != bench.times && clone.options != bench.options);
1050    });
1051
1052    test('produces the correct result passing a data object', function() {
1053      var clone = bench.clone({ 'fn': '', 'name': 'foo' });
1054      ok(clone.fn === '' && clone.options.fn === '');
1055      ok(clone.name == 'foo' && clone.options.name == 'foo');
1056    });
1057  }());
1058
1059  /*--------------------------------------------------------------------------*/
1060
1061  QUnit.module('Benchmark#run');
1062
1063  (function() {
1064    var data = { 'onComplete': 0, 'onCycle': 0, 'onStart': 0 };
1065
1066    var bench = Benchmark({
1067      'fn': function() {
1068        this.count += 0;
1069      },
1070      'onStart': function() {
1071        data.onStart++;
1072      },
1073      'onComplete': function() {
1074        data.onComplete++;
1075      }
1076    })
1077    .run();
1078
1079    test('onXYZ callbacks should not be triggered by internal benchmark clones', function() {
1080      equal(data.onStart, 1);
1081      equal(data.onComplete, 1);
1082    });
1083  }());
1084
1085  /*--------------------------------------------------------------------------*/
1086
1087  forOwn({
1088    'Benchmark': Benchmark,
1089    'Benchmark.Suite': Benchmark.Suite
1090  },
1091  function(Constructor, namespace) {
1092
1093    QUnit.module(namespace + '#emit');
1094
1095    (function() {
1096      test('emits passed arguments', function() {
1097        var args,
1098            object = Constructor();
1099
1100        object.on('args', function() { args = slice.call(arguments, 1); });
1101        object.emit('args', 'a', 'b', 'c');
1102        deepEqual(args, ['a', 'b', 'c']);
1103      });
1104
1105      test('emits with no listeners', function() {
1106        var event = Benchmark.Event('empty'),
1107            object = Constructor();
1108
1109        object.emit(event);
1110        equal(event.cancelled, false);
1111      });
1112
1113      test('emits with an event type of "toString"', function() {
1114        var event = Benchmark.Event('toString'),
1115            object = Constructor();
1116
1117        object.emit(event);
1118        equal(event.cancelled, false);
1119      });
1120
1121      test('returns the last listeners returned value', function() {
1122        var event = Benchmark.Event('result'),
1123            object = Constructor();
1124
1125        object.on('result', function() { return 'x'; });
1126        object.on('result', function() { return 'y'; });
1127        equal(object.emit(event), 'y');
1128      });
1129
1130      test('aborts the emitters listener iteration when `event.aborted` is `true`', function() {
1131        var event = Benchmark.Event('aborted'),
1132            object = Constructor();
1133
1134        object.on('aborted', function(event) {
1135          event.aborted = true;
1136          return false;
1137        });
1138
1139        object.on('aborted', function(event) {
1140          // should not get here
1141          event.aborted = false;
1142          return true;
1143        });
1144
1145        equal(object.emit(event), false);
1146        equal(event.aborted, true);
1147      });
1148
1149      test('cancels the event if a listener explicitly returns `false`', function() {
1150        var event = Benchmark.Event('cancel'),
1151            object = Constructor();
1152
1153        object.on('cancel', function() { return false; });
1154        object.on('cancel', function() { return true; });
1155        object.emit(event);
1156        equal(event.cancelled, true);
1157      });
1158
1159      test('uses a shallow clone of the listeners when emitting', function() {
1160        var event,
1161            listener2 = function(eventObject) { eventObject.listener2 = true },
1162            object = Constructor();
1163
1164        object.on('shallowclone', function(eventObject) {
1165          event = eventObject;
1166          object.off(event.type, listener2);
1167        })
1168        .on('shallowclone', listener2)
1169        .emit('shallowclone');
1170
1171        ok(event.listener2);
1172      });
1173
1174      test('emits a custom event object', function() {
1175        var event = Benchmark.Event('custom'),
1176            object = Constructor();
1177
1178        object.on('custom', function(eventObject) { eventObject.touched = true; });
1179        object.emit(event);
1180        ok(event.touched);
1181      });
1182
1183      test('sets `event.result` correctly', function() {
1184        var event = Benchmark.Event('result'),
1185            object = Constructor();
1186
1187        object.on('result', function() { return 'x'; });
1188        object.emit(event);
1189        equal(event.result, 'x');
1190      });
1191
1192      test('sets `event.type` correctly', function() {
1193        var event,
1194            object = Constructor();
1195
1196        object.on('type', function(eventObj) {
1197          event = eventObj;
1198        });
1199
1200        object.emit('type');
1201        equal(event.type, 'type');
1202      });
1203    }());
1204
1205    /*------------------------------------------------------------------------*/
1206
1207    QUnit.module(namespace + '#listeners');
1208
1209    (function() {
1210      test('returns the correct listeners', function() {
1211        var listener = function() { },
1212            object = Constructor();
1213
1214        object.on('x', listener);
1215        deepEqual(object.listeners('x'), [listener]);
1216      });
1217
1218      test('returns an array and initializes previously uninitialized listeners', function() {
1219        var object = Constructor();
1220        deepEqual(object.listeners('x'), []);
1221        deepEqual(object.events, { 'x': [] });
1222      });
1223    }());
1224
1225    /*------------------------------------------------------------------------*/
1226
1227    QUnit.module(namespace + '#off');
1228
1229    (function() {
1230      test('returns the benchmark', function() {
1231        var listener = function() { },
1232            object = Constructor();
1233
1234        object.on('x', listener);
1235        equal(object.off('x', listener), object);
1236      });
1237
1238      test('will ignore inherited properties of the event cache', function() {
1239        var Dummy = function() { },
1240            listener = function() { },
1241            object = Constructor();
1242
1243        Dummy.prototype.x = [listener];
1244        object.events = new Dummy;
1245
1246        object.off('x', listener);
1247        deepEqual(object.events.x, [listener]);
1248      });
1249
1250      test('handles an event type and listener', function() {
1251        var listener = function() { },
1252            object = Constructor();
1253
1254        object.on('x', listener);
1255        object.off('x', listener);
1256        deepEqual(object.events.x, []);
1257      });
1258
1259      test('handles unregistering duplicate listeners', function() {
1260        var listener = function() { },
1261            object = Constructor();
1262
1263        object.on('x', listener);
1264        object.on('x', listener);
1265
1266        var events = object.events;
1267        object.off('x', listener);
1268        deepEqual(events.x, [listener]);
1269
1270        object.off('x', listener);
1271        deepEqual(events.x, []);
1272      });
1273
1274      test('handles a non-registered listener', function() {
1275        var object = Constructor();
1276        object.off('x', function() { });
1277        equal(object.events, undefined);
1278      });
1279
1280      test('handles space separated event type and listener', function() {
1281        var listener = function() { },
1282            object = Constructor();
1283
1284        object.on('x', listener);
1285        object.on('y', listener);
1286
1287        var events = object.events;
1288        object.off('x y', listener);
1289        deepEqual(events.x, []);
1290        deepEqual(events.y, []);
1291      });
1292
1293      test('handles space separated event type and no listener', function() {
1294        var listener1 = function() { },
1295            listener2 = function() { },
1296            object = Constructor();
1297
1298        object.on('x', listener1);
1299        object.on('y', listener2);
1300
1301        var events = object.events;
1302        object.off('x y');
1303        deepEqual(events.x, []);
1304        deepEqual(events.y, []);
1305      });
1306
1307      test('handles no arguments', function() {
1308        var listener1 = function() { },
1309            listener2 = function() { },
1310            listener3 = function() { },
1311            object = Constructor();
1312
1313        object.on('x', listener1);
1314        object.on('y', listener2);
1315        object.on('z', listener3);
1316
1317        var events = object.events;
1318        object.off();
1319        deepEqual(events.x, []);
1320        deepEqual(events.y, []);
1321        deepEqual(events.z, []);
1322      });
1323    }());
1324
1325    /*------------------------------------------------------------------------*/
1326
1327    QUnit.module(namespace + '#on');
1328
1329    (function() {
1330      test('returns the benchmark', function() {
1331        var listener = function() { },
1332            object = Constructor();
1333
1334        equal(object.on('x', listener), object);
1335      });
1336
1337      test('will ignore inherited properties of the event cache', function() {
1338        var Dummy = function() { },
1339            listener1 = function() { },
1340            listener2 = function() { },
1341            object = Constructor();
1342
1343        Dummy.prototype.x = [listener1];
1344        object.events = new Dummy;
1345
1346        object.on('x', listener2);
1347        deepEqual(object.events.x, [listener2]);
1348      });
1349
1350      test('handles an event type and listener', function() {
1351        var listener = function() { },
1352            object = Constructor();
1353
1354        object.on('x', listener);
1355        deepEqual(object.events.x, [listener]);
1356      });
1357
1358      test('handles registering duplicate listeners', function() {
1359        var listener = function() { },
1360            object = Constructor();
1361
1362        object.on('x', listener);
1363        object.on('x', listener);
1364        deepEqual(object.events.x, [listener, listener]);
1365      });
1366
1367      test('handles space separated event type and listener', function() {
1368        var listener = function() { },
1369            object = Constructor();
1370
1371        object.on('x y', listener);
1372
1373        var events = object.events;
1374        deepEqual(events.x, [listener]);
1375        deepEqual(events.y, [listener]);
1376      });
1377    }());
1378  });
1379
1380  /*--------------------------------------------------------------------------*/
1381
1382  QUnit.module('Benchmark.Suite#abort');
1383
1384  (function() {
1385    test('igores abort calls when the suite isn\'t running', function() {
1386      var fired = false;
1387      var suite = Benchmark.Suite('suite', {
1388        'onAbort': function() { fired = true; }
1389      });
1390
1391      suite.add('foo', function() { });
1392      suite.abort();
1393      equal(fired, false);
1394    });
1395
1396    test('ignores abort calls from `Benchmark.Suite#reset` when the suite isn\'t running', function() {
1397      var fired = false;
1398      var suite = Benchmark.Suite('suite', {
1399        'onAbort': function() { fired = true; }
1400      });
1401
1402      suite.add('foo', function() { });
1403      suite.reset();
1404      equal(fired, false);
1405    });
1406
1407    asyncTest('emits an abort event when running', function() {
1408      var fired = false;
1409
1410      Benchmark.Suite({
1411        'onAbort': function() { fired = true; }
1412      })
1413      .on('start', function() {
1414        this.abort();
1415      })
1416      .on('complete', function() {
1417        ok(fired);
1418        QUnit.start();
1419      })
1420      .add(function(){ })
1421      .run({ 'async': true });
1422    });
1423
1424    asyncTest('emits an abort event after calling `Benchmark.Suite#reset`', function() {
1425      var fired = false;
1426
1427      Benchmark.Suite({
1428        'onAbort': function() { fired = true; }
1429      })
1430      .on('start', function() {
1431        this.reset();
1432      })
1433      .on('complete', function() {
1434        ok(fired);
1435        QUnit.start();
1436      })
1437      .add(function(){ })
1438      .run({ 'async': true });
1439    });
1440
1441    asyncTest('should abort deferred benchmark', function() {
1442      var fired = false,
1443          suite = Benchmark.Suite();
1444
1445      suite.on('complete', function() {
1446        equal(fired, false);
1447        QUnit.start();
1448      })
1449      .add('a', {
1450        'defer': true,
1451        'fn': function(deferred) {
1452          // avoid test inlining
1453          suite.name;
1454          // delay resolve
1455          setTimeout(function() {
1456            deferred.resolve();
1457            suite.abort();
1458          }, 10);
1459        }
1460      })
1461      .add('b', {
1462        'defer': true,
1463        'fn': function(deferred) {
1464          // avoid test inlining
1465          suite.name;
1466          // delay resolve
1467          setTimeout(function() {
1468            deferred.resolve();
1469            fired = true;
1470          }, 10);
1471        }
1472      })
1473      .run();
1474    });
1475  }());
1476
1477  /*--------------------------------------------------------------------------*/
1478
1479  QUnit.module('Benchmark.Suite#concat');
1480
1481  (function() {
1482    var args = arguments;
1483
1484    test('doesn\'t treat an arguments object like an array', function() {
1485      var suite = Benchmark.Suite();
1486      deepEqual(suite.concat(args), [args]);
1487    });
1488
1489    test('flattens array arguments', function() {
1490      var suite = Benchmark.Suite();
1491      deepEqual(suite.concat([1, 2], 3, [4, 5]), [1, 2, 3, 4, 5]);
1492    });
1493
1494    test('supports concating sparse arrays', function() {
1495      var suite = Benchmark.Suite();
1496      suite[0] = 0;
1497      suite[2] = 2;
1498      suite.length = 3;
1499
1500      var actual = suite.concat(3);
1501      deepEqual(actual, [0, undefined, 2, 3]);
1502      equal('1' in actual, false);
1503    });
1504
1505    test('supports sparse arrays as arguments', function() {
1506      var suite = Benchmark.Suite(),
1507          sparse = [];
1508
1509      sparse[0] = 0;
1510      sparse[2] = 2;
1511      sparse.length = 3;
1512
1513      var actual = suite.concat(sparse);
1514      deepEqual(actual, [0, undefined, 2]);
1515      equal('1' in actual, false);
1516    });
1517
1518    test('creates a new array', function() {
1519      var suite = Benchmark.Suite();
1520      ok(suite.concat(1) !== suite);
1521    });
1522  }(1, 2, 3));
1523
1524  /*--------------------------------------------------------------------------*/
1525
1526  QUnit.module('Benchmark.Suite#reverse');
1527
1528  (function() {
1529    test('reverses the element order', function() {
1530      var suite = Benchmark.Suite();
1531      suite[0] = 0;
1532      suite[1] = 1;
1533      suite.length = 2;
1534
1535      var actual = suite.reverse();
1536      equal(actual, suite);
1537      deepEqual(slice.call(actual), [1, 0]);
1538    });
1539
1540    test('supports reversing sparse arrays', function() {
1541      var suite = Benchmark.Suite();
1542      suite[0] = 0;
1543      suite[2] = 2;
1544      suite.length = 3;
1545
1546      var actual = suite.reverse();
1547      equal(actual, suite);
1548      deepEqual(slice.call(actual), [2, undefined, 0]);
1549      equal('1' in actual, false);
1550    });
1551  }());
1552
1553  /*--------------------------------------------------------------------------*/
1554
1555  QUnit.module('Benchmark.Suite#shift');
1556
1557  (function() {
1558    test('removes the first element', function() {
1559      var suite = Benchmark.Suite();
1560      suite[0] = 0;
1561      suite[1] = 1;
1562      suite.length = 2;
1563
1564      var actual = suite.shift();
1565      equal(actual, 0);
1566      deepEqual(slice.call(suite), [1]);
1567    });
1568
1569    test('shifts an object with no elements', function() {
1570      var suite = Benchmark.Suite(),
1571          actual = suite.shift();
1572
1573      equal(actual, undefined);
1574      deepEqual(slice.call(suite), []);
1575    });
1576
1577    test('should have no elements when length is 0 after shift', function() {
1578      var suite = Benchmark.Suite();
1579      suite[0] = 0;
1580      suite.length = 1;
1581      suite.shift();
1582
1583      // ensure element is removed
1584      equal('0' in suite, false);
1585      equal(suite.length, 0);
1586    });
1587
1588    test('supports shifting sparse arrays', function() {
1589      var suite = Benchmark.Suite();
1590      suite[1] = 1;
1591      suite[3] = 3;
1592      suite.length = 4;
1593
1594      var actual = suite.shift();
1595      equal(actual, undefined);
1596      deepEqual(slice.call(suite), [1, undefined, 3]);
1597      equal('1' in suite, false);
1598    });
1599  }());
1600
1601  /*--------------------------------------------------------------------------*/
1602
1603  QUnit.module('Benchmark.Suite#slice');
1604
1605  (function() {
1606    var suite = Benchmark.Suite();
1607    suite[0] = 0;
1608    suite[1] = 1;
1609    suite[2] = 2;
1610    suite[3] = 3;
1611    suite.length = 4;
1612
1613    test('works with no arguments', function() {
1614      var actual = suite.slice();
1615      deepEqual(actual, [0, 1, 2, 3]);
1616      ok(suite !== actual);
1617    });
1618
1619    test('works with positive `start` argument', function() {
1620      var actual = suite.slice(2);
1621      deepEqual(actual, [2, 3]);
1622      ok(suite !== actual);
1623    });
1624
1625    test('works with positive `start` and `end` arguments', function() {
1626      var actual = suite.slice(1, 3);
1627      deepEqual(actual, [1, 2]);
1628      ok(suite !== actual);
1629    });
1630
1631    test('works with `end` values exceeding length', function() {
1632      var actual = suite.slice(1, 10);
1633      deepEqual(actual, [1, 2, 3]);
1634      ok(suite !== actual);
1635    });
1636
1637    test('works with negative `start` and `end` arguments', function() {
1638      var actual = suite.slice(-3, -1);
1639      deepEqual(actual, [1, 2]);
1640      ok(suite !== actual);
1641    });
1642
1643    test('works with an extreme negative `end` value', function() {
1644      var actual = suite.slice(1, -10);
1645      deepEqual(actual, []);
1646      equal('-1' in actual, false);
1647      ok(suite !== actual);
1648    });
1649
1650    test('supports slicing sparse arrays', function() {
1651      var sparse = Benchmark.Suite();
1652      sparse[1] = 1;
1653      sparse[3] = 3;
1654      sparse.length = 4;
1655
1656      var actual = sparse.slice(0, 2);
1657      deepEqual(actual, [undefined, 1]);
1658      equal('0' in actual, false);
1659
1660      actual = sparse.slice(1);
1661      deepEqual(actual, [1, undefined, 3]);
1662      equal('1' in actual, false);
1663    });
1664  }());
1665
1666  /*--------------------------------------------------------------------------*/
1667
1668  QUnit.module('Benchmark.Suite#splice');
1669
1670  (function() {
1671    test('works with no arguments', function() {
1672      var suite = Benchmark.Suite();
1673      suite[0] = 0;
1674      suite.length = 1;
1675
1676      var actual = suite.splice();
1677      deepEqual(actual, []);
1678      deepEqual(slice.call(suite), [0]);
1679    });
1680
1681    test('works with only the `start` argument', function() {
1682      var suite = Benchmark.Suite();
1683      suite[0] = 0;
1684      suite[1] = 1;
1685      suite.length = 2;
1686
1687      var actual = suite.splice(1);
1688      deepEqual(actual, [1]);
1689      deepEqual(slice.call(suite), [0]);
1690    });
1691
1692    test('should have no elements when length is 0 after splice', function() {
1693      var suite = Benchmark.Suite();
1694      suite[0] = 0;
1695      suite.length = 1
1696      suite.splice(0, 1);
1697
1698      // ensure element is removed
1699      equal('0' in suite, false);
1700      equal(suite.length, 0);
1701    });
1702
1703    test('works with positive `start` argument', function() {
1704      var suite = Benchmark.Suite();
1705      suite[0] = 0;
1706      suite[1] = 3;
1707      suite.length = 2;
1708
1709      var actual = suite.splice(1, 0, 1, 2);
1710      deepEqual(actual, []);
1711      deepEqual(slice.call(suite), [0, 1, 2, 3]);
1712    });
1713
1714    test('works with positive `start` and `deleteCount` arguments', function() {
1715      var suite = Benchmark.Suite();
1716      suite[0] = 0;
1717      suite[1] = 3;
1718      suite.length = 2;
1719
1720      var actual = suite.splice(1, 1, 1, 2);
1721      deepEqual(actual, [3]);
1722      deepEqual(slice.call(suite), [0, 1, 2]);
1723    });
1724
1725    test('works with `deleteCount` values exceeding length', function() {
1726      var suite = Benchmark.Suite();
1727      suite[0] = 0;
1728      suite[1] = 3;
1729      suite.length = 2;
1730
1731      var actual = suite.splice(1, 10, 1, 2);
1732      deepEqual(actual, [3]);
1733      deepEqual(slice.call(suite), [0, 1, 2]);
1734    });
1735
1736    test('works with negative `start` and `deleteCount` arguments', function() {
1737      var suite = Benchmark.Suite();
1738      suite[0] = 0;
1739      suite[1] = 3;
1740      suite.length = 2;
1741
1742      var actual = suite.splice(-1, -1, 1, 2);
1743      deepEqual(actual, []);
1744      deepEqual(slice.call(suite), [0, 1, 2, 3]);
1745    });
1746
1747    test('works with an extreme negative `deleteCount` value', function() {
1748      var suite = Benchmark.Suite();
1749      suite[0] = 0;
1750      suite[1] = 3;
1751      suite.length = 2;
1752
1753      var actual = suite.splice(0, -10, 1, 2);
1754      deepEqual(actual, []);
1755      deepEqual(slice.call(suite), [1, 2, 0, 3]);
1756    });
1757
1758    test('supports splicing sparse arrays', function() {
1759      var suite = Benchmark.Suite();
1760      suite[1] = 1;
1761      suite[3] = 3;
1762      suite.length = 4;
1763
1764      var actual = suite.splice(1, 2, 1, 2);
1765      deepEqual(actual, [1, undefined]);
1766      equal(actual.length, 2);
1767      deepEqual(slice.call(suite), [undefined, 1, 2, 3]);
1768      equal('0' in suite, false);
1769    });
1770  }());
1771
1772  /*--------------------------------------------------------------------------*/
1773
1774  QUnit.module('Benchmark.Suite#unshift');
1775
1776  (function() {
1777    test('adds a first element', function() {
1778      var suite = Benchmark.Suite();
1779      suite[0] = 1;
1780      suite.length = 1;
1781
1782      var actual = suite.unshift(0);
1783      equal(actual, 2);
1784      deepEqual(slice.call(suite), [0, 1]);
1785    });
1786
1787    test('adds multiple elements to the front', function() {
1788      var suite = Benchmark.Suite();
1789      suite[0] = 3;
1790      suite.length = 1;
1791
1792      var actual = suite.unshift(0, 1, 2);
1793      equal(actual, 4);
1794      deepEqual(slice.call(suite), [0, 1, 2, 3]);
1795    });
1796
1797    test('supports unshifting sparse arrays', function() {
1798      var suite = Benchmark.Suite();
1799      suite[1] = 2;
1800      suite.length = 2;
1801
1802      var actual = suite.unshift(0);
1803      equal(actual, 3);
1804      deepEqual(slice.call(suite), [0, undefined, 2]);
1805      equal('1' in suite, false);
1806    });
1807  }());
1808
1809  /*--------------------------------------------------------------------------*/
1810
1811  QUnit.module('Benchmark.Suite filtered results onComplete');
1812
1813  (function() {
1814    var count = 0,
1815        suite = Benchmark.Suite();
1816
1817    suite.add('a', function() {
1818      count++;
1819    })
1820    .add('b', function() {
1821      for (var i = 0; i < 1e6; i++) {
1822        count++;
1823      }
1824    })
1825    .add('c', function() {
1826      throw new TypeError;
1827    });
1828
1829    asyncTest('should filter by fastest', function() {
1830      suite.on('complete', function() {
1831        suite.off();
1832        deepEqual(this.filter('fastest').pluck('name'), ['a']);
1833        QUnit.start();
1834      })
1835      .run({ 'async': true });
1836    });
1837
1838    asyncTest('should filter by slowest', function() {
1839      suite.on('complete', function() {
1840        suite.off();
1841        deepEqual(this.filter('slowest').pluck('name'), ['b']);
1842        QUnit.start();
1843      })
1844      .run({ 'async': true });
1845    });
1846
1847    asyncTest('should filter by successful', function() {
1848      suite.on('complete', function() {
1849        suite.off();
1850        deepEqual(this.filter('successful').pluck('name'), ['a', 'b']);
1851        QUnit.start();
1852      })
1853      .run({ 'async': true });
1854    });
1855  }());
1856
1857  /*--------------------------------------------------------------------------*/
1858
1859  QUnit.module('Benchmark.Suite event flow');
1860
1861  (function() {
1862    var events = [],
1863        callback = function(event) { events.push(event); };
1864
1865    var suite = Benchmark.Suite('suite', {
1866      'onAdd': callback,
1867      'onAbort': callback,
1868      'onClone': callback,
1869      'onError': callback,
1870      'onStart': callback,
1871      'onCycle': callback,
1872      'onComplete': callback,
1873      'onReset': callback
1874    })
1875    .add('bench', function() {
1876      throw null;
1877    }, {
1878      'onAbort': callback,
1879      'onClone': callback,
1880      'onError': callback,
1881      'onStart': callback,
1882      'onCycle': callback,
1883      'onComplete': callback,
1884      'onReset': callback
1885    })
1886    .run({ 'async': false });
1887
1888    // first Suite#onAdd
1889    test('should emit the suite "add" event first', function() {
1890      var event = events[0];
1891      ok(event.type == 'add' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
1892    });
1893
1894    // next we start the Suite because no reset was needed
1895    test('should emit the suite "start" event', function() {
1896      var event = events[1];
1897      ok(event.type == 'start' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
1898    });
1899
1900    // and so start the first benchmark
1901    test('should emit the benchmark "start" event', function() {
1902      var event = events[2];
1903      ok(event.type == 'start' && event.currentTarget.name == 'bench');
1904    });
1905
1906    // oh no! we abort because of an error
1907    test('should emit the benchmark "error" event', function() {
1908      var event = events[3];
1909      ok(event.type == 'error' && event.currentTarget.name == 'bench');
1910    });
1911
1912    // benchmark error triggered
1913    test('should emit the benchmark "abort" event', function() {
1914      var event = events[4];
1915      ok(event.type == 'abort' && event.currentTarget.name == 'bench');
1916    });
1917
1918    // we reset the benchmark as part of the abort
1919    test('should emit the benchmark "reset" event', function() {
1920      var event = events[5];
1921      ok(event.type == 'reset' && event.currentTarget.name == 'bench');
1922    });
1923
1924    // benchmark is cycle is finished
1925    test('should emit the benchmark "cycle" event', function() {
1926      var event = events[6];
1927      ok(event.type == 'cycle' && event.currentTarget.name == 'bench');
1928    });
1929
1930    // benchmark is complete
1931    test('should emit the benchmark "complete" event', function() {
1932      var event = events[7];
1933      ok(event.type == 'complete' && event.currentTarget.name == 'bench');
1934    });
1935
1936    // the benchmark error triggers a Suite error
1937    test('should emit the suite "error" event', function() {
1938      var event = events[8];
1939      ok(event.type == 'error' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
1940    });
1941
1942    // the Suite cycle finishes
1943    test('should emit the suite "cycle" event', function() {
1944      var event = events[9];
1945      ok(event.type == 'cycle' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
1946    });
1947
1948    // the Suite completes
1949    test('finally it should emit the suite "complete" event', function() {
1950      var event = events[10];
1951      ok(event.type == 'complete' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
1952    });
1953
1954    test('emitted all expected events', function() {
1955      ok(events.length == 11);
1956    });
1957  }());
1958
1959  /*--------------------------------------------------------------------------*/
1960
1961  QUnit.module('Deferred benchmarks');
1962
1963  (function() {
1964    asyncTest('should run a deferred benchmark correctly', function() {
1965      Benchmark(function(deferred) {
1966        setTimeout(function() { deferred.resolve(); }, 1e3);
1967      }, {
1968        'defer': true,
1969        'onComplete': function() {
1970          equal(this.hz.toFixed(0), 1);
1971          QUnit.start();
1972        }
1973      })
1974      .run();
1975    });
1976
1977    asyncTest('should run with string values for "fn", "setup", and "teardown"', function() {
1978      Benchmark({
1979        'defer': true,
1980        'setup': 'var x = [3, 2, 1];',
1981        'fn': 'setTimeout(function() { x.sort(); deferred.resolve(); }, 10);',
1982        'teardown': 'x.length = 0;',
1983        'onComplete': function() {
1984          ok(true);
1985          QUnit.start();
1986        }
1987      })
1988      .run();
1989    });
1990
1991    asyncTest('should run recursively', function() {
1992      Benchmark({
1993        'defer': true,
1994        'setup': 'var x = [3, 2, 1];',
1995        'fn': 'for (var i = 0; i < 100; i++) x[ i % 2 ? "sort" : "reverse" ](); deferred.resolve();',
1996        'teardown': 'x.length = 0;',
1997        'onComplete': function() {
1998          ok(true);
1999          QUnit.start();
2000        }
2001      })
2002      .run();
2003    });
2004
2005    asyncTest('should execute "setup", "fn", and "teardown" in correct order', function() {
2006      var fired = [];
2007
2008      Benchmark({
2009        'defer': true,
2010        'setup': function() {
2011          fired.push('setup');
2012        },
2013        'fn': function(deferred) {
2014          fired.push('fn');
2015          setTimeout(function() { deferred.resolve(); }, 10);
2016        },
2017        'teardown': function() {
2018          fired.push('teardown');
2019        },
2020        'onComplete': function() {
2021          var actual = fired.join().replace(/(fn,)+/g, '$1').replace(/(setup,fn,teardown(?:,|$))+/, '$1');
2022          equal(actual, 'setup,fn,teardown');
2023          QUnit.start();
2024        }
2025      })
2026      .run();
2027    });
2028  }());
2029
2030  /*--------------------------------------------------------------------------*/
2031
2032  QUnit.module('Benchmark.deepClone');
2033
2034  (function() {
2035    asyncTest('avoids call stack limits', function() {
2036      var result,
2037          count = 0,
2038          object = {},
2039          recurse = function() { count++; recurse(); };
2040
2041      setTimeout(function() {
2042        ok(result, 'avoids call stack limits (stack limit is ' + (count - 1) + ')');
2043        QUnit.start();
2044      }, 15);
2045
2046      if (toString.call(window.java) == '[object JavaPackage]') {
2047        // Java throws uncatchable errors on call stack overflows, so to avoid
2048        // them I chose a number higher than Rhino's call stack limit without
2049        // dynamically testing for the actual limit
2050        count = 3e3;
2051      } else {
2052        try { recurse(); } catch(e) { }
2053      }
2054
2055      // exceed limit
2056      count++;
2057      for (var i = 0, sub = object; i <= count; i++) {
2058        sub = sub[i] = {};
2059      }
2060
2061      try {
2062        for (var i = 0, sub = Benchmark.deepClone(object); sub = sub[i]; i++) { }
2063        result = --i == count;
2064      } catch(e) { }
2065    });
2066  }());
2067
2068  /*--------------------------------------------------------------------------*/
2069
2070  // explicitly call `QUnit.start()` for Narwhal, Rhino, and RingoJS
2071  if (!window.document) {
2072    QUnit.start();
2073  }
2074}(typeof global == 'object' && global || this));