152 lines
2.8 KiB
JavaScript
152 lines
2.8 KiB
JavaScript
|
/**
|
||
|
* Module dependencies.
|
||
|
*/
|
||
|
|
||
|
var Base = require('./base');
|
||
|
|
||
|
/**
|
||
|
* Expose `JSONCov`.
|
||
|
*/
|
||
|
|
||
|
exports = module.exports = JSONCov;
|
||
|
|
||
|
/**
|
||
|
* Initialize a new `JsCoverage` reporter.
|
||
|
*
|
||
|
* @api public
|
||
|
* @param {Runner} runner
|
||
|
* @param {boolean} output
|
||
|
*/
|
||
|
function JSONCov(runner, output) {
|
||
|
Base.call(this, runner);
|
||
|
|
||
|
output = arguments.length === 1 || output;
|
||
|
var self = this;
|
||
|
var tests = [];
|
||
|
var failures = [];
|
||
|
var passes = [];
|
||
|
|
||
|
runner.on('test end', function(test) {
|
||
|
tests.push(test);
|
||
|
});
|
||
|
|
||
|
runner.on('pass', function(test) {
|
||
|
passes.push(test);
|
||
|
});
|
||
|
|
||
|
runner.on('fail', function(test) {
|
||
|
failures.push(test);
|
||
|
});
|
||
|
|
||
|
runner.on('end', function() {
|
||
|
var cov = global._$jscoverage || {};
|
||
|
var result = self.cov = map(cov);
|
||
|
result.stats = self.stats;
|
||
|
result.tests = tests.map(clean);
|
||
|
result.failures = failures.map(clean);
|
||
|
result.passes = passes.map(clean);
|
||
|
if (!output) {
|
||
|
return;
|
||
|
}
|
||
|
process.stdout.write(JSON.stringify(result, null, 2));
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Map jscoverage data to a JSON structure
|
||
|
* suitable for reporting.
|
||
|
*
|
||
|
* @api private
|
||
|
* @param {Object} cov
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
|
||
|
function map(cov) {
|
||
|
var ret = {
|
||
|
instrumentation: 'node-jscoverage',
|
||
|
sloc: 0,
|
||
|
hits: 0,
|
||
|
misses: 0,
|
||
|
coverage: 0,
|
||
|
files: []
|
||
|
};
|
||
|
|
||
|
for (var filename in cov) {
|
||
|
if (Object.prototype.hasOwnProperty.call(cov, filename)) {
|
||
|
var data = coverage(filename, cov[filename]);
|
||
|
ret.files.push(data);
|
||
|
ret.hits += data.hits;
|
||
|
ret.misses += data.misses;
|
||
|
ret.sloc += data.sloc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ret.files.sort(function(a, b) {
|
||
|
return a.filename.localeCompare(b.filename);
|
||
|
});
|
||
|
|
||
|
if (ret.sloc > 0) {
|
||
|
ret.coverage = (ret.hits / ret.sloc) * 100;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Map jscoverage data for a single source file
|
||
|
* to a JSON structure suitable for reporting.
|
||
|
*
|
||
|
* @api private
|
||
|
* @param {string} filename name of the source file
|
||
|
* @param {Object} data jscoverage coverage data
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
function coverage(filename, data) {
|
||
|
var ret = {
|
||
|
filename: filename,
|
||
|
coverage: 0,
|
||
|
hits: 0,
|
||
|
misses: 0,
|
||
|
sloc: 0,
|
||
|
source: {}
|
||
|
};
|
||
|
|
||
|
data.source.forEach(function(line, num) {
|
||
|
num++;
|
||
|
|
||
|
if (data[num] === 0) {
|
||
|
ret.misses++;
|
||
|
ret.sloc++;
|
||
|
} else if (data[num] !== undefined) {
|
||
|
ret.hits++;
|
||
|
ret.sloc++;
|
||
|
}
|
||
|
|
||
|
ret.source[num] = {
|
||
|
source: line,
|
||
|
coverage: data[num] === undefined ? '' : data[num]
|
||
|
};
|
||
|
});
|
||
|
|
||
|
ret.coverage = ret.hits / ret.sloc * 100;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return a plain-object representation of `test`
|
||
|
* free of cyclic properties etc.
|
||
|
*
|
||
|
* @api private
|
||
|
* @param {Object} test
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
function clean(test) {
|
||
|
return {
|
||
|
duration: test.duration,
|
||
|
currentRetry: test.currentRetry(),
|
||
|
fullTitle: test.fullTitle(),
|
||
|
title: test.title
|
||
|
};
|
||
|
}
|