topical media & game development
mobile-query-three-bench-benchmark.js-tests-tests.js / js
(function(window, undefined) {
Use a single load function
var load = typeof require == 'function' ? require : window.load;
The unit testing framework
var QUnit =
window.QUnit || (
window.setTimeout || (window.addEventListener = window.setTimeout = / /),
window.QUnit = load('../vendor/qunit/qunit/qunit.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
);
/*--------------------------------------------------------------------------*/
// must explicitly use `QUnit.module` instead of `module()`
// in case we are in a CLI environment
QUnit.module('Benchmark');
test('Benchmark.platform', function() {
if (window.document) {
equal(String(Benchmark.platform), navigator.userAgent, 'default value');
} else {
ok(true, 'test skipped');
}
});
test('require("benchmark")', function() {
if (window.document && window.require) {
equal((Benchmark2 || {}).version, Benchmark.version, 'require("benchmark")');
} else {
ok(true, 'test skipped');
}
});
test('require("platform")', function() {
if (window.document && window.require) {
var bench = Benchmark2 || {},
platform = bench.platform || {};
equal(typeof platform.name, 'string', 'required("platform")');
} else {
ok(true, 'test skipped');
}
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark constructor');
test('basic', function() {
var bench = Benchmark(function() { });
ok(bench instanceof Benchmark, 'creation without `new` operator');
bench = Benchmark({ 'name': 'foo', 'fn': function() { } });
ok(bench.fn && bench.name == 'foo', 'arguments (options)');
bench = Benchmark('foo', function() { });
ok(bench.fn && bench.name == 'foo', 'arguments (name, function)');
bench = Benchmark('foo', { 'fn': function() { } });
ok(bench.fn && bench.name == 'foo', 'arguments (name, options)');
bench = Benchmark('foo', function() { }, { 'id': 'bar' });
ok(bench.fn && bench.name == 'foo' && bench.id == 'bar', 'arguments (name, function, options)');
});
test('empty', function() {
var options = Benchmark.options,
maxTime = options.maxTime;
// inits Benchmark.options.minTime
var bench = Benchmark(function() { throw ''; }).run();
options.minTime && (options.maxTime = options.minTime * 5);
bench = Benchmark(function() { }).run();
var error = bench.error;
ok(/setup\(\)/.test(bench.compiled) ? !error : error, 'error check');
bench = Benchmark({ 'fn': '' }).run();
ok(!bench.error, 'no error on explicitly empty');
options.maxTime = maxTime;
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark compiling');
test('basic', function() {
var bench = Benchmark({
'setup': function() { var a = 1; },
'fn': function() { throw a; },
'teardown': function() { a = 2; }
}).run();
var compiled = bench.compiled;
var result = /var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled);
ok(/setup\(\)/.test(compiled) ? true : result, 'compiled');
});
test('toString', 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;
var result = /var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled);
ok(/setup\(\)/.test(compiled) ? true : result, 'compiled');
});
test('as a string', function() {
var bench = Benchmark({
'setup': 'var a = 1;',
'fn': 'throw a;',
'teardown': 'a = 2;'
}).run();
var compiled = bench.compiled;
var result = /var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled);
ok(/setup\(\)/.test(compiled) ? true : result, 'compiled');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.deepClone');
test('basic', function() {
var o = { 'a': 1, 'b': '2' },
Klass = function() {},
toString = {}.toString,
result = Benchmark.deepClone(o);
Klass.prototype = { 'x': 1 };
deepEqual(result, o, 'clones simple object');
ok(result != o, 'clone isn\'t the original object');
o = { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } };
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones complex object');
o = 'x';
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones string primitive');
o = new String('x');
result = Benchmark.deepClone(o);
ok(result == 'x' && typeof result == 'object' &&
toString.call(result) == '[object String]', 'clones string object');
o = 3;
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones number primitive');
o = new Number(3);
result = Benchmark.deepClone(o);
ok(result == 3 && typeof result == 'object' &&
toString.call(result) == '[object Number]', 'clones number object');
o = false;
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones boolean primitive');
o = new Boolean(false);
result = Benchmark.deepClone(o);
ok(result == false && typeof result == 'object' &&
toString.call(result) == '[object Boolean]', 'clones boolean object');
o = null;
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones null');
o = undefined;
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones undefined');
o = [1, 'b', false];
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones array');
o = /x/gim;
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones regexp');
o = new Klass;
ok(Benchmark.deepClone(o) === o, 'Klass instance is not cloned');
ok(Benchmark.deepClone(arguments) === arguments, 'arguments object is not cloned');
ok(Benchmark.deepClone(Klass) === Klass, 'function is not cloned');
Klass.prototype.deepClone = function() {
return new Klass;
};
result = Benchmark.deepClone(o);
ok(result != o && result instanceof Klass, 'clones using Klass#deepClone');
if (window.document) {
ok(Benchmark.deepClone(document.body) === document.body, 'DOM element is not cloned');
} else {
ok(true, 'test skipped');
}
});
test('edge', function() {
var result,
getDescriptor = Object.getOwnPropertyDescriptor,
setDescriptor = Object.defineProperty,
toString = {}.toString;
var has = {
'descriptors' : !!(function() {
try {
var o = {};
return (setDescriptor(o, o, o), 'value' in getDescriptor(o, o));
} catch(e) { }
}())
};
var o = {
'constructor': 1,
'hasOwnProperty': 2,
'isPrototypeOf': 3,
'propertyIsEnumerable': 4,
'toLocaleString': 5,
'toString': 6,
'valueOf': 7
};
function createCircularObject() {
var result = {
'foo': { 'b': { 'foo': { 'c': { } } } },
'bar': { }
};
result.foo.b.foo.c.foo = result;
result.bar.b = result.foo.b;
return result;
}
result = Benchmark.deepClone(o);
deepEqual(result, o, 'clones problem JScript props');
o = new String('x');
o.x = 1;
result = Benchmark.deepClone(o);
ok(result == 'x' && typeof result == 'object' && result.x === 1 &&
toString.call(result) == '[object String]', 'clones string object with custom property');
o = createCircularObject();
result = Benchmark.deepClone(o);
ok(result.bar.b === result.foo.b && result === result.foo.b.foo.c.foo &&
result !== o, 'clones objects with circular references');
if (Object.preventExtensions) {
o = Object.preventExtensions(createCircularObject());
Object.preventExtensions(o.bar.b);
result = Benchmark.deepClone(o);
ok(result.bar.b === result.foo.b && result === result.foo.b.foo.c.foo &&
result !== o, 'clones non-extensible objects with circular references');
} else {
ok(true, 'test skipped');
}
if (Object.seal) {
o = Object.seal(createCircularObject());
Object.seal(o.bar.b);
result = Benchmark.deepClone(o);
ok(result.bar.b === result.foo.b && result === result.foo.b.foo.c.foo &&
result !== o, 'clones sealed objects with circular references');
} else {
ok(true, 'test skipped');
}
if (Object.freeze) {
o = Object.freeze(createCircularObject());
Object.freeze(o.bar.b);
result = Benchmark.deepClone(o);
ok(result.bar.b === result.foo.b && result === result.foo.b.foo.c.foo &&
result !== o, 'clones frozen objects with circular references');
} else {
ok(true, 'test skipped');
}
if (has.descriptors) {
var accessor;
o = setDescriptor({}, 'foo', {
'configurable': true,
'value': setDescriptor({}, 'b', {
'writable': true,
'value': setDescriptor({}, 'foo', {
'get': function() { return accessor; },
'set': function(value) { accessor = value; }
})
})
});
setDescriptor(o, 'bar', { 'value': {} });
o.foo.b.foo = { 'c': o };
o.bar.b = o.foo.b;
result = Benchmark.deepClone(o);
var descriptor;
ok(result !== o &&
result.bar.b === result.foo.b &&
result !== result.foo.b.foo.c.foo &&
(descriptor = getDescriptor(result, 'foo')) &&
descriptor.configurable && !(descriptor.enumerable && descriptor.writable) &&
(descriptor = getDescriptor(result.foo, 'b')) &&
descriptor.writable && !(descriptor.configurable && descriptor.enumerable) &&
(descriptor = getDescriptor(result.foo.b, 'foo')) &&
descriptor.get && descriptor.set &&
(descriptor = getDescriptor(result.foo.b, 'foo')) &&
!(descriptor.configurable && descriptor.enumerable && descriptor.writable) &&
(descriptor = getDescriptor(result, 'bar')) &&
!(descriptor.configurable && descriptor.enumerable && descriptor.writable),
'clones objects with custom descriptors and circular references');
}
else {
ok(true, 'test skipped');
}
});
asyncTest('call stack overflow', function() {
var result,
o = {},
count = 0,
recurse = function() { count++; recurse(); },
setTimeout = window.setTimeout,
toString = {}.toString;
function fn() {
try {
for (var i = 0, sub = Benchmark.deepClone(o); sub = sub[i]; i++) { }
result = --i == count;
} catch(e) { }
ok(result, 'avoids call stack overflow (stack limit is ' + (count - 1) + ')');
QUnit.start();
}
if (setTimeout) {
setTimeout(fn, 1);
}
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 that limit
count = 3e3;
} else {
try {
recurse();
} catch(e) { }
}
count++;
for (var i = 0, sub = o; i <= count; i++) {
sub = sub[i] = {};
}
if (!setTimeout) {
fn();
}
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.each');
test('basic', function() {
var args,
o = ['a', 'b', 'c'],
values = [];
var result = Benchmark.each(o, function(value) {
args || (args = [].slice.call(arguments));
values.push(value);
});
ok(o === result, 'object returned');
deepEqual(values, ['a', 'b', 'c'], 'values');
deepEqual(args, ['a', 0, o], 'passed arguments to callback');
values.length = 0;
Benchmark.each(o, function(value, index) {
values.push(value);
return !(index == 1);
});
deepEqual(values, ['a', 'b'], 'exit early');
});
test('array-like-object', function() {
var thirdArg,
values = [],
o = { '0': 'a', '2': 'c', 'length': 3 };
Benchmark.each(o, function(value) {
values.push(value);
});
deepEqual(values, ['a', 'c'], 'sparse check');
values.length = 0;
Benchmark.each('hello', function(value, index, object) {
thirdArg = object;
values.push(value);
});
ok(thirdArg == 'hello' && typeof thirdArg == 'object', 'string passed, third callback arg');
deepEqual(values, ['h', 'e', 'l', 'l', 'o'], 'string passed, values check');
values.length = 0;
Benchmark.each('hello', function(value) {
values.push(value);
return !(value == 'e');
});
deepEqual(values, ['h', 'e'], 'string passed, exit early');
});
test('xpath snapshot', function() {
if (window.document && document.evaluate) {
var o = document.evaluate('//html', document, null, 7, null),
values = [];
Benchmark.each(o, function(value) {
values.push(value);
});
deepEqual(values, [document.documentElement], 'basic');
}
else {
ok(true, 'test skipped');
}
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.filter');
test('basic', function() {
var args,
o = ['a', 'b', 'c'];
var result = Benchmark.filter(o, function(value) {
args || (args = [].slice.call(arguments));
return value == 'b';
});
deepEqual(result, ['b'], 'basic');
deepEqual(args, ['a', 0, o], 'passed arguments to callback');
});
test('array-like-object', function() {
var count = 0,
o = { '0': 'a', '2': 'c', 'length': 3 };
var result = Benchmark.filter(o, function(value) {
count++;
return value != null;
});
deepEqual(result, ['a', 'c'], 'basic');
equal(count, 2, 'sparse check');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.forOwn');
test('basic', function() {
var args = [],
values = [],
O = function(){ var me = this; me.a = 1; me.b = 2; me.c = 3; },
o = (O.prototype.d = 4, new O);
var result = Benchmark.forOwn(o, function(value) {
if (value == 1) {
args = [].slice.call(arguments);
}
values.push(value);
});
ok(o === result, 'object returned');
deepEqual(values.sort(), [1, 2, 3], 'values');
deepEqual(args, [1, 'a', o], 'passed arguments to callback');
values.length = 0;
Benchmark.forOwn(o, function(value, key) {
values.push(value);
return !(key == 'b');
});
deepEqual(values.sort(), [1, 2], 'exit early');
});
test('enumeration', function() {
var thirdArg,
keys = [],
values = [],
Klass = function() { },
o = { 'constructor': 1, 'hasOwnProperty': 2, 'isPrototypeOf': 3, 'propertyIsEnumerable': 4, 'toLocaleString': 5, 'toString': 6, 'valueOf': 7 };
Klass.a = 1;
Klass.prototype.b = 2;
Benchmark.forOwn(o, function(value, key) {
keys.push(key);
values.push(value);
});
deepEqual(keys.sort(), ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'], 'problem JScript props, keys check');
keys.length = 0;
deepEqual(values.sort(), [1, 2, 3, 4, 5, 6, 7], 'problem JScript props, values check');
values.length = 0;
Benchmark.forOwn(o, function(value, key) {
keys.push(key);
return !(key == 'hasOwnProperty');
});
ok(keys.length < 7, 'problem JScript props, exit early during forced iteration');
keys.length = 0;
o = { 'a': 1 };
Benchmark.forOwn(o, function(value, key) {
keys.push(key);
if (key == 'a') {
o.toString = 'toString';
return false;
}
});
deepEqual(keys, ['a'], 'problem JScript props, exit early before forced iteration');
keys.length = 0;
(function(a, b, c) {
Benchmark.forOwn(arguments, function(value, key) {
keys.push(key);
values.push(value);
});
}('a', 'b', 'c'));
deepEqual(keys.sort(), ['0', '1', '2'], 'arguments object, keys check');
keys.length = 0;
deepEqual(values.sort(), ['a', 'b', 'c'], 'arguments object, values check');
values.length = 0;
(function(a, b, c) {
Benchmark.forOwn(arguments, function(value, key, object) {
values.push(value);
if (value == 'b') {
object.toString = 'toString';
return false;
}
});
}('a', 'b', 'c'));
deepEqual(values.sort(), ['a', 'b'], 'arguments object, exit early');
values.length = 0;
Benchmark.forOwn(Klass, function(value, key) {
keys.push(key);
values.push(value);
});
deepEqual(keys, ['a'], 'function passed, keys check');
keys.length = 0;
deepEqual(values, [1], 'function passed, values check');
values.length = 0;
Benchmark.forOwn(Klass.prototype, function(value, key) {
keys.push(key);
values.push(value);
});
deepEqual(keys, ['b'], 'prototype passed, keys check');
keys.length = 0;
deepEqual(values, [2], 'prototype passed, values check');
values.length = 0;
Benchmark.forOwn('hello', function(value, key, object) {
thirdArg = object;
keys.push(key);
values.push(value);
});
equal(thirdArg, 'hello', 'string passed, third callback arg');
deepEqual(keys.sort(), ['0', '1', '2', '3', '4'], 'string passed, keys check');
deepEqual(values, ['h', 'e', 'l', 'l', 'o'], 'string passed, values check');
values.length = 0;
Benchmark.forOwn('hello', function(value, key, object) {
values.push(value);
if (value == 'e') {
object.toString = 'toString';
return false;
}
});
deepEqual(values, ['h', 'e'], 'string passed, exit early');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.formatNumber');
test('basic', function() {
var num = 1e6;
equal(Benchmark.formatNumber(num), '1,000,000', 'basic');
num = 23;
equal(Benchmark.formatNumber(num), '23', 'short');
num = 1234.56;
equal(Benchmark.formatNumber(num), '1,234.56', 'decimals');
num *= -1;
equal(Benchmark.formatNumber(num), '-1,234.56', 'negatives');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.indexOf');
test('basic', function() {
var o = ['a', 'b', 'c'];
equal(Benchmark.indexOf(o, 'b'), 1, 'basic');
equal(Benchmark.indexOf(o, new String('b')), -1, 'strict');
});
test('array-like-object', function() {
var o = { '0': 'a', '2': 'c', 'length': 3 };
equal(Benchmark.indexOf(o, 'c'), 2, 'basic');
equal(Benchmark.indexOf(o, 'b'), -1, 'not found');
equal(Benchmark.indexOf(o, undefined), -1, 'sparse check');
});
test('fromIndex', function() {
var o = ['a', 'b', 'c', 'a'];
o['-1'] = 'z';
equal(Benchmark.indexOf(o, 'a', 1), 3, 'fromIndex');
equal(Benchmark.indexOf(o, 'z', -5), -1, 'extreme negative fromIndex');
var o = { '0': 'a', '2': 'c', '3': 'z', 'length': 3 };
equal(Benchmark.indexOf(o, 'z', 3), -1, 'extreme positive fromIndex');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.invoke');
test('basic', function() {
var callbacks = [],
lengths = [],
callback = function() { callbacks.push(slice.call(arguments)); },
slice = [].slice,
o = [new Array, null, new Array, new Array];
var result = Benchmark.invoke(o, 'push', 'b');
deepEqual(result, [1, undefined, 1, 1], 'return values');
result = Benchmark.pluck(o, '0');
deepEqual(result, ['b', undefined, 'b', 'b'], 'methods invoked');
Benchmark.invoke(o, {
'name': 'splice',
'args': [0, 0, 'a'],
'onStart': callback,
'onCycle': callback,
'onComplete': callback
});
ok(callbacks[0].length == 2 && callbacks[0][0].type && callbacks[0][1].push, 'passed arguments to callback');
equal(callbacks.shift()[0].type, 'start', 'onStart');
equal(callbacks.shift()[0].type, 'cycle', 'onCycle');
equal(callbacks.pop()[0].type, 'complete', 'onComplete');
});
test('queued', function() {
var lengths = [],
expected = [1, 1],
o = [new Array, new Array];
o[3] = new Array;
expected[3] = 1;
var result = Benchmark.invoke(o, {
'name': 'push',
'queued': true,
'args': 'a',
'onCycle': function() {
lengths.push(o.length);
}
});
deepEqual(lengths, [4, 3, 1], 'removed queued items');
deepEqual(result, expected, 'return values');
});
test('array-like-object', function() {
var expected = [1],
o = { '0': new Array, '2': new Array, 'length': 3 },
result = Benchmark.invoke(o, 'push', 'a');
expected[2] = 1;
deepEqual(result, expected, 'sparse check');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.join');
test('basic', function() {
var o = ['a', 'b', 'c'];
equal(Benchmark.join(o), 'a,b,c', 'default separator 1');
equal(Benchmark.join(o, '+', '@'), 'a+b+c', 'custom separator 1');
o = { 'a': 'apple', 'b': 'ball', 'c': 'cat' };
equal(Benchmark.join(o), 'a: apple,b: ball,c: cat', 'default separator 2');
equal(Benchmark.join(o, '; ', ' -> '), 'a -> apple; b -> ball; c -> cat', 'custom separator 2');
});
test('array-like-object', function() {
var o = { '0': 'a', '2': 'c', 'length': 3 };
equal(Benchmark.join(o), 'a,c', 'sparse check');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.map');
test('basic', function() {
var args,
o = ['a', 'b', 'c'];
var result = Benchmark.map(o, function(value, index) {
args || (args = [].slice.call(arguments));
return index;
});
deepEqual(result, [0, 1, 2], 'basic');
deepEqual(args, ['a', 0, o], 'passed arguments to callback');
});
test('array-like-object', function() {
var expected = [0],
o = { '0': 'a', '2': 'c', 'length': 4 },
result = Benchmark.map(o, function(value, index) { return index; });
expected[2] = 2;
expected.length = 4;
deepEqual(result, expected, 'sparse value check');
deepEqual(result.length, 4, 'sparse length check');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.pluck');
test('basic', function() {
var o = [{ 'name': 'a' }, null, { 'name': 'c' }],
result = Benchmark.pluck(o, 'name');
deepEqual(result, ['a', undefined, 'c'], 'basic');
result = Benchmark.pluck(o, 'nonexistent');
deepEqual(result, [undefined, undefined, undefined], 'undefined property');
});
test('array-like-object', function() {
var expected = ['a'],
o = { '0': { 'name': 'a' }, '2': { 'name': 'c' }, 'length': 3 },
result = Benchmark.pluck(o, 'name');
expected[2] = 'c';
deepEqual(result, expected, 'sparse check');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.reduce');
test('basic', function() {
var args,
slice = [].slice,
o = ['a', 'b', 'c'];
var result = Benchmark.reduce(o, function(string, value, index) {
args || (args = slice.call(arguments));
return string + value;
}, '');
equal(result, 'abc', 'accumulation correct');
deepEqual(args, ['', 'a', 0, o], 'passed arguments to callback');
args = null;
Benchmark.reduce(o, function() {
args || (args = slice.call(arguments));
});
deepEqual(args, ['a', 'b', 1, o], 'no initial value');
});
test('array-like-object', function() {
var o = { '0': 'a', '2': 'c', 'length': 3 };
var result = Benchmark.reduce(o, function(string, value, index) {
return string + value;
});
equal(result, 'ac', 'sparse check');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark#clone');
test('basic', function() {
var i = 0,
options = Benchmark.options,
maxTime = options.maxTime;
options.minTime && (options.maxTime = options.minTime * 5);
var bench = Benchmark(function() { i++; }).run();
options.maxTime = maxTime;
var clone = bench.clone();
deepEqual(clone, bench, 'clones properties');
ok(clone.stats != bench.stats && clone.times != bench.times && clone.options != bench.options, 'deep clones object properties');
clone = bench.clone({ 'fn': '', 'name': 'foo' });
ok(clone.fn === '' && clone.options.fn === '', 'adds custom "fn" option');
equal(clone.name, 'foo', 'adds other custom options');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark#emit');
test('event object', function() {
var args = [],
bench = Benchmark(function() {}),
event = Benchmark.Event('custom'),
listener2 = function(event) { event.listener2 = 1 };
bench.on('custom', function(event) { event.touched = 1; });
bench.emit(event);
bench.events = {};
ok(event.touched, 'emit custom event object');
bench.on('type', function(eventObj) { event = eventObj; });
bench.emit('type');
bench.events = {};
equal(event.type, 'type', 'emit event.type');
bench.on('args', function() { args = args.slice.call(arguments, 1); });
bench.emit('args', 'a', 'b', 'c');
bench.events = {};
deepEqual(args, ['a', 'b', 'c'], 'emit curried arguments');
ok(bench.emit('empty'), 'emit empty successful');
bench.on('success', function() { return 'bogus'; });
ok(bench.emit('success'), 'emit successful');
bench.on('success', function() { return false; });
ok(!bench.emit('success'), 'emit unsuccessful');
bench.events = {};
bench.on('shallowclone', function(eventObject) {
event = eventObject;
bench.removeListener(event.type, listener2);
})
.on('shallowclone', listener2)
.emit('shallowclone');
bench.events = {};
ok(event.listener2, 'emit shallow cloned listeners');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.Suite#abort');
test('basic', function() {
var fired = false;
var suite = Benchmark.Suite('suite', {
'onAbort': function() { fired = true }
})
.add('foo', function() { });
suite.abort();
ok(fired == false, 'calling abort() won\'t fire an abort event when suite isn\'t running');
fired = false;
suite.reset();
ok(fired == false, 'calling reset() won\'t fire an abort event when suite isn\'t running');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Benchmark.Suite#add');
test('event flow', function() {
var args,
pair,
thisBinding,
slice = [].slice,
callbacks = [],
callback = function() { callbacks.push([arguments, this]); };
var suite = Benchmark.Suite('suite', {
'onAdd': callback,
'onAbort': callback,
'onClone': callback,
'onError': callback,
'onStart': callback,
'onCycle': callback,
'onComplete': callback,
'onReset': callback
})
.add('foo', function() {
throw null;
}, {
'onAbort': callback,
'onClone': callback,
'onError': callback,
'onStart': callback,
'onCycle': callback,
'onComplete': callback,
'onReset': callback
})
.run({ 'async': false });
// first Suite#onAdd
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 2 && args[0].type == 'add' && thisBinding.name == 'suite' && args[1].name == 'foo', 'passed arguments to Suite#onAdd');
// next we start the Suite because no reset was needed
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 2 && args[0].type == 'start' && thisBinding.name == 'suite' && args[1].name == 'foo', 'passed arguments to Suite#onStart');
// and so start the first benchmark
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 1 && args[0].type == 'start' && thisBinding.name == 'foo', 'passed arguments to Benchmark#onStart');
// after starting we reset the benchmark
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 1 && args[0].type == 'reset' && thisBinding.name == 'foo', 'passed arguments to Benchmark#onReset');
// oh no! we abort because of an error
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 1 && args[0].type == 'abort' && thisBinding.name == 'foo', 'passed arguments to Benchmark#onAbort');
// benchmark error triggered
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 1 && args[0].type == 'error' && thisBinding.name == 'foo', 'passed arguments to Benchmark#onError');
// benchmark is cycle is finished
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 1 && args[0].type == 'cycle' && thisBinding.name == 'foo', 'passed arguments to Benchmark#onCycle');
// benchmark is complete
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 1 && args[0].type == 'complete' && thisBinding.name == 'foo', 'passed arguments to Benchmark#onComplete');
// the benchmark error triggers a Suite error
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 2 && args[0].type == 'error' && thisBinding.name == 'suite' && args[1].name == 'foo', 'passed arguments to Suite#onError');
// the Suite cycle finishes
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 2 && args[0].type == 'cycle' && thisBinding.name == 'suite' && args[1].name == 'foo', 'passed arguments to Suite#onCycle');
// the Suite completes
pair = callbacks.shift();
args = pair[0];
thisBinding = pair[1];
ok(args.length == 2 && args[0].type == 'complete' && thisBinding.name == 'suite' && args[1].name == 'foo', 'passed arguments to Suite#onComplete');
ok(callbacks.length == 0, 'all callbacks executed');
});
/*--------------------------------------------------------------------------*/
QUnit.module('Async tests');
asyncTest('Benchmark.options.defer', function() {
var options = Benchmark.options,
maxTime = options.maxTime;
options.minTime && (options.maxTime = options.minTime * 5);
Benchmark(function(deferred) {
setTimeout(function() { deferred.resolve(); }, 10);
}, {
'defer': true,
'onComplete': function() {
ok(this.cycles, 'deferred benchmark');
options.maxTime = maxTime;
QUnit.start();
}
})
.run();
});
asyncTest('Benchmark.filter', function() {
var count = 0,
options = Benchmark.options,
maxTime = options.maxTime,
suite = new Benchmark.Suite;
options.minTime && (options.maxTime = options.minTime * 5);
suite.add('a', function() {
count++;
})
.add('b', function() {
for (var i = 0; i < 1e6; i++) {
count++;
}
})
.add('c', function() {
throw new TypeError;
})
.on('complete', function() {
deepEqual(this.filter('fastest').pluck('name'), ['a'], 'by fastest');
deepEqual(this.filter('slowest').pluck('name'), ['b'], 'by slowest');
deepEqual(this.filter('successful').pluck('name'), ['a', 'b'], 'by successful');
options.maxTime = maxTime;
QUnit.start();
})
.run({ 'async': true });
});
asyncTest('Benchmark.Suite#abort', function() {
var count = -1,
fired = false;
var suite = Benchmark.Suite('foo', {
'onAbort': function() { fired = true }
})
.add('a', function() {
// empty
})
.on('start', function() {
this[++count ? 'reset' : 'abort']();
this.aborted = true;
})
.on('complete', function() {
if (count == 0) {
ok(fired == true, 'calling abort() fires an abort event when suite is running');
fired = false;
suite.run({ 'async': true });
} else {
ok(fired == true, 'calling reset() fires an abort event when suite is running');
QUnit.start();
}
});
suite.run({ 'async': true });
});
/*--------------------------------------------------------------------------*/
// explicitly call `QUnit.start()` in a CLI environment
if (!window.document) {
QUnit.start();
}
}(typeof global == 'object' && global || this));
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.