blob: a99ac910b1593c9806ec01810eb353df72132e18 [file] [log] [blame]
var _ = require("underscore");
var assert = require("assert");
var fs = require("fs");
var path = require("path");
var linter = require("../../../src/next/jshint.js");
// Returns contents of a fixture.
//
// Fixture's parent directory depends on the suite's file name. For example,
// fixtures for test/unit/parser.js should be in test/fixtures/parser/<file>.js
function Fixtures(dirname, filename) {
this.dirname = dirname;
this.filename = filename;
}
Fixtures.prototype.get = function (name) {
var dir, stream;
dir = path.basename(this.filename).replace(".js", "");
stream = fs.readFileSync(path.resolve(this.dirname, "..", "fixtures", dir, name));
return stream.toString().replace(/\r\n/g, "\n");
};
// A test helper designed specifically for JSHint. It allows us to write
// tests in a declarative manner thus reducing code duplication.
function createRunner(dirname, filename) {
var fixtures = new Fixtures(dirname, filename);
function runner(test) {
var expected = [];
var helper = {
addError: function (line, code) {
expected.push({
line: line,
code: code
});
return helper;
},
addErrors: function (lines, code) {
_.each(lines, function (line) {
helper.addError(line, code);
});
return helper;
},
test: function (source, options, globals) {
var retval = linter.lint({ code: source, predefined: globals });
var errors = retval.report.getMessages();
// If the linter didn't produce any errors and we don't
// expect any, quietly return.
if (errors.length === 0 && expected.length === 0)
return;
// Otherwise get a list of unexpected errors.
var unexpected = _.reject(errors, function (err, line) {
return _.any(expected, function (exp) {
return exp.line === err.line && exp.code === err.data.code;
});
});
// And errors that were expected but not thrown by the linter.
var unthrown = _.reject(expected, function (exp) {
return _.any(errors, function (err) {
return err.line === exp.line && err.data.code === exp.code;
});
});
// If we expected all errors thrown by the linter, quietly return.
if (unexpected.length === 0 && unthrown.length === 0)
return void test.ok(true);
// Otherwise format a message listing all unexpected and unthrown
// errors and fail the test case by failing an assertion.
var message = "";
if (unexpected.length > 0) {
message += "\n\tUnexpected errors";
message += "\n" + _.map(unexpected, function (err) {
return "\t L" + err.line + ": " + err.data.code;
}).join("\n");
}
if (unthrown.length > 0) {
message += "\n\tErrors defined, but not thrown by JSHint";
message += "\n" + _.map(unthrown, function (err) {
return "\t L" + err.line + ": " + err.code;
}).join("\n");
}
test.ok(false, message);
},
// Shortcut to helper.test that allows us to provide a fixture file name
// instead of a string.
testFile: function (name, options, globals) {
helper.test(fixtures.get(name), options, globals);
}
};
return helper;
}
return runner;
}
exports.Fixtures = Fixtures;
exports.createRunner = createRunner;