128 lines
3.6 KiB
JavaScript
128 lines
3.6 KiB
JavaScript
var bunker = require('bunker'),
|
|
Module = require('module').Module,
|
|
path = require('path'),
|
|
fs = require('fs'),
|
|
vm = require('vm');
|
|
|
|
function CoverageData (filename, bunker) {
|
|
this.bunker = bunker;
|
|
this.filename = filename;
|
|
this.nodes = {};
|
|
};
|
|
|
|
CoverageData.prototype.visit = function(node) {
|
|
++(this.nodes[node.id] = this.nodes[node.id] || {node:node, count:0}).count;
|
|
};
|
|
|
|
CoverageData.prototype.missing = function() {
|
|
var nodes = this.nodes,
|
|
missing = this.bunker.nodes.filter(function(node) {
|
|
return !nodes[node.id];
|
|
});
|
|
|
|
return missing;
|
|
};
|
|
|
|
CoverageData.prototype.stats = function() {
|
|
var missing = this.missing(),
|
|
filedata = fs.readFileSync(this.filename, 'utf8').split('\n');
|
|
|
|
var seenLines = [],
|
|
lines =
|
|
missing.sort(function(lhs, rhs) {
|
|
return lhs.node[0].start.line < rhs.node[0].start.line ? -1 :
|
|
lhs.node[0].start.line > rhs.node[0].start.line ? 1 :
|
|
0;
|
|
}).filter(function(node) {
|
|
|
|
var okay = (seenLines.indexOf(node.node[0].start.line) < 0);
|
|
if(okay)
|
|
seenLines.push(node.node[0].start.line);
|
|
return okay;
|
|
|
|
}).map(function(node, idx, all) {
|
|
return {
|
|
lineno:node.node[0].start.line + 1,
|
|
source:function() { return filedata[node.node[0].start.line]; }
|
|
};
|
|
});
|
|
|
|
return {
|
|
percentage:(filedata.length-seenLines.length)/filedata.length,
|
|
lines:lines,
|
|
missing:seenLines.length,
|
|
seen:(filedata.length-seenLines.length)
|
|
};
|
|
};
|
|
|
|
module.exports.createEnvironment = function(module, filename) {
|
|
var req = function(path) {
|
|
return Module._load(path, module);
|
|
};
|
|
req.resolve = function(request) {
|
|
return Module._resolveFilename(request, module)[1];
|
|
}
|
|
req.paths = Module._paths;
|
|
req.main = process.mainModule;
|
|
req.extensions = Module._extensions;
|
|
req.registerExtension = function() {
|
|
throw new Error('require.registerExtension() removed. Use ' +
|
|
'require.extensions instead.');
|
|
}
|
|
require.cache = Module._cache;
|
|
|
|
var ctxt = {};
|
|
for(var k in global)
|
|
ctxt[k] = global[k];
|
|
|
|
ctxt.require = req;
|
|
ctxt.exports = module.exports;
|
|
ctxt.__filename = filename;
|
|
ctxt.__dirname = path.dirname(filename);
|
|
ctxt.process = process;
|
|
ctxt.console = console;
|
|
ctxt.module = module;
|
|
ctxt.global = ctxt;
|
|
|
|
return ctxt;
|
|
};
|
|
|
|
module.exports.cover = function(fileRegex) {
|
|
var originalRequire = require.extensions['.js'],
|
|
coverageData = {},
|
|
match = fileRegex instanceof RegExp ?
|
|
fileRegex : new RegExp(
|
|
fileRegex ? fileRegex.replace(/\//g, '\\/').replace(/\./g, '\\.') : '.*'
|
|
, 'g'),
|
|
target = this;
|
|
|
|
require.extensions['.js'] = function(module, filename) {
|
|
if(!match.test(filename)) return originalRequire(module, filename);
|
|
|
|
var context = target.createEnvironment(module, filename),
|
|
data = fs.readFileSync(filename, 'utf8'),
|
|
bunkerized = bunker(data),
|
|
coverage = coverageData[filename] = new CoverageData(filename, bunkerized);
|
|
|
|
bunkerized.on('node', coverage.visit.bind(coverage));
|
|
bunkerized.assign(context);
|
|
|
|
var wrapper = '(function(ctxt) { with(ctxt) { return '+Module.wrap(bunkerized.compile())+'; } })',
|
|
compiledWrapper = vm.runInThisContext(wrapper, filename, true)(context);
|
|
|
|
var args = [context.exports, context.require, module, filename, context.__dirname];
|
|
return compiledWrapper.apply(module.exports, args);
|
|
};
|
|
|
|
var retval = function(ready) {
|
|
ready(coverageData);
|
|
};
|
|
|
|
retval.release = function() {
|
|
require.extensions['.js'] = originalRequire;
|
|
};
|
|
|
|
return retval;
|
|
};
|
|
|