comunicationLeap/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));