1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 89 89 14 89 89 89 5 2 2 2 2 2 2 2 2 8 8 1 8 8 8 8 7 7 8 8 1 1 8 32 32 4 3 28 7 8 89 | /* Copyright (c) 2012, Yahoo! Inc. All rights reserved. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. */ var nopt = require('nopt'), path = require('path'), fs = require('fs'), Collector = require('../collector'), formatOption = require('../util/help-formatter').formatOption, util = require('util'), utils = require('../object-utils'), filesFor = require('../util/file-matcher').filesFor, Command = require('./index'); function CheckCoverageCommand() { Command.call(this); } CheckCoverageCommand.TYPE = 'check-coverage'; util.inherits(CheckCoverageCommand, Command); Command.mix(CheckCoverageCommand, { synopsis: function () { return "checks overall coverage against thresholds from coverage JSON files. Exits 1 if thresholds are not met, 0 otherwise"; }, usage: function () { console.error('\nUsage: ' + this.toolName() + ' ' + this.type() + ' <options> [<include-pattern>]\n\nOptions are:\n\n' + [ formatOption('--statements <threshold>', 'statement coverage threshold'), formatOption('--functions <threshold>', 'function coverage threshold'), formatOption('--branches <threshold>', 'branch coverage threshold'), formatOption('--lines <threshold>', 'line coverage threshold') ].join('\n\n') + '\n'); console.error('\n\n'); console.error('Thresholds, when specified as a positive number are taken to be the minimum percentage required.'); console.error('When a threshold is specified as a negative number it represents the maximum number of uncovered entities allowed.\n'); console.error('For example, --statements 90 implies minimum statement coverage is 90%.'); console.error(' --statements -10 implies that no more than 10 uncovered statements are allowed\n'); console.error('<include-pattern> is a fileset pattern that can be used to select one or more coverage files ' + 'for merge. This defaults to "**/coverage*.json"'); console.error('\n'); }, run: function (args, callback) { var config = { root: path, dir: path, statements: Number, lines: Number, branches: Number, functions: Number, verbose: Boolean }, opts = nopt(config, { v : '--verbose' }, args, 0), includePattern = '**/coverage*.json', root, collector = new Collector(), errors = []; if (opts.argv.remain.length > 0) { includePattern = opts.argv.remain[0]; } root = opts.root || process.cwd(); filesFor({ root: root, includes: [ includePattern ] }, function (err, files) { Iif (err) { throw err; } files.forEach(function (file) { var coverageObject = JSON.parse(fs.readFileSync(file, 'utf8')); collector.add(coverageObject); }); var thresholds = { statements: opts.statements || 0, branches: opts.branches || 0, lines: opts.lines || 0, functions: opts.functions || 0 }, actuals = utils.summarizeCoverage(collector.getFinalCoverage()); if (opts.verbose) { console.log('Compare actuals against thresholds'); console.log(JSON.stringify({ actuals: actuals, thresholds: thresholds }, undefined, 4)); } Object.keys(thresholds).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 threshold (' + -1 * threshold + ')'); } } else { if (actual < threshold) { errors.push('ERROR: Coverage for ' + key + ' (' + actual + '%) does not meet threshold (' + threshold + '%)'); } } }); return callback(errors.length === 0 ? null : errors.join("\n")); }); } }); module.exports = CheckCoverageCommand; |