Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / istanbul / lib / command / check-coverage.js
1 /*
2  Copyright (c) 2012, Yahoo! Inc.  All rights reserved.
3  Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
4  */
5
6 var nopt = require('nopt'),
7     path = require('path'),
8     fs = require('fs'),
9     Collector = require('../collector'),
10     formatOption = require('../util/help-formatter').formatOption,
11     util = require('util'),
12     utils = require('../object-utils'),
13     filesFor = require('../util/file-matcher').filesFor,
14     Command = require('./index'),
15     configuration = require('../config');
16
17 function isAbsolute(file) {
18     if (path.isAbsolute) {
19         return path.isAbsolute(file);
20     }
21
22     return path.resolve(file) === path.normalize(file);
23 }
24
25 function CheckCoverageCommand() {
26     Command.call(this);
27 }
28
29 function removeFiles(covObj, root, files) {
30     var filesObj = {},
31         obj = {};
32
33     // Create lookup table.
34     files.forEach(function (file) {
35         filesObj[file] = true;
36     });
37
38     Object.keys(covObj).forEach(function (key) {
39         // Exclude keys will always be relative, but covObj keys can be absolute or relative
40         var excludeKey = isAbsolute(key) ? path.relative(root, key) : key;
41         // Also normalize for files that start with `./`, etc.
42         excludeKey = path.normalize(excludeKey);
43         if (filesObj[excludeKey] !== true) {
44             obj[key] = covObj[key];
45         }
46     });
47
48     return obj;
49 }
50
51 CheckCoverageCommand.TYPE = 'check-coverage';
52 util.inherits(CheckCoverageCommand, Command);
53
54 Command.mix(CheckCoverageCommand, {
55     synopsis: function () {
56         return "checks overall/per-file coverage against thresholds from coverage JSON files. Exits 1 if thresholds are not met, 0 otherwise";
57     },
58
59     usage: function () {
60         console.error('\nUsage: ' + this.toolName() + ' ' + this.type() + ' <options> [<include-pattern>]\n\nOptions are:\n\n' +
61             [
62                 formatOption('--statements <threshold>', 'global statement coverage threshold'),
63                 formatOption('--functions <threshold>', 'global function coverage threshold'),
64                 formatOption('--branches <threshold>', 'global branch coverage threshold'),
65                 formatOption('--lines <threshold>', 'global line coverage threshold')
66             ].join('\n\n') + '\n');
67
68         console.error('\n\n');
69
70         console.error('Thresholds, when specified as a positive number are taken to be the minimum percentage required.');
71         console.error('When a threshold is specified as a negative number it represents the maximum number of uncovered entities allowed.\n');
72         console.error('For example, --statements 90 implies minimum statement coverage is 90%.');
73         console.error('             --statements -10 implies that no more than 10 uncovered statements are allowed\n');
74         console.error('Per-file thresholds can be specified via a configuration file.\n');
75         console.error('<include-pattern> is a fileset pattern that can be used to select one or more coverage files ' +
76             'for merge. This defaults to "**/coverage*.json"');
77
78         console.error('\n');
79     },
80
81     run: function (args, callback) {
82
83         var template = {
84                 config: path,
85                 root: path,
86                 statements: Number,
87                 lines: Number,
88                 branches: Number,
89                 functions: Number,
90                 verbose: Boolean
91             },
92             opts = nopt(template, { v : '--verbose' }, args, 0),
93             // Translate to config opts.
94             config = configuration.loadFile(opts.config, {
95                 verbose: opts.verbose,
96                 check: {
97                     global: {
98                         statements: opts.statements,
99                         lines: opts.lines,
100                         branches: opts.branches,
101                         functions: opts.functions
102                     }
103                 }
104             }),
105             includePattern = '**/coverage*.json',
106             root,
107             collector = new Collector(),
108             errors = [];
109
110         if (opts.argv.remain.length > 0) {
111             includePattern = opts.argv.remain[0];
112         }
113
114         root = opts.root || process.cwd();
115         filesFor({
116             root: root,
117             includes: [ includePattern ]
118         }, function (err, files) {
119             if (err) { throw err; }
120             if (files.length === 0) {
121                return callback('ERROR: No coverage files found.');
122             }
123             files.forEach(function (file) {
124                 var coverageObject = JSON.parse(fs.readFileSync(file, 'utf8'));
125                 collector.add(coverageObject);
126             });
127             var thresholds = {
128                 global: {
129                     statements: config.check.global.statements || 0,
130                     branches: config.check.global.branches || 0,
131                     lines: config.check.global.lines || 0,
132                     functions: config.check.global.functions || 0,
133                     excludes: config.check.global.excludes || []
134                 },
135                 each: {
136                     statements: config.check.each.statements || 0,
137                     branches: config.check.each.branches || 0,
138                     lines: config.check.each.lines || 0,
139                     functions: config.check.each.functions || 0,
140                     excludes: config.check.each.excludes || []
141                 }
142             },
143                 rawCoverage = collector.getFinalCoverage(),
144                 globalResults = utils.summarizeCoverage(removeFiles(rawCoverage, root, thresholds.global.excludes)),
145                 eachResults = removeFiles(rawCoverage, root, thresholds.each.excludes);
146
147             // Summarize per-file results and mutate original results.
148             Object.keys(eachResults).forEach(function (key) {
149                 eachResults[key] = utils.summarizeFileCoverage(eachResults[key]);
150             });
151
152             if (config.verbose) {
153                 console.log('Compare actuals against thresholds');
154                 console.log(JSON.stringify({ global: globalResults, each: eachResults, thresholds: thresholds }, undefined, 4));
155             }
156
157             function check(name, thresholds, actuals) {
158                 [
159                     "statements",
160                     "branches",
161                     "lines",
162                     "functions"
163                 ].forEach(function (key) {
164                     var actual = actuals[key].pct,
165                         actualUncovered = actuals[key].total - actuals[key].covered,
166                         threshold = thresholds[key];
167
168                     if (threshold < 0) {
169                         if (threshold * -1 < actualUncovered) {
170                             errors.push('ERROR: Uncovered count for ' + key + ' (' + actualUncovered +
171                                 ') exceeds ' + name + ' threshold (' + -1 * threshold + ')');
172                         }
173                     } else {
174                         if (actual < threshold) {
175                             errors.push('ERROR: Coverage for ' + key + ' (' + actual +
176                                 '%) does not meet ' + name + ' threshold (' + threshold + '%)');
177                         }
178                     }
179                 });
180             }
181
182             check("global", thresholds.global, globalResults);
183
184             Object.keys(eachResults).forEach(function (key) {
185                 check("per-file" + " (" + key + ") ", thresholds.each, eachResults[key]);
186             });
187
188             return callback(errors.length === 0 ? null : errors.join("\n"));
189         });
190     }
191 });
192
193 module.exports = CheckCoverageCommand;
194
195