| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074 |
- ;(function(window, undefined) {
- 'use strict';
- /** Use a single load function */
- var load = typeof require == 'function' ? require : window.load;
- /** The `platform` object to check */
- var platform =
- window.platform ||
- load('../vendor/platform.js/platform.js') ||
- window.platform;
- /** The unit testing framework */
- var QUnit =
- window.QUnit || (
- window.setTimeout || (window.addEventListener = window.setTimeout = / /),
- window.QUnit = load('../vendor/qunit/qunit/qunit' + (platform.name == 'Narwhal' ? '-1.8.0' : '') + '.js') || window.QUnit,
- load('../vendor/qunit-clib/qunit-clib.js'),
- (window.addEventListener || 0).test && delete window.addEventListener,
- window.QUnit
- );
- /** The `Benchmark` constructor to test */
- var Benchmark =
- window.Benchmark || (
- Benchmark = load('../benchmark.js') || window.Benchmark,
- Benchmark.Benchmark || Benchmark
- );
- /** API shortcut */
- var forOwn = Benchmark.forOwn;
- /** Used to get property descriptors */
- var getDescriptor = Object.getOwnPropertyDescriptor;
- /** Used to set property descriptors */
- var setDescriptor = Object.defineProperty;
- /** Shortcut used to convert array-like objects to arrays */
- var slice = [].slice;
- /** Used to resolve a value's internal [[Class]] */
- var toString = {}.toString;
- /** Used to check problem JScript properties (a.k.a. the [[DontEnum]] bug) */
- var shadowed = {
- 'constructor': 1,
- 'hasOwnProperty': 2,
- 'isPrototypeOf': 3,
- 'propertyIsEnumerable': 4,
- 'toLocaleString': 5,
- 'toString': 6,
- 'valueOf': 7
- };
- /** Used to flag environments/features */
- var support = {
- 'descriptors': !!function() {
- try {
- var o = {};
- return (setDescriptor(o, o, o), 'value' in getDescriptor(o, o));
- } catch(e) { }
- }()
- };
- /*--------------------------------------------------------------------------*/
- /**
- * Skips a given number of tests with a passing result.
- *
- * @private
- * @param {Number} [count=1] The number of tests to skip.
- */
- function skipTest(count) {
- count || (count = 1);
- while (count--) {
- ok(true, 'test skipped');
- }
- }
- /*--------------------------------------------------------------------------*/
- // init Benchmark.options.minTime
- Benchmark(function() { throw 0; }).run();
- // set a shorter max time
- Benchmark.options.maxTime = Benchmark.options.minTime * 5;
- // explicitly call `QUnit.module()` instead of `module()`
- // in case we are in a CLI environment
- QUnit.module('Benchmark');
- (function() {
- test('has the default `Benchmark.platform` value', function() {
- if (window.document) {
- equal(String(Benchmark.platform), navigator.userAgent);
- } else {
- skipTest(1)
- }
- });
- test('supports loading Benchmark.js as a module', function() {
- if (window.document && window.require) {
- equal((Benchmark2 || {}).version, Benchmark.version);
- } else {
- skipTest(1)
- }
- });
- test('supports loading Platform.js as a module', function() {
- if (window.document && window.require) {
- var platform = (Benchmark2 || {}).platform || {};
- equal(typeof platform.name, 'string');
- } else {
- skipTest(1)
- }
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark constructor');
- (function() {
- test('creates a new instance when called without the `new` operator', function() {
- ok(Benchmark() instanceof Benchmark);
- });
- test('supports passing an options object', function() {
- var bench = Benchmark({ 'name': 'foo', 'fn': function() { } });
- ok(bench.fn && bench.name == 'foo');
- });
- test('supports passing a "name" and "fn" argument', function() {
- var bench = Benchmark('foo', function() { });
- ok(bench.fn && bench.name == 'foo');
- });
- test('supports passing a "name" argument and an options object', function() {
- var bench = Benchmark('foo', { 'fn': function() { } });
- ok(bench.fn && bench.name == 'foo');
- });
- test('supports passing a "name" argument and an options object', function() {
- var bench = Benchmark('foo', function() { }, { 'id': 'bar' });
- ok(bench.fn && bench.name == 'foo' && bench.id == 'bar');
- });
- test('supports passing an empy string for the "fn" options property', function() {
- var bench = Benchmark({ 'fn': '' }).run();
- ok(!bench.error);
- });
- test('detects dead code', function() {
- var bench = Benchmark(function() { }).run();
- ok(/setup\(\)/.test(bench.compiled) ? !bench.error : bench.error);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark compilation');
- (function() {
- test('compiles using the default `Function#toString`', function() {
- var bench = Benchmark({
- 'setup': function() { var a = 1; },
- 'fn': function() { throw a; },
- 'teardown': function() { a = 2; }
- }).run();
- var compiled = bench.compiled;
- if (/setup\(\)/.test(compiled)) {
- skipTest();
- }
- else {
- ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled));
- }
- });
- test('compiles using a custom "toString" method', function() {
- var bench = Benchmark({
- 'setup': function() { },
- 'fn': function() { },
- 'teardown': function() { }
- });
- bench.setup.toString = function() { return 'var a = 1;' };
- bench.fn.toString = function() { return 'throw a;' };
- bench.teardown.toString = function() { return 'a = 2;' };
- bench.run();
- var compiled = bench.compiled;
- if (/setup\(\)/.test(compiled)) {
- skipTest();
- }
- else {
- ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled));
- }
- });
- test('compiles using a string value', function() {
- var bench = Benchmark({
- 'setup': 'var a = 1;',
- 'fn': 'throw a;',
- 'teardown': 'a = 2;'
- }).run();
- var compiled = bench.compiled;
- if (/setup\(\)/.test(compiled)) {
- skipTest();
- }
- else {
- ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled));
- }
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark test binding');
- (function() {
- var count = 0;
- var tests = {
- 'inlined "setup", "fn", and "teardown"': (
- 'if(/ops/.test(this))this._fn=true;'
- ),
- 'called "fn" and inlined "setup"/"teardown" reached by error': function() {
- count++;
- if (/ops/.test(this)) {
- this._fn = true;
- }
- },
- 'called "fn" and inlined "setup"/"teardown" reached by `return` statement': function() {
- if (/ops/.test(this)) {
- this._fn = true;
- }
- return;
- }
- };
- forOwn(tests, function(fn, title) {
- test('has correct binding for ' + title, function() {
- var bench = Benchmark({
- 'setup': 'if(/ops/.test(this))this._setup=true;',
- 'fn': fn,
- 'teardown': 'if(/ops/.test(this))this._teardown=true;',
- 'onCycle': function() { this.abort(); }
- }).run();
- var compiled = bench.compiled;
- if (/setup\(\)/.test(compiled)) {
- skipTest(3);
- }
- else {
- ok(bench._setup, 'correct binding for "setup"');
- ok(bench._fn, 'correct binding for "fn"');
- ok(bench._teardown, 'correct binding for "teardown"');
- }
- });
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.deepClone');
- (function() {
- function createCircularObject() {
- var result = {
- 'foo': { 'b': { 'foo': { 'c': { } } } },
- 'bar': { }
- };
- result.foo.b.foo.c.foo = result;
- result.bar.b = result.foo.b;
- return result;
- }
- function Klass() {
- this.a = 1;
- }
- Klass.prototype = { 'b': 1 };
- var notCloneable = {
- 'an arguments object': arguments,
- 'an element': window.document && document.body,
- 'a function': Klass,
- 'a Klass instance': new Klass
- };
- var objects = {
- 'an array': ['a', 'b', 'c', ''],
- 'an array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 },
- 'boolean': false,
- 'boolean object': Object(false),
- 'an object': { 'a': 0, 'b': 1, 'c': 3 },
- 'an object with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } },
- 'null': null,
- 'a number': 3,
- 'a number object': Object(3),
- 'a regexp': /x/gim,
- 'a string': 'x',
- 'a string object': Object('x'),
- 'undefined': undefined
- };
- objects['an array'].length = 5;
- forOwn(objects, function(object, key) {
- test('clones ' + key + ' correctly', function() {
- var kind = toString.call(object),
- clone = Benchmark.deepClone(object);
- if (object == null) {
- equal(clone, object);
- } else {
- deepEqual(clone.valueOf(), object.valueOf());
- }
- if (object === Object(object)) {
- ok(clone !== object);
- } else {
- skipTest();
- }
- });
- });
- forOwn(notCloneable, function(object, key) {
- test('does not clone ' + key, function() {
- ok(Benchmark.deepClone(object) === object);
- });
- });
- test('clones using Klass#deepClone', function() {
- var object = new Klass;
- Klass.prototype.deepClone = function() { return new Klass; };
- var clone = Benchmark.deepClone(object);
- ok(clone !== object && clone instanceof Klass);
- delete Klass.prototype.clone;
- });
- test('clones problem JScript properties', function() {
- var clone = Benchmark.deepClone(shadowed);
- deepEqual(clone, shadowed);
- });
- test('clones string object with custom property', function() {
- var object = new String('x');
- object.x = 1;
- var clone = Benchmark.deepClone(object);
- ok(clone == 'x' && typeof clone == 'object' && clone.x === 1 && toString.call(clone) == '[object String]');
- });
- test('clones objects with circular references', function() {
- var object = createCircularObject(),
- clone = Benchmark.deepClone(object);
- ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object);
- });
- test('clones non-extensible objects with circular references', function() {
- if (Object.preventExtensions) {
- var object = Object.preventExtensions(createCircularObject());
- Object.preventExtensions(object.bar.b);
- var clone = Benchmark.deepClone(object);
- ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object);
- } else {
- skipTest(1)
- }
- });
- test('clones sealed objects with circular references', function() {
- if (Object.seal) {
- var object = Object.seal(createCircularObject());
- Object.seal(object.bar.b);
- var clone = Benchmark.deepClone(object);
- ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object);
- } else {
- skipTest(1)
- }
- });
- test('clones frozen objects with circular references', function() {
- if (Object.freeze) {
- var object = Object.freeze(createCircularObject());
- Object.freeze(object.bar.b);
- var clone = Benchmark.deepClone(object);
- ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object);
- } else {
- skipTest(1)
- }
- });
- test('clones objects with custom descriptors and circular references', function() {
- var accessor,
- descriptor;
- if (support.descriptors) {
- var object = setDescriptor({}, 'foo', {
- 'configurable': true,
- 'value': setDescriptor({}, 'b', {
- 'writable': true,
- 'value': setDescriptor({}, 'foo', {
- 'get': function() { return accessor; },
- 'set': function(value) { accessor = value; }
- })
- })
- });
- setDescriptor(object, 'bar', { 'value': {} });
- object.foo.b.foo = { 'c': object };
- object.bar.b = object.foo.b;
- var clone = Benchmark.deepClone(object);
- ok(clone !== object &&
- clone.bar.b === clone.foo.b &&
- clone !== clone.foo.b.foo.c.foo &&
- (descriptor = getDescriptor(clone, 'foo')) &&
- descriptor.configurable && !(descriptor.enumerable && descriptor.writable) &&
- (descriptor = getDescriptor(clone.foo, 'b')) &&
- descriptor.writable && !(descriptor.configurable && descriptor.enumerable) &&
- (descriptor = getDescriptor(clone.foo.b, 'foo')) &&
- descriptor.get && descriptor.set &&
- (descriptor = getDescriptor(clone.foo.b, 'foo')) &&
- !(descriptor.configurable && descriptor.enumerable && descriptor.writable) &&
- (descriptor = getDescriptor(clone, 'bar')) &&
- !(descriptor.configurable && descriptor.enumerable && descriptor.writable));
- }
- else {
- skipTest(1)
- }
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.each');
- (function() {
- var xpathResult;
- var objects = {
- 'array': ['a', 'b', 'c', ''],
- 'array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 },
- 'xpath snapshot': null
- };
- if (window.document && document.evaluate) {
- xpathResult = [document.documentElement, document.getElementsByTagName('head')[0], document.body];
- objects['xpath snapshot'] = document.evaluate('//*[self::html or self::head or self::body]', document, null, 7, null);
- }
- objects.array.length = 5;
- forOwn(objects, function(object, key) {
- test('passes the correct arguments when passing an ' + key, function() {
- if (object) {
- var args
- Benchmark.each(object, function() {
- args || (args = slice.call(arguments));
- });
- if (key == 'xpath snapshot') {
- ok(args[0] === xpathResult[0]);
- } else {
- equal(args[0], 'a');
- }
- equal(args[1], 0);
- ok(args[2] === object);
- }
- else {
- skipTest(3);
- }
- });
- test('returns the passed object when passing an ' + key, function() {
- if (object) {
- var actual = Benchmark.each(object, function() { });
- ok(actual === object);
- }
- else {
- skipTest();
- }
- });
- test('iterates over all indexes when passing an ' + key, function() {
- if (object) {
- var values = [];
- Benchmark.each(object, function(value) {
- values.push(value);
- });
- deepEqual(values, key == 'xpath snapshot' ? xpathResult : ['a', 'b', 'c', '']);
- }
- else {
- skipTest();
- }
- });
- test('exits early when returning `false` when passing an ' + key, function() {
- if (object) {
- var values = [];
- Benchmark.each(object, function(value) {
- values.push(value);
- return values.length < 2;
- });
- deepEqual(values, key == 'xpath snapshot' ? xpathResult.slice(0, 2) : ['a', 'b']);
- }
- else {
- skipTest();
- }
- });
- });
- test('passes the third callback argument as an object', function() {
- var thirdArg;
- Benchmark.each('hello', function(value, index, object) {
- thirdArg = object;
- });
- ok(thirdArg && typeof thirdArg == 'object');
- });
- test('iterates over strings by index', function() {
- var values = [];
- Benchmark.each('hello', function(value) {
- values.push(value)
- });
- deepEqual(values, ['h', 'e', 'l', 'l', 'o']);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.extend');
- (function() {
- test('allows no source argument', function() {
- var object = {};
- equal(Benchmark.extend(object), object);
- });
- test('allows a single source argument', function() {
- var source = { 'x': 1, 'y': 1 },
- actual = Benchmark.extend({}, source);
- deepEqual(Benchmark.extend({}, source), { 'x': 1, 'y': 1 });
- });
- test('allows multiple source arguments', function() {
- var source1 = { 'x': 1, 'y': 1 },
- source2 = { 'y': 2, 'z': 2 },
- actual = Benchmark.extend({}, source1, source2);
- deepEqual(actual, { 'x': 1, 'y': 2, 'z': 2 });
- });
- test('will add inherited source properties', function() {
- function Source() { }
- Source.prototype.x = 1;
- deepEqual(Benchmark.extend({}, new Source), { 'x': 1 });
- });
- test('will add problem JScript properties', function() {
- deepEqual(Benchmark.extend({}, shadowed), shadowed);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.filter');
- (function() {
- var objects = {
- 'array': ['a', 'b', 'c', ''],
- 'array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 }
- };
- objects.array.length = 5;
- forOwn(objects, function(object, key) {
- test('passes the correct arguments when passing an ' + key, function() {
- var args;
- Benchmark.filter(object, function() {
- args || (args = slice.call(arguments));
- });
- deepEqual(args, ['a', 0, object]);
- });
- test('produces the correct result when passing an ' + key, function() {
- var actual = Benchmark.filter(object, function(value, index) {
- return index > 0;
- });
- deepEqual(actual, ['b', 'c', '']);
- });
- test('iterates over sparse ' + key + 's correctly', function() {
- var actual = Benchmark.filter(object, function(value) {
- return value === undefined;
- });
- deepEqual(actual, []);
- });
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.forOwn');
- (function() {
- function fn() {
- // no-op
- }
- function KlassA() {
- this.a = 1;
- this.b = 2;
- this.c = 3;
- }
- function KlassB() {
- this.a = 1;
- this.constructor = 2;
- this.hasOwnProperty = 3;
- this.isPrototypeOf = 4;
- this.propertyIsEnumerable = 5;
- this.toLocaleString = 6;
- this.toString = 7;
- this.valueOf = 8;
- }
- function KlassC() {
- // no-op
- }
- fn.a = 1;
- fn.b = 2;
- fn.c = 3;
- KlassC.prototype.a = 1;
- KlassC.prototype.b = 2;
- KlassC.prototype.c = 3;
- var objects = {
- 'an arguments object': arguments,
- 'a function': fn,
- 'an object': new KlassA,
- 'an object shadowing properties on Object.prototype': new KlassB,
- 'a prototype object': KlassC.prototype,
- 'a string': 'abc'
- };
- forOwn(objects, function(object, key) {
- test('passes the correct arguments when passing ' + key, function() {
- var args;
- Benchmark.forOwn(object, function() {
- args || (args = slice.call(arguments));
- });
- equal(typeof args[0], key == 'a string' ? 'string' : 'number');
- equal(typeof args[1], 'string');
- equal(args[2] && typeof args[2], key == 'a function' ? 'function' : 'object');
- });
- test('returns the passed object when passing ' + key, function() {
- var actual = Benchmark.forOwn(object, function() { });
- deepEqual(actual, object);
- });
- test('iterates over own properties when passing ' + key, function() {
- var values = [];
- Benchmark.forOwn(object, function(value) {
- values.push(value);
- });
- if (object instanceof KlassB) {
- deepEqual(values.sort(), [1, 2, 3, 4, 5, 6, 7, 8]);
- } else if (key == 'a string') {
- deepEqual(values, ['a', 'b', 'c']);
- } else {
- deepEqual(values.sort(), [1, 2, 3]);
- }
- });
- test('exits early when returning `false` when passing ' + key, function() {
- var values = [];
- Benchmark.forOwn(object, function(value) {
- values.push(value);
- return false;
- });
- equal(values.length, 1);
- });
- if (object instanceof KlassB) {
- test('exits correctly when transitioning to the JScript [[DontEnum]] fix', function() {
- var values = [];
- Benchmark.forOwn(object, function(value) {
- values.push(value);
- return values.length < 2;
- });
- equal(values.length, 2);
- });
- }
- });
- }(1, 2, 3));
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.formatNumber');
- (function() {
- test('formats a million correctly', function() {
- equal(Benchmark.formatNumber(1e6), '1,000,000');
- });
- test('formats less than 100 correctly', function() {
- equal(Benchmark.formatNumber(23), '23');
- });
- test('formats numbers with decimal values correctly', function() {
- equal(Benchmark.formatNumber(1234.56), '1,234.56');
- });
- test('formats negative numbers correctly', function() {
- equal(Benchmark.formatNumber(-1234.56), '-1,234.56');
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.hasKey');
- (function() {
- test('returns `true` for own properties', function() {
- var object = { 'x': 1 };
- equal(Benchmark.hasKey(object, 'x'), true);
- });
- test('returns `false` for inherited properties', function() {
- equal(Benchmark.hasKey({}, 'toString'), false);
- });
- test('doesn\'t use an object\'s `hasOwnProperty` method', function() {
- var object = { 'hasOwnProperty': function() { return true; } };
- equal(Benchmark.hasKey(object, 'x'), false);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.indexOf');
- (function() {
- var objects = {
- 'array': ['a', 'b', 'c', ''],
- 'array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 }
- };
- objects.array.length = 5;
- forOwn(objects, function(object, key) {
- test('produces the correct result when passing an ' + key, function() {
- equal(Benchmark.indexOf(object, 'b'), 1);
- });
- test('matches values by strict equality when passing an ' + key, function() {
- equal(Benchmark.indexOf(object, new String('b')), -1);
- });
- test('iterates over sparse ' + key + 's correctly', function() {
- equal(Benchmark.indexOf(object, undefined), -1);
- });
- });
- test('searches from the given `fromIndex`', function() {
- var array = ['a', 'b', 'c', 'a'];
- equal(Benchmark.indexOf(array, 'a', 1), 3);
- });
- test('handles extreme negative `fromIndex` values correctly', function() {
- var array = ['a'];
- array['-1'] = 'z';
- equal(Benchmark.indexOf(array, 'z', -2), -1);
- });
- test('handles extreme positive `fromIndex` values correctly', function() {
- var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 2 };
- equal(Benchmark.indexOf(object, 'c', 2), -1);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.interpolate');
- (function() {
- test('replaces tokens correctly', function() {
- var actual = Benchmark.interpolate('#{greeting} #{location}.', {
- 'greeting': 'Hello',
- 'location': 'world'
- });
- equal(actual, 'Hello world.');
- });
- test('ignores inherited object properties', function() {
- var actual = Benchmark.interpolate('x#{toString}', {});
- equal(actual, 'x#{toString}');
- });
- test('allows for no template object', function() {
- var actual = Benchmark.interpolate('x');
- equal(actual, 'x');
- });
- test('replaces duplicate tokens', function() {
- var actual = Benchmark.interpolate('#{x}#{x}#{x}', { 'x': 'a' });
- equal(actual, 'aaa');
- });
- test('handles keys containing RegExp special characters', function() {
- var actual = Benchmark.interpolate('#{.*+?^=!:${}()|[]\\/}', { '.*+?^=!:${}()|[]\\/': 'x' });
- equal(actual, 'x');
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.invoke');
- (function() {
- var objects = {
- 'array': ['a', ['b'], 'c', null],
- 'array-like-object': { '0': 'a', '1': ['b'], '2': 'c', '3': null, 'length': 5 }
- };
- objects.array.length = 5;
- forOwn(objects, function(object, key) {
- test('produces the correct result when passing an ' + key, function() {
- var actual = Benchmark.invoke(object, 'concat');
- deepEqual(actual, ['a', ['b'], 'c', undefined, undefined]);
- equal('4' in actual, false);
- });
- test('passes the correct arguments to the invoked method when passing an ' + key, function() {
- var actual = Benchmark.invoke(object, 'concat', 'x', 'y', 'z');
- deepEqual(actual, ['axyz', ['b', 'x', 'y', 'z'], 'cxyz', undefined, undefined]);
- equal('4' in actual, false);
- });
- test('handles options object with callbacks correctly when passing an ' + key, function() {
- function callback() {
- callbacks.push(slice.call(arguments));
- }
- var callbacks = [];
- var actual = Benchmark.invoke(object, {
- 'name': 'concat',
- 'args': ['x', 'y', 'z'],
- 'onStart': callback,
- 'onCycle': callback,
- 'onComplete': callback
- });
- deepEqual(actual, ['axyz', ['b', 'x', 'y', 'z'], 'cxyz', undefined, undefined]);
- equal('4' in actual, false);
- equal(callbacks[0].length, 1);
- equal(callbacks[0][0].target, 'a');
- deepEqual(callbacks[0][0].currentTarget, object);
- equal(callbacks[0][0].type, 'start');
- equal(callbacks[1][0].type, 'cycle');
- equal(callbacks[5][0].type, 'complete');
- });
- test('supports queuing when passing an ' + key, function() {
- var lengths = [];
- var actual = Benchmark.invoke(object, {
- 'name': 'concat',
- 'queued': true,
- 'args': 'x',
- 'onCycle': function() {
- lengths.push(object.length);
- }
- });
- deepEqual(lengths, [5, 4, 3, 2]);
- deepEqual(actual, ['ax', ['b', 'x'], 'cx', undefined, undefined]);
- });
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.join');
- (function() {
- var objects = {
- 'array': ['a', 'b', ''],
- 'array-like-object': { '0': 'a', '1': 'b', '2': '', 'length': 4 },
- 'object': { 'a': '0', 'b': '1', '': '2' }
- };
- objects.array.length = 4;
- forOwn(objects, function(object, key) {
- test('joins correctly using the default separator when passing an ' + key, function() {
- equal(Benchmark.join(object), key == 'object' ? 'a: 0,b: 1,: 2' : 'a,b,');
- });
- test('joins correctly using a custom separator when passing an ' + key, function() {
- equal(Benchmark.join(object, '+', '@'), key == 'object' ? 'a@0+b@1+@2' : 'a+b+');
- });
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.map');
- (function() {
- var objects = {
- 'array': ['a', 'b', 'c', ''],
- 'array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 }
- };
- objects.array.length = 5;
- forOwn(objects, function(object, key) {
- test('passes the correct arguments when passing an ' + key, function() {
- var args;
- Benchmark.map(object, function() {
- args || (args = slice.call(arguments));
- });
- deepEqual(args, ['a', 0, object]);
- });
- test('produces the correct result when passing an ' + key, function() {
- var actual = Benchmark.map(object, function(value, index) {
- return value + index;
- });
- deepEqual(actual, ['a0', 'b1', 'c2', '3', undefined]);
- equal('4' in actual, false);
- });
- test('produces an array of the correct length for sparse ' + key + 's', function() {
- equal(Benchmark.map(object, function() { }).length, 5);
- });
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.pluck');
- (function() {
- var objects = {
- 'array': [{ '_': 'a' }, { '_': 'b' }, { '_': 'c' }, null],
- 'array-like-object': { '0': { '_': 'a' }, '1': { '_': 'b' }, '2': { '_': 'c' }, '3': null, 'length': 5 }
- };
- objects.array.length = 5;
- forOwn(objects, function(object, key) {
- test('produces the correct result when passing an ' + key, function() {
- var actual = Benchmark.pluck(object, '_');
- deepEqual(actual, ['a', 'b', 'c', undefined, undefined]);
- equal('4' in actual, false);
- });
- test('produces the correct result for non-existent keys when passing an ' + key, function() {
- var actual = Benchmark.pluck(object, 'non-existent');
- deepEqual(actual, [undefined, undefined, undefined, undefined, undefined]);
- equal('4' in actual, false);
- });
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.reduce');
- (function() {
- var objects = {
- 'array': ['b', 'c', ''],
- 'array-like-object': { '0': 'b', '1': 'c', '2': '', 'length': 4 }
- };
- objects.array.length = 4;
- forOwn(objects, function(object, key) {
- test('passes the correct arguments when passing an ' + key, function() {
- var args;
- Benchmark.reduce(object, function() {
- args || (args = slice.call(arguments));
- }, 'a');
- deepEqual(args, ['a', 'b', 0, object]);
- });
- test('accumulates correctly when passing an ' + key, function() {
- var actual = Benchmark.reduce(object, function(string, value) {
- return string + value;
- }, 'a');
- equal(actual, 'abc');
- });
- test('handles arguments with no initial value correctly when passing an ' + key, function() {
- var args;
- Benchmark.reduce(object, function() {
- args || (args = slice.call(arguments));
- });
- deepEqual(args, ['b', 'c', 1, object]);
- });
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark#clone');
- (function() {
- var bench = Benchmark(function() { this.count += 0; }).run();
- test('produces the correct result passing no arguments', function() {
- var clone = bench.clone();
- deepEqual(clone, bench);
- ok(clone.stats != bench.stats && clone.times != bench.times && clone.options != bench.options);
- });
- test('produces the correct result passing a data object', function() {
- var clone = bench.clone({ 'fn': '', 'name': 'foo' });
- ok(clone.fn === '' && clone.options.fn === '');
- ok(clone.name == 'foo' && clone.options.name == 'foo');
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark#run');
- (function() {
- var data = { 'onComplete': 0, 'onCycle': 0, 'onStart': 0 };
- var bench = Benchmark({
- 'fn': function() {
- this.count += 0;
- },
- 'onStart': function() {
- data.onStart++;
- },
- 'onComplete': function() {
- data.onComplete++;
- }
- })
- .run();
- test('onXYZ callbacks should not be triggered by internal benchmark clones', function() {
- equal(data.onStart, 1);
- equal(data.onComplete, 1);
- });
- }());
- /*--------------------------------------------------------------------------*/
- forOwn({
- 'Benchmark': Benchmark,
- 'Benchmark.Suite': Benchmark.Suite
- },
- function(Constructor, namespace) {
- QUnit.module(namespace + '#emit');
- (function() {
- test('emits passed arguments', function() {
- var args,
- object = Constructor();
- object.on('args', function() { args = slice.call(arguments, 1); });
- object.emit('args', 'a', 'b', 'c');
- deepEqual(args, ['a', 'b', 'c']);
- });
- test('emits with no listeners', function() {
- var event = Benchmark.Event('empty'),
- object = Constructor();
- object.emit(event);
- equal(event.cancelled, false);
- });
- test('emits with an event type of "toString"', function() {
- var event = Benchmark.Event('toString'),
- object = Constructor();
- object.emit(event);
- equal(event.cancelled, false);
- });
- test('returns the last listeners returned value', function() {
- var event = Benchmark.Event('result'),
- object = Constructor();
- object.on('result', function() { return 'x'; });
- object.on('result', function() { return 'y'; });
- equal(object.emit(event), 'y');
- });
- test('aborts the emitters listener iteration when `event.aborted` is `true`', function() {
- var event = Benchmark.Event('aborted'),
- object = Constructor();
- object.on('aborted', function(event) {
- event.aborted = true;
- return false;
- });
- object.on('aborted', function(event) {
- // should not get here
- event.aborted = false;
- return true;
- });
- equal(object.emit(event), false);
- equal(event.aborted, true);
- });
- test('cancels the event if a listener explicitly returns `false`', function() {
- var event = Benchmark.Event('cancel'),
- object = Constructor();
- object.on('cancel', function() { return false; });
- object.on('cancel', function() { return true; });
- object.emit(event);
- equal(event.cancelled, true);
- });
- test('uses a shallow clone of the listeners when emitting', function() {
- var event,
- listener2 = function(eventObject) { eventObject.listener2 = true },
- object = Constructor();
- object.on('shallowclone', function(eventObject) {
- event = eventObject;
- object.off(event.type, listener2);
- })
- .on('shallowclone', listener2)
- .emit('shallowclone');
- ok(event.listener2);
- });
- test('emits a custom event object', function() {
- var event = Benchmark.Event('custom'),
- object = Constructor();
- object.on('custom', function(eventObject) { eventObject.touched = true; });
- object.emit(event);
- ok(event.touched);
- });
- test('sets `event.result` correctly', function() {
- var event = Benchmark.Event('result'),
- object = Constructor();
- object.on('result', function() { return 'x'; });
- object.emit(event);
- equal(event.result, 'x');
- });
- test('sets `event.type` correctly', function() {
- var event,
- object = Constructor();
- object.on('type', function(eventObj) {
- event = eventObj;
- });
- object.emit('type');
- equal(event.type, 'type');
- });
- }());
- /*------------------------------------------------------------------------*/
- QUnit.module(namespace + '#listeners');
- (function() {
- test('returns the correct listeners', function() {
- var listener = function() { },
- object = Constructor();
- object.on('x', listener);
- deepEqual(object.listeners('x'), [listener]);
- });
- test('returns an array and initializes previously uninitialized listeners', function() {
- var object = Constructor();
- deepEqual(object.listeners('x'), []);
- deepEqual(object.events, { 'x': [] });
- });
- }());
- /*------------------------------------------------------------------------*/
- QUnit.module(namespace + '#off');
- (function() {
- test('returns the benchmark', function() {
- var listener = function() { },
- object = Constructor();
- object.on('x', listener);
- equal(object.off('x', listener), object);
- });
- test('will ignore inherited properties of the event cache', function() {
- var Dummy = function() { },
- listener = function() { },
- object = Constructor();
- Dummy.prototype.x = [listener];
- object.events = new Dummy;
- object.off('x', listener);
- deepEqual(object.events.x, [listener]);
- });
- test('handles an event type and listener', function() {
- var listener = function() { },
- object = Constructor();
- object.on('x', listener);
- object.off('x', listener);
- deepEqual(object.events.x, []);
- });
- test('handles unregistering duplicate listeners', function() {
- var listener = function() { },
- object = Constructor();
- object.on('x', listener);
- object.on('x', listener);
- var events = object.events;
- object.off('x', listener);
- deepEqual(events.x, [listener]);
- object.off('x', listener);
- deepEqual(events.x, []);
- });
- test('handles a non-registered listener', function() {
- var object = Constructor();
- object.off('x', function() { });
- equal(object.events, undefined);
- });
- test('handles space separated event type and listener', function() {
- var listener = function() { },
- object = Constructor();
- object.on('x', listener);
- object.on('y', listener);
- var events = object.events;
- object.off('x y', listener);
- deepEqual(events.x, []);
- deepEqual(events.y, []);
- });
- test('handles space separated event type and no listener', function() {
- var listener1 = function() { },
- listener2 = function() { },
- object = Constructor();
- object.on('x', listener1);
- object.on('y', listener2);
- var events = object.events;
- object.off('x y');
- deepEqual(events.x, []);
- deepEqual(events.y, []);
- });
- test('handles no arguments', function() {
- var listener1 = function() { },
- listener2 = function() { },
- listener3 = function() { },
- object = Constructor();
- object.on('x', listener1);
- object.on('y', listener2);
- object.on('z', listener3);
- var events = object.events;
- object.off();
- deepEqual(events.x, []);
- deepEqual(events.y, []);
- deepEqual(events.z, []);
- });
- }());
- /*------------------------------------------------------------------------*/
- QUnit.module(namespace + '#on');
- (function() {
- test('returns the benchmark', function() {
- var listener = function() { },
- object = Constructor();
- equal(object.on('x', listener), object);
- });
- test('will ignore inherited properties of the event cache', function() {
- var Dummy = function() { },
- listener1 = function() { },
- listener2 = function() { },
- object = Constructor();
- Dummy.prototype.x = [listener1];
- object.events = new Dummy;
- object.on('x', listener2);
- deepEqual(object.events.x, [listener2]);
- });
- test('handles an event type and listener', function() {
- var listener = function() { },
- object = Constructor();
- object.on('x', listener);
- deepEqual(object.events.x, [listener]);
- });
- test('handles registering duplicate listeners', function() {
- var listener = function() { },
- object = Constructor();
- object.on('x', listener);
- object.on('x', listener);
- deepEqual(object.events.x, [listener, listener]);
- });
- test('handles space separated event type and listener', function() {
- var listener = function() { },
- object = Constructor();
- object.on('x y', listener);
- var events = object.events;
- deepEqual(events.x, [listener]);
- deepEqual(events.y, [listener]);
- });
- }());
- });
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite#abort');
- (function() {
- test('igores abort calls when the suite isn\'t running', function() {
- var fired = false;
- var suite = Benchmark.Suite('suite', {
- 'onAbort': function() { fired = true; }
- });
- suite.add('foo', function() { });
- suite.abort();
- equal(fired, false);
- });
- test('ignores abort calls from `Benchmark.Suite#reset` when the suite isn\'t running', function() {
- var fired = false;
- var suite = Benchmark.Suite('suite', {
- 'onAbort': function() { fired = true; }
- });
- suite.add('foo', function() { });
- suite.reset();
- equal(fired, false);
- });
- asyncTest('emits an abort event when running', function() {
- var fired = false;
- Benchmark.Suite({
- 'onAbort': function() { fired = true; }
- })
- .on('start', function() {
- this.abort();
- })
- .on('complete', function() {
- ok(fired);
- QUnit.start();
- })
- .add(function(){ })
- .run({ 'async': true });
- });
- asyncTest('emits an abort event after calling `Benchmark.Suite#reset`', function() {
- var fired = false;
- Benchmark.Suite({
- 'onAbort': function() { fired = true; }
- })
- .on('start', function() {
- this.reset();
- })
- .on('complete', function() {
- ok(fired);
- QUnit.start();
- })
- .add(function(){ })
- .run({ 'async': true });
- });
- asyncTest('should abort deferred benchmark', function() {
- var fired = false,
- suite = Benchmark.Suite();
- suite.on('complete', function() {
- equal(fired, false);
- QUnit.start();
- })
- .add('a', {
- 'defer': true,
- 'fn': function(deferred) {
- // avoid test inlining
- suite.name;
- // delay resolve
- setTimeout(function() {
- deferred.resolve();
- suite.abort();
- }, 10);
- }
- })
- .add('b', {
- 'defer': true,
- 'fn': function(deferred) {
- // avoid test inlining
- suite.name;
- // delay resolve
- setTimeout(function() {
- deferred.resolve();
- fired = true;
- }, 10);
- }
- })
- .run();
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite#concat');
- (function() {
- var args = arguments;
- test('doesn\'t treat an arguments object like an array', function() {
- var suite = Benchmark.Suite();
- deepEqual(suite.concat(args), [args]);
- });
- test('flattens array arguments', function() {
- var suite = Benchmark.Suite();
- deepEqual(suite.concat([1, 2], 3, [4, 5]), [1, 2, 3, 4, 5]);
- });
- test('supports concating sparse arrays', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[2] = 2;
- suite.length = 3;
- var actual = suite.concat(3);
- deepEqual(actual, [0, undefined, 2, 3]);
- equal('1' in actual, false);
- });
- test('supports sparse arrays as arguments', function() {
- var suite = Benchmark.Suite(),
- sparse = [];
- sparse[0] = 0;
- sparse[2] = 2;
- sparse.length = 3;
- var actual = suite.concat(sparse);
- deepEqual(actual, [0, undefined, 2]);
- equal('1' in actual, false);
- });
- test('creates a new array', function() {
- var suite = Benchmark.Suite();
- ok(suite.concat(1) !== suite);
- });
- }(1, 2, 3));
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite#reverse');
- (function() {
- test('reverses the element order', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 1;
- suite.length = 2;
- var actual = suite.reverse();
- equal(actual, suite);
- deepEqual(slice.call(actual), [1, 0]);
- });
- test('supports reversing sparse arrays', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[2] = 2;
- suite.length = 3;
- var actual = suite.reverse();
- equal(actual, suite);
- deepEqual(slice.call(actual), [2, undefined, 0]);
- equal('1' in actual, false);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite#shift');
- (function() {
- test('removes the first element', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 1;
- suite.length = 2;
- var actual = suite.shift();
- equal(actual, 0);
- deepEqual(slice.call(suite), [1]);
- });
- test('shifts an object with no elements', function() {
- var suite = Benchmark.Suite(),
- actual = suite.shift();
- equal(actual, undefined);
- deepEqual(slice.call(suite), []);
- });
- test('should have no elements when length is 0 after shift', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite.length = 1;
- suite.shift();
- // ensure element is removed
- equal('0' in suite, false);
- equal(suite.length, 0);
- });
- test('supports shifting sparse arrays', function() {
- var suite = Benchmark.Suite();
- suite[1] = 1;
- suite[3] = 3;
- suite.length = 4;
- var actual = suite.shift();
- equal(actual, undefined);
- deepEqual(slice.call(suite), [1, undefined, 3]);
- equal('1' in suite, false);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite#slice');
- (function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 1;
- suite[2] = 2;
- suite[3] = 3;
- suite.length = 4;
- test('works with no arguments', function() {
- var actual = suite.slice();
- deepEqual(actual, [0, 1, 2, 3]);
- ok(suite !== actual);
- });
- test('works with positive `start` argument', function() {
- var actual = suite.slice(2);
- deepEqual(actual, [2, 3]);
- ok(suite !== actual);
- });
- test('works with positive `start` and `end` arguments', function() {
- var actual = suite.slice(1, 3);
- deepEqual(actual, [1, 2]);
- ok(suite !== actual);
- });
- test('works with `end` values exceeding length', function() {
- var actual = suite.slice(1, 10);
- deepEqual(actual, [1, 2, 3]);
- ok(suite !== actual);
- });
- test('works with negative `start` and `end` arguments', function() {
- var actual = suite.slice(-3, -1);
- deepEqual(actual, [1, 2]);
- ok(suite !== actual);
- });
- test('works with an extreme negative `end` value', function() {
- var actual = suite.slice(1, -10);
- deepEqual(actual, []);
- equal('-1' in actual, false);
- ok(suite !== actual);
- });
- test('supports slicing sparse arrays', function() {
- var sparse = Benchmark.Suite();
- sparse[1] = 1;
- sparse[3] = 3;
- sparse.length = 4;
- var actual = sparse.slice(0, 2);
- deepEqual(actual, [undefined, 1]);
- equal('0' in actual, false);
- actual = sparse.slice(1);
- deepEqual(actual, [1, undefined, 3]);
- equal('1' in actual, false);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite#splice');
- (function() {
- test('works with no arguments', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite.length = 1;
- var actual = suite.splice();
- deepEqual(actual, []);
- deepEqual(slice.call(suite), [0]);
- });
- test('works with only the `start` argument', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 1;
- suite.length = 2;
- var actual = suite.splice(1);
- deepEqual(actual, [1]);
- deepEqual(slice.call(suite), [0]);
- });
- test('should have no elements when length is 0 after splice', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite.length = 1
- suite.splice(0, 1);
- // ensure element is removed
- equal('0' in suite, false);
- equal(suite.length, 0);
- });
- test('works with positive `start` argument', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 3;
- suite.length = 2;
- var actual = suite.splice(1, 0, 1, 2);
- deepEqual(actual, []);
- deepEqual(slice.call(suite), [0, 1, 2, 3]);
- });
- test('works with positive `start` and `deleteCount` arguments', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 3;
- suite.length = 2;
- var actual = suite.splice(1, 1, 1, 2);
- deepEqual(actual, [3]);
- deepEqual(slice.call(suite), [0, 1, 2]);
- });
- test('works with `deleteCount` values exceeding length', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 3;
- suite.length = 2;
- var actual = suite.splice(1, 10, 1, 2);
- deepEqual(actual, [3]);
- deepEqual(slice.call(suite), [0, 1, 2]);
- });
- test('works with negative `start` and `deleteCount` arguments', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 3;
- suite.length = 2;
- var actual = suite.splice(-1, -1, 1, 2);
- deepEqual(actual, []);
- deepEqual(slice.call(suite), [0, 1, 2, 3]);
- });
- test('works with an extreme negative `deleteCount` value', function() {
- var suite = Benchmark.Suite();
- suite[0] = 0;
- suite[1] = 3;
- suite.length = 2;
- var actual = suite.splice(0, -10, 1, 2);
- deepEqual(actual, []);
- deepEqual(slice.call(suite), [1, 2, 0, 3]);
- });
- test('supports splicing sparse arrays', function() {
- var suite = Benchmark.Suite();
- suite[1] = 1;
- suite[3] = 3;
- suite.length = 4;
- var actual = suite.splice(1, 2, 1, 2);
- deepEqual(actual, [1, undefined]);
- equal(actual.length, 2);
- deepEqual(slice.call(suite), [undefined, 1, 2, 3]);
- equal('0' in suite, false);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite#unshift');
- (function() {
- test('adds a first element', function() {
- var suite = Benchmark.Suite();
- suite[0] = 1;
- suite.length = 1;
- var actual = suite.unshift(0);
- equal(actual, 2);
- deepEqual(slice.call(suite), [0, 1]);
- });
- test('adds multiple elements to the front', function() {
- var suite = Benchmark.Suite();
- suite[0] = 3;
- suite.length = 1;
- var actual = suite.unshift(0, 1, 2);
- equal(actual, 4);
- deepEqual(slice.call(suite), [0, 1, 2, 3]);
- });
- test('supports unshifting sparse arrays', function() {
- var suite = Benchmark.Suite();
- suite[1] = 2;
- suite.length = 2;
- var actual = suite.unshift(0);
- equal(actual, 3);
- deepEqual(slice.call(suite), [0, undefined, 2]);
- equal('1' in suite, false);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite filtered results onComplete');
- (function() {
- var count = 0,
- suite = Benchmark.Suite();
- suite.add('a', function() {
- count++;
- })
- .add('b', function() {
- for (var i = 0; i < 1e6; i++) {
- count++;
- }
- })
- .add('c', function() {
- throw new TypeError;
- });
- asyncTest('should filter by fastest', function() {
- suite.on('complete', function() {
- suite.off();
- deepEqual(this.filter('fastest').pluck('name'), ['a']);
- QUnit.start();
- })
- .run({ 'async': true });
- });
- asyncTest('should filter by slowest', function() {
- suite.on('complete', function() {
- suite.off();
- deepEqual(this.filter('slowest').pluck('name'), ['b']);
- QUnit.start();
- })
- .run({ 'async': true });
- });
- asyncTest('should filter by successful', function() {
- suite.on('complete', function() {
- suite.off();
- deepEqual(this.filter('successful').pluck('name'), ['a', 'b']);
- QUnit.start();
- })
- .run({ 'async': true });
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.Suite event flow');
- (function() {
- var events = [],
- callback = function(event) { events.push(event); };
- var suite = Benchmark.Suite('suite', {
- 'onAdd': callback,
- 'onAbort': callback,
- 'onClone': callback,
- 'onError': callback,
- 'onStart': callback,
- 'onCycle': callback,
- 'onComplete': callback,
- 'onReset': callback
- })
- .add('bench', function() {
- throw null;
- }, {
- 'onAbort': callback,
- 'onClone': callback,
- 'onError': callback,
- 'onStart': callback,
- 'onCycle': callback,
- 'onComplete': callback,
- 'onReset': callback
- })
- .run({ 'async': false });
- // first Suite#onAdd
- test('should emit the suite "add" event first', function() {
- var event = events[0];
- ok(event.type == 'add' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
- });
- // next we start the Suite because no reset was needed
- test('should emit the suite "start" event', function() {
- var event = events[1];
- ok(event.type == 'start' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
- });
- // and so start the first benchmark
- test('should emit the benchmark "start" event', function() {
- var event = events[2];
- ok(event.type == 'start' && event.currentTarget.name == 'bench');
- });
- // oh no! we abort because of an error
- test('should emit the benchmark "error" event', function() {
- var event = events[3];
- ok(event.type == 'error' && event.currentTarget.name == 'bench');
- });
- // benchmark error triggered
- test('should emit the benchmark "abort" event', function() {
- var event = events[4];
- ok(event.type == 'abort' && event.currentTarget.name == 'bench');
- });
- // we reset the benchmark as part of the abort
- test('should emit the benchmark "reset" event', function() {
- var event = events[5];
- ok(event.type == 'reset' && event.currentTarget.name == 'bench');
- });
- // benchmark is cycle is finished
- test('should emit the benchmark "cycle" event', function() {
- var event = events[6];
- ok(event.type == 'cycle' && event.currentTarget.name == 'bench');
- });
- // benchmark is complete
- test('should emit the benchmark "complete" event', function() {
- var event = events[7];
- ok(event.type == 'complete' && event.currentTarget.name == 'bench');
- });
- // the benchmark error triggers a Suite error
- test('should emit the suite "error" event', function() {
- var event = events[8];
- ok(event.type == 'error' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
- });
- // the Suite cycle finishes
- test('should emit the suite "cycle" event', function() {
- var event = events[9];
- ok(event.type == 'cycle' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
- });
- // the Suite completes
- test('finally it should emit the suite "complete" event', function() {
- var event = events[10];
- ok(event.type == 'complete' && event.currentTarget.name == 'suite' && event.target.name == 'bench');
- });
- test('emitted all expected events', function() {
- ok(events.length == 11);
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Deferred benchmarks');
- (function() {
- asyncTest('should run a deferred benchmark correctly', function() {
- Benchmark(function(deferred) {
- setTimeout(function() { deferred.resolve(); }, 1e3);
- }, {
- 'defer': true,
- 'onComplete': function() {
- equal(this.hz.toFixed(0), 1);
- QUnit.start();
- }
- })
- .run();
- });
- asyncTest('should run with string values for "fn", "setup", and "teardown"', function() {
- Benchmark({
- 'defer': true,
- 'setup': 'var x = [3, 2, 1];',
- 'fn': 'setTimeout(function() { x.sort(); deferred.resolve(); }, 10);',
- 'teardown': 'x.length = 0;',
- 'onComplete': function() {
- ok(true);
- QUnit.start();
- }
- })
- .run();
- });
- asyncTest('should run recursively', function() {
- Benchmark({
- 'defer': true,
- 'setup': 'var x = [3, 2, 1];',
- 'fn': 'for (var i = 0; i < 100; i++) x[ i % 2 ? "sort" : "reverse" ](); deferred.resolve();',
- 'teardown': 'x.length = 0;',
- 'onComplete': function() {
- ok(true);
- QUnit.start();
- }
- })
- .run();
- });
- asyncTest('should execute "setup", "fn", and "teardown" in correct order', function() {
- var fired = [];
- Benchmark({
- 'defer': true,
- 'setup': function() {
- fired.push('setup');
- },
- 'fn': function(deferred) {
- fired.push('fn');
- setTimeout(function() { deferred.resolve(); }, 10);
- },
- 'teardown': function() {
- fired.push('teardown');
- },
- 'onComplete': function() {
- var actual = fired.join().replace(/(fn,)+/g, '$1').replace(/(setup,fn,teardown(?:,|$))+/, '$1');
- equal(actual, 'setup,fn,teardown');
- QUnit.start();
- }
- })
- .run();
- });
- }());
- /*--------------------------------------------------------------------------*/
- QUnit.module('Benchmark.deepClone');
- (function() {
- asyncTest('avoids call stack limits', function() {
- var result,
- count = 0,
- object = {},
- recurse = function() { count++; recurse(); };
- setTimeout(function() {
- ok(result, 'avoids call stack limits (stack limit is ' + (count - 1) + ')');
- QUnit.start();
- }, 15);
- if (toString.call(window.java) == '[object JavaPackage]') {
- // Java throws uncatchable errors on call stack overflows, so to avoid
- // them I chose a number higher than Rhino's call stack limit without
- // dynamically testing for the actual limit
- count = 3e3;
- } else {
- try { recurse(); } catch(e) { }
- }
- // exceed limit
- count++;
- for (var i = 0, sub = object; i <= count; i++) {
- sub = sub[i] = {};
- }
- try {
- for (var i = 0, sub = Benchmark.deepClone(object); sub = sub[i]; i++) { }
- result = --i == count;
- } catch(e) { }
- });
- }());
- /*--------------------------------------------------------------------------*/
- // explicitly call `QUnit.start()` for Narwhal, Rhino, and RingoJS
- if (!window.document) {
- QUnit.start();
- }
- }(typeof global == 'object' && global || this));
|