blob: 501545d002aa69905fd2ae4a607b2efd146a8d6d [file] [log] [blame]
/**
* Helper for JSHint-tests.
* Export itself as function in setup.testhelper to
* prevent expresso to use it as test...
*
* Use it with method chaining, so you get something like
*
* var TestRun = require("./testhelper").setup.testRun;
*
* TestRun(test, name)
* .addError(line, errorMessage)
* .test(source, options);
*
* TestRun(test, name)
* test: nodeunit test object
* name: optional. name of the test run
* with a name, it's easier to identify a test run
*
* .addError(line, errorMessage)
* line: line of the error message
* errorMessage: the message of the reported error
*
* .test(source, options)
* starts the test run
* source: source of the test file
* options: optional. the options for jshint
*/
/*jshint node: true, eqnull: true*/
var JSHINT = require('../../../src/stable/jshint.js').JSHINT;
if (exports.setup === undefined || exports.setup === null) {
exports.setup = {};
}
exports.setup.testRun = function (test, name) {
var initCounter = 0, runCounter = 0, seq = 0, checked = [], definedErrors = [];
var helperObj = {
addError: function (line, message, extras) {
definedErrors.push({
line: line,
message: message,
extras: extras
});
return helperObj;
},
test: function (source, options, globals) {
var ret = !!JSHINT(source, options, globals);
var errors = JSHINT.errors.filter(function (er) {
return er && er.id === "(error)";
});
if (errors.length === 0 && definedErrors.length === 0) {
return;
}
// filter all thrown errors
var undefinedErrors = errors.filter(function (er) {
return !definedErrors.some(function (def) {
var result = def.line === er.line &&
def.message === er.reason;
if (!result) {
return result;
}
if (def.extras) {
for (var extra in def.extras) {
if (def.extras.hasOwnProperty(extra) &&
er.hasOwnProperty(extra)) {
result = (def.extras[extra] === er[extra]);
if (!result) {
return result;
}
}
}
}
return result;
});
});
// filter all defined errors
var unthrownErrors = definedErrors.filter(function (def) {
return !errors.some(function (er) {
return def.line === er.line &&
def.message === er.reason;
});
});
// elements that only differs in line number
var wrongLineNumbers = undefinedErrors.map(function (er) {
var lines = unthrownErrors.filter(function (def) {
return def.line !== er.line &&
def.message === er.reason;
}).map(function (def) {
return def.line;
});
if (lines.length) {
return {
line: er.line,
message: er.reason,
definedIn: lines
};
}
return null;
}).filter(function (er) {
return !!er;
});
// remove undefined errors, if there is a definition with wrong line number
undefinedErrors = undefinedErrors.filter(function (er) {
return !wrongLineNumbers.some(function (def) {
return def.message === er.reason;
});
});
unthrownErrors = unthrownErrors.filter(function (er) {
return !wrongLineNumbers.some(function (def) {
return def.message === er.message;
});
});
test.ok(
undefinedErrors.length === 0 && unthrownErrors.length === 0 && wrongLineNumbers.length === 0,
(name == null ? "" : "\n TestRun: [bold]{" + name + "}") +
unthrownErrors.map(function (el, idx) {
return (idx === 0 ? "\n [yellow]{Errors defined, but not thrown by JSHINT}\n" : "") +
" [bold]{Line " + el.line + ", Char " + el.character + "} " + el.message;
}).join("\n") +
undefinedErrors.map(function (el, idx) {
return (idx === 0 ? "\n [yellow]{Errors thrown by JSHINT, but not defined in test run}\n" : "") +
" [bold]{Line " + el.line + ", Char " + el.character + "} " + el.reason;
}).join("\n") +
wrongLineNumbers.map(function (el, idx) {
return (idx === 0 ? "\n [yellow]{Errors with wrong line number}\n" : "") +
" [bold]{Line " + el.line + "} " + el.message + " [red]{not in line(s)} [bold]{" + el.definedIn.join(", ") + "}";
}).join("\n") + "\n"
);
}
};
return helperObj;
};