191 lines
5.0 KiB
JavaScript
191 lines
5.0 KiB
JavaScript
|
/*!
|
||
|
* Nodeunit
|
||
|
* Copyright (c) 2010 Caolan McMahon
|
||
|
* MIT Licensed
|
||
|
*
|
||
|
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
|
||
|
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
|
||
|
* Only code on that line will be removed, it's mostly to avoid requiring code
|
||
|
* that is node specific
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Module dependencies
|
||
|
*/
|
||
|
|
||
|
var assert = require('./assert'), //@REMOVE_LINE_FOR_BROWSER
|
||
|
async = require('../deps/async'); //@REMOVE_LINE_FOR_BROWSER
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Creates assertion objects representing the result of an assert call.
|
||
|
* Accepts an object or AssertionError as its argument.
|
||
|
*
|
||
|
* @param {object} obj
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
exports.assertion = function (obj) {
|
||
|
return {
|
||
|
method: obj.method || '',
|
||
|
message: obj.message || (obj.error && obj.error.message) || '',
|
||
|
error: obj.error,
|
||
|
passed: function () {
|
||
|
return !this.error;
|
||
|
},
|
||
|
failed: function () {
|
||
|
return Boolean(this.error);
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Creates an assertion list object representing a group of assertions.
|
||
|
* Accepts an array of assertion objects.
|
||
|
*
|
||
|
* @param {Array} arr
|
||
|
* @param {Number} duration
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
exports.assertionList = function (arr, duration) {
|
||
|
var that = arr || [];
|
||
|
that.failures = function () {
|
||
|
var failures = 0;
|
||
|
for (var i = 0; i < this.length; i += 1) {
|
||
|
if (this[i].failed()) {
|
||
|
failures += 1;
|
||
|
}
|
||
|
}
|
||
|
return failures;
|
||
|
};
|
||
|
that.passes = function () {
|
||
|
return that.length - that.failures();
|
||
|
};
|
||
|
that.duration = duration || 0;
|
||
|
return that;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Create a wrapper function for assert module methods. Executes a callback
|
||
|
* after it's complete with an assertion object representing the result.
|
||
|
*
|
||
|
* @param {Function} callback
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
var assertWrapper = function (callback) {
|
||
|
return function (new_method, assert_method, arity) {
|
||
|
return function () {
|
||
|
var message = arguments[arity - 1];
|
||
|
var a = exports.assertion({method: new_method, message: message});
|
||
|
try {
|
||
|
assert[assert_method].apply(null, arguments);
|
||
|
}
|
||
|
catch (e) {
|
||
|
a.error = e;
|
||
|
}
|
||
|
callback(a);
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Creates the 'test' object that gets passed to every test function.
|
||
|
* Accepts the name of the test function as its first argument, followed by
|
||
|
* the start time in ms, the options object and a callback function.
|
||
|
*
|
||
|
* @param {String} name
|
||
|
* @param {Number} start
|
||
|
* @param {Object} options
|
||
|
* @param {Function} callback
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
exports.test = function (name, start, options, callback) {
|
||
|
var expecting;
|
||
|
var a_list = [];
|
||
|
|
||
|
var wrapAssert = assertWrapper(function (a) {
|
||
|
a_list.push(a);
|
||
|
if (options.log) {
|
||
|
async.nextTick(function () {
|
||
|
options.log(a);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
var test = {
|
||
|
done: function (err) {
|
||
|
if (expecting !== undefined && expecting !== a_list.length) {
|
||
|
var e = new Error(
|
||
|
'Expected ' + expecting + ' assertions, ' +
|
||
|
a_list.length + ' ran'
|
||
|
);
|
||
|
var a1 = exports.assertion({method: 'expect', error: e});
|
||
|
a_list.push(a1);
|
||
|
if (options.log) {
|
||
|
async.nextTick(function () {
|
||
|
options.log(a1);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
if (err) {
|
||
|
var a2 = exports.assertion({error: err});
|
||
|
a_list.push(a2);
|
||
|
if (options.log) {
|
||
|
async.nextTick(function () {
|
||
|
options.log(a2);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
var end = new Date().getTime();
|
||
|
async.nextTick(function () {
|
||
|
var assertion_list = exports.assertionList(a_list, end - start);
|
||
|
options.testDone(name, assertion_list);
|
||
|
callback(null, a_list);
|
||
|
});
|
||
|
},
|
||
|
ok: wrapAssert('ok', 'ok', 2),
|
||
|
same: wrapAssert('same', 'deepEqual', 3),
|
||
|
equals: wrapAssert('equals', 'equal', 3),
|
||
|
expect: function (num) {
|
||
|
expecting = num;
|
||
|
},
|
||
|
_assertion_list: a_list
|
||
|
};
|
||
|
// add all functions from the assert module
|
||
|
for (var k in assert) {
|
||
|
if (assert.hasOwnProperty(k)) {
|
||
|
test[k] = wrapAssert(k, k, assert[k].length);
|
||
|
}
|
||
|
}
|
||
|
return test;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Ensures an options object has all callbacks, adding empty callback functions
|
||
|
* if any are missing.
|
||
|
*
|
||
|
* @param {Object} opt
|
||
|
* @return {Object}
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
exports.options = function (opt) {
|
||
|
var optionalCallback = function (name) {
|
||
|
opt[name] = opt[name] || function () {};
|
||
|
};
|
||
|
|
||
|
optionalCallback('moduleStart');
|
||
|
optionalCallback('moduleDone');
|
||
|
optionalCallback('testStart');
|
||
|
optionalCallback('testReady');
|
||
|
optionalCallback('testDone');
|
||
|
//optionalCallback('log');
|
||
|
|
||
|
// 'done' callback is not optional.
|
||
|
|
||
|
return opt;
|
||
|
};
|