Skip to content

Commit

Permalink
adds coverage map functionality
Browse files Browse the repository at this point in the history
adds code coverage map functionality via jscoverage.

  --cover-plain - outputs any coverage output in plain test
  --cover-html - outputs any coverage output to a local copy of coverage.html

output occurs if jscoverage is encountered in source files during run of vows.
  • Loading branch information
jsievert committed Jul 17, 2011
1 parent bc868fa commit 3d400b8
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 1 deletion.
17 changes: 16 additions & 1 deletion bin/vows
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ var stylize = require('vows/console').stylize;
var _reporter = require('vows/reporters/dot-matrix'), reporter = {
name: _reporter.name,
};
var _coverage;

var help = [
"usage: vows [FILE, ...] [options]",
Expand All @@ -56,6 +57,8 @@ var help = [
" --spec Use Spec reporter",
" --dot-matrix Use Dot-Matrix reporter",
" --xunit Use xUnit reporter",
" --cover-plain Print plain coverage map if detected",
" --cover-html Write coverage map to \"coverage.html\"",
//" --no-color Don't use terminal colors",
" --version Show version",
" -h, --help You're staring at it"
Expand All @@ -64,7 +67,8 @@ var help = [
var options = {
reporter: reporter,
matcher: /.*/,
watch: false
watch: false,
coverage: false
};

var files = [];
Expand Down Expand Up @@ -116,6 +120,14 @@ while (arg = argv.shift()) {
case 'xunit':
_reporter = require('vows/reporters/xunit');
break;
case 'cover-plain':
options.coverage = true;
_coverage = require('vows/coverage/report-plain');
break;
case 'cover-html':
options.coverage = true;
_coverage = require('vows/coverage/report-html');
break;
case 'verbose':
case 'v':
options.verbose = true;
Expand Down Expand Up @@ -209,6 +221,9 @@ if (! options.watch) {
util.print(str.replace(/^\n\n/, '\n'));
}
});
if (options.coverage === true && _$jscoverage !== undefined) {
_coverage.report(_$jscoverage);
}
if (process.stdout.write('')) { // Check if stdout is drained
process.exit(status);
} else {
Expand Down
29 changes: 29 additions & 0 deletions lib/vows/coverage/file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

exports.coverage = function (filename, data) {
var ret = {
filename: filename,
coverage: 0,
hits: 0,
misses: 0,
sloc : 0
};

var source = data.source;
ret.source = source.map(function (line, num) {
num++;

if (data[num] === 0) {
ret.misses++;
ret.sloc++;
} else if (data[num] !== undefined) {
ret.hits++;
ret.sloc++;
}

return { line: line, coverage: (data[num] === undefined ? '' : data[num]) };
});

ret.coverage = (ret.hits / ret.sloc) * 100;

return ret;
};
2 changes: 2 additions & 0 deletions lib/vows/coverage/fragments/coverage-foot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
</body>
</html>
38 changes: 38 additions & 0 deletions lib/vows/coverage/fragments/coverage-head.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.covered {
background-color: green;
}
.uncovered {
background-color: red;
}
.coverage {
font-size: 0.8em;
color: #333;
}
.code {
font-family: "Consolas", "Courier New", Courier, mono;
white-space: pre;
line-height: 16px;
}
body {
margin-left: 20px;
margin-top: 8px;
background-color: white;
color: black;
font-size: 16px;
}
ol {
margin-left: 20px;
margin-bottom: 40px;
width: 800px;
line-height: 18px;
-moz-box-shadow: 10px 10px 5px #888;
-webkit-box-shadow: 10px 10px 5px #888;
box-shadow: 10px 10px 5px #888;
}
</style>
</head>
<body>
44 changes: 44 additions & 0 deletions lib/vows/coverage/report-html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var sys = require('sys'),
fs = require('fs'),
file = require('vows/coverage/file');

this.name = 'coverage-report-html';

this.report = function (coverageMap) {
var out, head, foot;

try {
out = fs.openSync("coverage.html", "w");
head = fs.readFileSync(__dirname + "/fragments/coverage-head.html", "utf8");
foot = fs.readFileSync(__dirname + "/fragments/coverage-foot.html", "utf8");
} catch (error) {
sys.print("Error: Unable to write to file coverage.html\n");
return;
}

fs.writeSync(out, head);

for (var filename in coverageMap) {
if (coverageMap.hasOwnProperty(filename)) {
var data = file.coverage(filename, coverageMap[filename]);

fs.writeSync(out, "<h2>" + filename + "</h2>\n");
fs.writeSync(out, '<span class="coverage">' + "[ hits: " + data.hits);
fs.writeSync(out, ", misses: " + data.misses + ", sloc: " + data.sloc);
fs.writeSync(out, ", coverage: " + data.coverage.toFixed(2) + "% ]" + "</span>\n");
fs.writeSync(out, "<ol>\n");

for (var i = 0; i < data.source.length; i++) {
fs.writeSync(out, ' <li class="code ');
fs.writeSync(out, (data.source[i].coverage === 0 ? 'uncovered' : 'covered'));
fs.writeSync(out, '" coverage="' + data.source[i].coverage + '">');
fs.writeSync(out, data.source[i].line + "</li>\n");
}

fs.writeSync(out, "</ol>\n");
}
}

fs.writeSync(out, foot);
fs.close(out);
};
38 changes: 38 additions & 0 deletions lib/vows/coverage/report-plain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
var sys = require('sys'),
file = require('./file');

this.name = 'coverage-report-plain';

function lpad(str, width) {
str = String(str);
var n = width - str.length;

if (n < 1) {
return str;
}

while (n--) {
str = ' ' + str;
}

return str;
}


this.report = function (coverageMap) {
for (var filename in coverageMap) {
if (coverageMap.hasOwnProperty(filename)) {
var data = file.coverage(filename, coverageMap[filename]);

sys.print(filename + ":\n");
sys.print("[ hits: " + data.hits + ", misses: " + data.misses);
sys.print(", sloc: " + data.sloc + ", coverage: " + data.coverage.toFixed(2) + "% ]\n");

for (var i = 0; i < data.source.length; i++) {
sys.print(lpad(data.source[i].coverage, 5) + " | " + data.source[i].line + "\n");
}

sys.print("\n");
}
}
};

0 comments on commit 3d400b8

Please sign in to comment.