Code coverage report for istanbul/lib/command/common/run-with-cover.js

Statements: 11.54% (6 / 52)      Branches: 7.14% (2 / 28)      Functions: 20% (1 / 5)      Lines: 11.76% (6 / 51)     

All files » istanbul/lib/command/common/ » run-with-cover.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 1 var Module = require('module'),
6 path = require('path'),
7 fs = require('fs'),
8 nopt = require('nopt'),
9 which = require('which'),
10 mkdirp = require('mkdirp'),
11 existsSync = fs.existsSync || path.existsSync,
12 inputError = require('../../util/input-error'),
13 matcherFor = require('../../util/file-matcher').matcherFor,
14 Instrumenter = require('../../instrumenter'),
15 Collector = require('../../collector'),
16 formatOption = require('../../util/help-formatter').formatOption,
17 hook = require('../../hook'),
18 Report = require('../../report'),
19 DEFAULT_REPORT_FORMAT = 'lcov';
20
21 1 function usage(arg0, command) {
22 4 console.error('\nUsage: ' + arg0 + ' ' + command + ' [<options>] <executable-js-file-or-command> [-- <arguments-to-jsfile>]\n\nOptions are:\n\n'
23 + [
24 formatOption('--root <path> ', 'the root path to look for files to instrument, defaults to .'),
25 formatOption('-x <exclude-pattern> [-x <exclude-pattern>]', 'one or more fileset patterns e.g. "**/vendor/**"'),
26 formatOption('--[no-]default-excludes', 'apply default excludes [ **/node_modules/**, **/test/**, **/tests/** ], defaults to true'),
27 formatOption('--report <report-type>', 'report type, one of html, lcov, lcovonly, none, defaults to lcov (= lcov.info + HTML)'),
28 formatOption('--dir <report-dir>', 'report directory, defaults to ./coverage'),
29 formatOption('--verbose, -v', 'verbose mode')
30 ].join('\n\n') + '\n');
31 4 console.error('\n');
32 }
33
34 1 function run(args, commandName, enableHooks) {
35
36 var config = {
37 root: path,
38 x: [Array, String],
39 report: String,
40 dir: path,
41 verbose: Boolean,
42 yui: Boolean,
43 'default-excludes': Boolean
44 },
45 opts = nopt(config, { v : '--verbose' }, args, 0),
46 cmdAndArgs = opts.argv.remain,
47 cmd,
48 cmdArgs,
49 reportingDir,
50 reportClassName,
51 report,
52 runFn,
53 excludes;
54
55 if (cmdAndArgs.length === 0) {
56 throw inputError.create('Need a filename argument for the ' + commandName + ' command!');
57 }
58
59 cmd = cmdAndArgs.shift();
60 cmdArgs = cmdAndArgs;
61
62 if (!existsSync(cmd)) {
63 try {
64 cmd = which.sync(cmd);
65 } catch (ex) {
66 throw inputError.create('Unable to resolve file [' + cmd + ']');
67 }
68 } else {
69 cmd = path.resolve(cmd);
70 }
71
72 runFn = function () {
73 process.argv = ["node", cmd].concat(cmdArgs);
74 if (opts.verbose) {
75 console.log('Running: ' + process.argv.join(' '));
76 }
77 Module.runMain(cmd, null, true);
78 };
79
80 excludes = typeof opts['default-excludes'] === 'undefined' || opts['default-excludes'] ?
81 [ '**/node_modules/**', '**/test/**', '**/tests/**' ] : [];
82 excludes.push.apply(excludes, opts.x);
83
84 if (enableHooks) {
85 reportingDir = opts.dir || path.resolve(process.cwd(), 'coverage');
86 mkdirp.sync(reportingDir);
87 reportClassName = opts.report || DEFAULT_REPORT_FORMAT;
88 report = Report.create(reportClassName, { dir: reportingDir });
89
90 matcherFor({
91 root: opts.root || process.cwd(),
92 includes: [ '**/*.js' ],
93 excludes: excludes
94 },
95 function (err, matchFn) {
96 if (err) { throw err; }
97
98 var coverageVar = '$$cov_' + new Date().getTime() + '$$',
99 instrumenter = new Instrumenter({ coverageVariable: coverageVar }),
100 transformer = instrumenter.instrumentSync.bind(instrumenter),
101 hookOpts = { verbose: opts.verbose };
102
103 if (opts.yui) { //EXPERIMENTAL code: do not rely on this in anyway until the docs say it is allowed
104 hookOpts.postLoadHook = require('../../util/yui-load-hook').getPostLoadHook(matchFn, transformer, opts.verbose);
105 }
106 hook.hookRequire(matchFn, transformer, hookOpts);
107 process.once('exit', function () {
108 var file = path.resolve(reportingDir, 'coverage.json'),
109 collector,
110 cov;
111 if (typeof global[coverageVar] === 'undefined') {
112 console.error('No coverage information was collected, exit without writing coverage information');
113 return;
114 } else {
115 cov = global[coverageVar];
116 }
117 //important: there is no event loop at this point
118 //everything that happens in this exit handler MUST be synchronous
119 console.log('=============================================================================');
120 console.log('Writing coverage object [' + file + ']');
121 fs.writeFileSync(file, JSON.stringify(cov), 'utf8');
122 collector = new Collector();
123 collector.add(cov);
124 if (report) {
125 console.log('Writing coverage reports at [' + reportingDir + ']');
126 report.writeReport(collector, true);
127 }
128 console.log('=============================================================================');
129 });
130 runFn();
131 });
132 } else {
133 runFn();
134 }
135 }
136
137 1 module.exports = {
138 run: run,
139 usage: usage
140 };
141