1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | var path = require('path');
|
25 | var fs = require('fs');
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | function stringifyCoverage(cov) {
|
31 | var i, files, file, fileObj, source;
|
32 | var tmp = {}, coverageObj = {};
|
33 |
|
34 | files = Object.keys(cov);
|
35 |
|
36 | for (i = 0; i < files.length; i++) {
|
37 | file = files[i];
|
38 | fileObj = cov[file];
|
39 | source = fileObj['source'];
|
40 | delete fileObj['source'];
|
41 |
|
42 | coverageObj[file] = {
|
43 | 'lines': fileObj,
|
44 | 'source': source
|
45 | };
|
46 | }
|
47 |
|
48 | return JSON.stringify(coverageObj);
|
49 | }
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 | function coverage(data, type) {
|
58 | var comparisionFunc;
|
59 | var n = 0;
|
60 |
|
61 | function isCovered(val) {
|
62 | return (val > 0);
|
63 | }
|
64 |
|
65 | function isMissed(val) {
|
66 | return !isCovered(val);
|
67 | }
|
68 |
|
69 | if (type === 'covered') {
|
70 | comparisionFunc = isCovered;
|
71 | }
|
72 | else if (type === 'missed') {
|
73 | comparisionFunc = isMissed;
|
74 | }
|
75 | else {
|
76 | throw new Error('Invalid type: ' + type);
|
77 | }
|
78 |
|
79 | for (var i = 0, len = data.lines.length; i < len; ++i) {
|
80 | if (data.lines[i] !== null && comparisionFunc(data.lines[i])) {
|
81 | ++n;
|
82 | }
|
83 | }
|
84 |
|
85 | return n;
|
86 | }
|
87 |
|
88 | function getEmptyResultObject() {
|
89 | var results = {};
|
90 |
|
91 | results.LOC = 0;
|
92 | results.SLOC = 0;
|
93 | results.totalFiles = 0;
|
94 | results.totalHits = 0;
|
95 | results.totalMisses = 0;
|
96 | results.coverage = 0;
|
97 | results.files = {};
|
98 |
|
99 | return results;
|
100 | }
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | function populateCoverage(results, cov) {
|
107 | var linesLen;
|
108 |
|
109 | results = (!results) ? getEmptyResultObject() : results;
|
110 |
|
111 |
|
112 | for (var testfile in cov) {
|
113 | for (var name in cov[testfile]) {
|
114 | var file = cov[testfile][name], file_stats;
|
115 |
|
116 | file_stats = results.files[name] || {
|
117 | name: name,
|
118 | htmlName: name.replace('.js', '.html').replace('.java', '.html').replace(/\/|\\/g, '_'),
|
119 | totalHits: 0,
|
120 | totalMisses: 0,
|
121 | totalLines: 0,
|
122 | lines: null,
|
123 | source: null
|
124 | };
|
125 |
|
126 | if (file_stats.lines === null) {
|
127 | file_stats.lines = file.lines;
|
128 | }
|
129 | else {
|
130 | linesLen = file.lines.length;
|
131 | for (var i = 0; i < linesLen; i++) {
|
132 | if (file.lines[i] !== null) {
|
133 | if (file_stats.lines[i] === null) {
|
134 | file_stats.lines[i] = file.lines[i];
|
135 | }
|
136 | else {
|
137 | file_stats.lines[i] += file.lines[i];
|
138 | }
|
139 | }
|
140 | }
|
141 | }
|
142 |
|
143 | if (file_stats.source === null) {
|
144 | file_stats.source = file.source;
|
145 | }
|
146 |
|
147 | results.files[name] = file_stats;
|
148 | }
|
149 | }
|
150 |
|
151 |
|
152 | for (var name in results.files) {
|
153 | var file_stats = results.files[name];
|
154 |
|
155 |
|
156 | file_stats.totalHits = coverage(file_stats, 'covered');
|
157 | file_stats.totalMisses = coverage(file_stats, 'missed');
|
158 | file_stats.totalLines = file_stats.totalHits + file_stats.totalMisses;
|
159 | file_stats.coverage = (file_stats.totalHits / file_stats.totalLines) * 100;
|
160 | file_stats.coverage = (isNaN(file_stats.coverage)) ? 0 : file_stats.coverage.toFixed(2);
|
161 | file_stats.LOC = file_stats.source.length;
|
162 | file_stats.SLOC = file_stats.totalLines;
|
163 | results.files[name] = file_stats;
|
164 |
|
165 |
|
166 | results.totalHits += file_stats.totalHits;
|
167 | results.totalMisses += file_stats.totalMisses;
|
168 | results.totalFiles++;
|
169 | results.LOC += file_stats.LOC;
|
170 | results.SLOC += file_stats.SLOC;
|
171 | }
|
172 |
|
173 |
|
174 | results.coverage = (results.totalHits / results.SLOC) * 100;
|
175 | results.coverage = results.coverage.toFixed(2);
|
176 |
|
177 | return results;
|
178 | }
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | function aggregateCoverage(files) {
|
184 | var i, len, file, content, results;
|
185 | var resultsObj = getEmptyResultObject();
|
186 |
|
187 | for (i = 0, len = files.length; i < len; i++) {
|
188 | file = files[i];
|
189 | content = JSON.parse(fs.readFileSync(file).toString());
|
190 | resultsObj = populateCoverage(resultsObj, content);
|
191 | }
|
192 |
|
193 | return resultsObj;
|
194 | }
|
195 |
|
196 |
|
197 | function installCoverageHandler() {
|
198 | var pid = process.pid;
|
199 | var coverageDirectory = process.env['COVERAGE_DIRECTORY'];
|
200 | var coveragePath = path.join(coverageDirectory, pid + '.json');
|
201 |
|
202 | function writeCoverage() {
|
203 | var coverage = {};
|
204 |
|
205 | if (typeof _$jscoverage === 'object') {
|
206 | coverage[pid] = JSON.parse(stringifyCoverage(_$jscoverage));
|
207 |
|
208 | try {
|
209 | fs.writeFileSync(coveragePath, JSON.stringify(coverage), 'utf8');
|
210 | }
|
211 | catch (e) {}
|
212 | }
|
213 |
|
214 | process.exit();
|
215 | }
|
216 |
|
217 | if (coverageDirectory) {
|
218 | process.on('SIGUSR2', writeCoverage);
|
219 | }
|
220 | }
|
221 |
|
222 | exports.stringifyCoverage = stringifyCoverage;
|
223 | exports.populateCoverage = populateCoverage;
|
224 | exports.aggregateCoverage = aggregateCoverage;
|
225 | exports.installCoverageHandler = installCoverageHandler;
|