Files
lodash/vendor/qunit-clib/qunit-clib.js
2013-10-24 09:09:18 -07:00

341 lines
10 KiB
JavaScript

/*!
* QUnit CLI Boilerplate v1.3.0
* Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/>
* Based on a gist by Jörn Zaefferer <https://gist.github.com/722381>
* Available under MIT license <http://mths.be/mit>
*/
;(function(root) {
'use strict';
/** Detect free variable `exports` */
var freeExports = typeof exports == 'object' && exports;
/** Detect free variable `global`, from Node.js or Browserified code, and use it as `root` */
var freeGlobal = typeof global == 'object' && global;
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
root = freeGlobal;
}
/*--------------------------------------------------------------------------*/
/**
* Installs the CLI boilerplate additions on the given `context` object.
*
* @memberOf exports
* @param {Object} context The context object.
*/
function runInContext(context) {
// exit early if no `context` is provided or if `QUnit` does not exist
if (!context || !context.QUnit) {
return;
}
/**
* Schedules timer-based callbacks.
*
* @private
* @param {Function|string} fn The function to call.
* @param {number} delay The number of milliseconds to delay the `fn` call.
* @param [arg1, arg2, ...] Arguments to invoke `fn` with.
* @param {boolean} repeated A flag to specify whether `fn` is called repeatedly.
* @returns {number} The the ID of the timeout.
*/
function schedule(fn, delay, args, repeated) {
// Rhino 1.7RC4 will error assigning `task` below
// https://bugzilla.mozilla.org/show_bug.cgi?id=775566
var task = ids[++counter] = new JavaAdapter(java.util.TimerTask, {
'run': function() {
fn.apply(context, args);
}
});
// support non-functions
if (typeof fn != 'function') {
fn = (function(code) {
code = String(code);
return function() { eval(code); };
}(fn));
}
// used by setInterval
if (repeated) {
timer.schedule(task, delay, delay);
}
// used by setTimeout
else {
timer.schedule(task, delay);
}
return counter;
}
/**
* Clears the delay set by `setInterval` or `setTimeout`.
*
* @memberOf context
* @param {number} id The ID of the timeout to be cleared.
*/
function clearTimer(id) {
if (ids[id]) {
ids[id].cancel();
timer.purge();
delete ids[id];
}
}
/**
* Executes a code snippet or function repeatedly, with a delay between each call.
*
* @memberOf context
* @param {Function|string} fn The function to call or string to evaluate.
* @param {number} delay The number of milliseconds to delay each `fn` call.
* @param [arg1, arg2, ...] Arguments to invoke `fn` with.
* @returns {number} The the ID of the timeout.
*/
function setInterval(fn, delay) {
return schedule(fn, delay, slice.call(arguments, 2), true);
}
/**
* Executes a code snippet or a function after specified delay.
*
* @memberOf context
* @param {Function|string} fn The function to call or string to evaluate.
* @param {number} delay The number of milliseconds to delay the `fn` call.
* @param [arg1, arg2, ...] Arguments to invoke `fn` with.
* @returns {number} The the ID of the timeout.
*/
function setTimeout(fn, delay) {
return schedule(fn, delay, slice.call(arguments, 2));
}
/*------------------------------------------------------------------------*/
/** Used to report the test module for failing tests */
var moduleName,
modulePrinted;
/** Add `console.log()` support for Narwhal, Rhino, and RingoJS */
var console = context.console || (context.console = { 'log': context.print });
/** Used as a horizontal rule in console output */
var hr = '----------------------------------------';
/** Used by `logInline` to clear previously logged messages */
var prevLine = '';
/** Shorten `context.QUnit.QUnit` to `context.QUnit` */
var QUnit = context.QUnit = context.QUnit.QUnit || context.QUnit;
/**
* Logs an inline message to standard output.
*
* @private
* @param {string} text The text to log.
*/
var logInline = (function() {
// exit early if not Node.js
if (!(typeof process == 'object' && process &&
process.on && process.stdout && process.platform != 'win32')) {
return function() {};
}
// cleanup any inline logs when exited via `ctrl+c`
process.on('SIGINT', function() {
logInline('');
process.exit();
});
return function(text) {
var blankLine = Array(prevLine.length + 1).join(' ');
if (text.length > hr.length) {
text = text.slice(0, hr.length - 3) + '...';
}
prevLine = text;
process.stdout.write(text + blankLine.slice(text.length) + '\r');
}
}());
/**
* A logging callback triggered when all testing is completed.
*
* @memberOf QUnit
* @param {Object} details An object with properties `failed`, `passed`, `runtime`, and `total`.
*/
QUnit.done(function() {
var ran;
return function(details) {
// stop `asyncTest()` from erroneously calling `done()` twice in
// environments w/o timeouts
if (ran) {
return;
}
ran = true;
logInline('');
console.log(hr);
console.log(' PASS: ' + details.passed + ' FAIL: ' + details.failed + ' TOTAL: ' + details.total);
console.log(' Finished in ' + details.runtime + ' milliseconds.');
console.log(hr);
// exit out of Node.js or PhantomJS
try {
var process = context.process || context.phantom;
if (details.failed) {
process.exit(1);
} else {
process.exit(0);
}
} catch(e) { }
// exit out of Narwhal, Rhino, or RingoJS
try {
if (details.failed) {
java.lang.System.exit(1);
} else {
quit();
}
} catch(e) { }
};
}());
/**
* A logging callback triggered after every assertion.
*
* @memberOf QUnit
* @param {Object} details An object with properties `actual`, `expected`, `message`, and `result`.
*/
QUnit.log(function(details) {
var expected = details.expected,
result = details.result,
type = typeof expected != 'undefined' ? 'EQ' : 'OK';
var assertion = [
result ? 'PASS' : 'FAIL',
type,
details.message || 'ok'
];
if (!result && type == 'EQ') {
assertion.push('Expected: ' + expected + ', Actual: ' + details.actual);
}
QUnit.config.testStats.assertions.push(assertion.join(' | '));
});
/**
* A logging callback triggered at the start of every test module.
*
* @memberOf QUnit
* @param {Object} details An object with property `name`.
*/
QUnit.moduleStart(function(details) {
var newModuleName = details.name;
if (moduleName != newModuleName) {
moduleName = newModuleName;
modulePrinted = false;
}
});
/**
* Converts an object into a string representation.
*
* @memberOf QUnit
* @type Function
* @param {Object} object The object to stringify.
* @returns {string} The result string.
*/
QUnit.jsDump.parsers.object = (function() {
var func = QUnit.jsDump.parsers.object;
return function(object) {
// fork to support Rhino's error objects
if (typeof object.rhinoException == 'object') {
return object.name +
' { message: "' + object.message +
'", fileName: "' + object.fileName +
'", lineNumber: ' + object.lineNumber + ' }';
}
return func(object);
};
}());
/**
* A logging callback triggered after a test is completed.
*
* @memberOf QUnit
* @param {Object} details An object with properties `failed`, `name`, `passed`, and `total`.
*/
QUnit.testDone(function(details) {
var assertions = QUnit.config.testStats.assertions,
testName = details.name;
if (details.failed > 0) {
logInline('');
if (!modulePrinted) {
modulePrinted = true;
console.log(hr);
console.log(moduleName);
console.log(hr);
}
console.log(' FAIL - '+ testName);
assertions.forEach(function(value) {
console.log(' ' + value);
});
} else {
logInline('Testing ' + moduleName + '...');
}
assertions.length = 0;
});
/**
* An object used to hold information about the current running test.
*
* @memberOf QUnit.config
* @type Object
*/
QUnit.config.testStats = {
/**
* An array of test summaries.
*
* @memberOf QUnit.config.testStats
* @type Array
*/
'assertions': []
};
/*------------------------------------------------------------------------*/
// Timeout fallbacks based on the work of Andrea Giammarchi and Weston C.
// https://github.com/WebReflection/wru/blob/master/src/rhinoTimers.js
// http://stackoverflow.com/questions/2261705/how-to-run-a-javascript-function-asynchronously-without-using-settimeout
try {
var counter = 0,
ids = {},
slice = Array.prototype.slice,
timer = new java.util.Timer;
context.clearInterval =
context.clearTimeout = clearTimer;
context.setInterval = setInterval;
context.setTimeout = setTimeout;
} catch(e) { }
// expose shortcuts
// exclude `module` because some environments have it as a built-in object
('asyncTest deepEqual equal equals expect notDeepEqual notEqual notStrictEqual ' +
'ok raises same start stop strictEqual test throws').replace(/\S+/g, function(methodName) {
context[methodName] = QUnit[methodName];
});
// must call `QUnit.start()` in the test file if not loaded in a browser
if (!context.document || context.phantom) {
QUnit.config.autostart = false;
QUnit.init();
}
}
/*--------------------------------------------------------------------------*/
// expose QUnit CLIB
if (freeExports && !freeExports.nodeType) {
freeExports.runInContext = runInContext;
} else {
runInContext(root);
}
}(this));