149 lines
5.0 KiB
JavaScript
149 lines
5.0 KiB
JavaScript
|
/*
|
||
|
Copyright 2012-2015, Yahoo Inc.
|
||
|
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
|
||
|
*/
|
||
|
var path = require('path'),
|
||
|
fs = require('fs'),
|
||
|
filesFor = require('./file-matcher').filesFor,
|
||
|
libCoverage = require('istanbul-lib-coverage'),
|
||
|
inputError = require('./input-error'),
|
||
|
isAbsolute = path.isAbsolute || function (file) {
|
||
|
return path.resolve(file) === path.normalize(file);
|
||
|
};
|
||
|
|
||
|
function removeFiles(origMap, root, files) {
|
||
|
var filesObj = {},
|
||
|
ret = libCoverage.createCoverageMap();
|
||
|
|
||
|
// Create lookup table.
|
||
|
files.forEach(function (file) {
|
||
|
filesObj[file] = true;
|
||
|
});
|
||
|
|
||
|
origMap.files().forEach(function (key) {
|
||
|
// Exclude keys will always be relative, but covObj keys can be absolute or relative
|
||
|
var excludeKey = isAbsolute(key) ? path.relative(root, key) : key;
|
||
|
// Also normalize for files that start with `./`, etc.
|
||
|
excludeKey = path.normalize(excludeKey);
|
||
|
if (filesObj[excludeKey] !== true) {
|
||
|
ret.addFileCoverage(origMap.fileCoverageFor(key));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
function run(config, opts, callback) {
|
||
|
|
||
|
if (!callback && typeof(opts) === 'function') {
|
||
|
callback = opts;
|
||
|
opts = {};
|
||
|
}
|
||
|
|
||
|
opts = opts || {};
|
||
|
|
||
|
var root = opts.root || config.instrumentation.root() || process.cwd(),
|
||
|
includePattern = opts.include || '**/coverage*.json',
|
||
|
errors = [],
|
||
|
check,
|
||
|
makeMap,
|
||
|
processFiles;
|
||
|
|
||
|
check = function (name, thresholds, actuals) {
|
||
|
[
|
||
|
"statements",
|
||
|
"branches",
|
||
|
"lines",
|
||
|
"functions"
|
||
|
].forEach(function (key) {
|
||
|
var actual = actuals[key].pct,
|
||
|
actualUncovered = actuals[key].total - actuals[key].covered,
|
||
|
threshold = thresholds[key];
|
||
|
|
||
|
if (threshold < 0) {
|
||
|
if (threshold * -1 < actualUncovered) {
|
||
|
errors.push('ERROR: Uncovered count for ' + key + ' (' + actualUncovered +
|
||
|
') exceeds ' + name + ' threshold (' + -1 * threshold + ')');
|
||
|
}
|
||
|
} else {
|
||
|
if (actual < threshold) {
|
||
|
errors.push('ERROR: Coverage for ' + key + ' (' + actual +
|
||
|
'%) does not meet ' + name + ' threshold (' + threshold + '%)');
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
makeMap = function (files, callback) {
|
||
|
var coverageMap = libCoverage.createCoverageMap();
|
||
|
if (files.length === 0) {
|
||
|
return callback(inputError.create('ERROR: No coverage files found.'));
|
||
|
}
|
||
|
files.forEach(function (file) {
|
||
|
var coverageObject = JSON.parse(fs.readFileSync(file, 'utf8'));
|
||
|
coverageMap.merge(coverageObject);
|
||
|
});
|
||
|
return callback(null, coverageMap);
|
||
|
};
|
||
|
|
||
|
processFiles = function (coverageMap, callback) {
|
||
|
var thresholds = {
|
||
|
global: {
|
||
|
statements: config.check.global.statements || 0,
|
||
|
branches: config.check.global.branches || 0,
|
||
|
lines: config.check.global.lines || 0,
|
||
|
functions: config.check.global.functions || 0,
|
||
|
excludes: config.check.global.excludes || []
|
||
|
},
|
||
|
each: {
|
||
|
statements: config.check.each.statements || 0,
|
||
|
branches: config.check.each.branches || 0,
|
||
|
lines: config.check.each.lines || 0,
|
||
|
functions: config.check.each.functions || 0,
|
||
|
excludes: config.check.each.excludes || []
|
||
|
}
|
||
|
},
|
||
|
globalResults = removeFiles(coverageMap, root, thresholds.global.excludes),
|
||
|
eachResults = removeFiles(coverageMap, root, thresholds.each.excludes),
|
||
|
finalError;
|
||
|
|
||
|
if (config.verbose) {
|
||
|
console.error('Compare actuals against thresholds');
|
||
|
console.error(JSON.stringify({
|
||
|
global: globalResults,
|
||
|
each: eachResults,
|
||
|
thresholds: thresholds
|
||
|
}, undefined, 4));
|
||
|
}
|
||
|
|
||
|
check("global", thresholds.global, globalResults.getCoverageSummary());
|
||
|
eachResults.files().forEach(function (key) {
|
||
|
var summary = eachResults.fileCoverageFor(key).toSummary();
|
||
|
check("per-file" + " (" + key + ") ", thresholds.each, summary);
|
||
|
});
|
||
|
finalError = errors.length === 0 ? null : errors.join("\n");
|
||
|
return callback(finalError);
|
||
|
};
|
||
|
|
||
|
filesFor({
|
||
|
root: root,
|
||
|
includes: [includePattern]
|
||
|
}, function (err, files) {
|
||
|
if (err) {
|
||
|
return callback(err);
|
||
|
}
|
||
|
makeMap(files, function (err, map) {
|
||
|
if (err) {
|
||
|
return callback(err);
|
||
|
}
|
||
|
return processFiles(map, callback);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
module.exports = {
|
||
|
run: run
|
||
|
};
|
||
|
|
||
|
|