Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Support for head/tail (intro/outro) templates.

With an template it is easier to control the __$coverObject output.
The node template for example can write the results directly to a file.

With a new tool "coverjs-report" the JS can be generated from an JSON file
which is outputted by the node template.
  • Loading branch information...
commit 02f4da7ee48e72aa2305f9e8b4e7ea5fba798f2a 1 parent a79e7d4
@arian authored
View
20 README.md
@@ -28,10 +28,13 @@ To instrument the code, CoverJS comes with a CLI tool:
### Reporting
-The instrumented code should be executed to count the number of calls for each statement.
+The instrumented code should be executed to count the number of calls for each
+statement.
+
Usually your tests will try to cover each statement.
-An example code that will capture the output and generate a HTML report would look like:
+An example code that will capture the output and generate a HTML report would
+look like:
```js
@@ -49,6 +52,19 @@ The output stream can be redirected to a file using
so the result can be viewed in a browser
+#### node
+
+There are different templates with which what the instrumented code should
+start and end. For node there exists an template that saves the output as a
+JSON file, which can later be used as to generate a HTML report.
+
+ coverjs --template node --report ./cov.json file.js
+
+With the `coverjs-report` tool, which reads from `stdin`, an HTML output can be
+generated:
+
+ cat ./cov.json | coverjs-report -r html > cov.html
+
#### Screenshot
![Screenshot](http://i.imgur.com/lxGpb.png)
View
24 bin/cover.js
@@ -15,6 +15,8 @@ var files = [];
var dir;
var recursive = false;
var excludes = [];
+var template;
+var result;
var args = process.argv.slice(2);
if (!args.length) args.push('--help');
@@ -43,6 +45,16 @@ for (var i = 0; i < args.length; i++){
continue;
}
+ if (arg == '--template' || arg == '-t'){
+ template = args[++i];
+ continue;
+ }
+
+ if (arg == '--result'){
+ result = args[++i];
+ continue;
+ }
+
if (arg == '--help' || arg == '-h'){
var help = '\n\n' +
@@ -52,7 +64,9 @@ for (var i = 0; i < args.length; i++){
' -v, --version output version information\n' +
' -o, --output <directory> directory to output the instrumented files\n' +
' -r, --recursive recurse in subdirectories\n' +
- ' -x, --exclude <directories> exclude these directories' +
+ ' -x, --exclude <directories> exclude these directories\n' +
+ ' -t, --template <template> which template should be used which exports the __$coverObject variable\n' +
+ ' --result <file> if --template option is node, also a result file should be given where the output is written to.' +
'\n\n';
console.log(help);
@@ -116,7 +130,7 @@ var processFile = function(file, outFile){
files.forEach(function(_file){
var __file = path.normalize(file + '/' + _file);
- if (_file.indexOf('.') != 0 && _file != '..' && _file != '.' && excludes.indexOf(__file) == -1){
+ if (_file.indexOf('.') !== 0 && _file != '..' && _file != '.' && excludes.indexOf(__file) == -1){
var fn = processFile(file + '/' + _file, outFile + '/' + _file);
if (fn) flow.push(fn);
@@ -157,7 +171,11 @@ var processFile = function(file, outFile){
// instrument the code
console.warn(('instrumenting ' + file).blue);
- var instrument = new Instrument(code, file);
+ var instrument = new Instrument(code, {
+ template: template,
+ result: result && path.resolve(result),
+ name: file
+ });
instrumented = instrument.instrument();
next();
View
64 bin/reporter.js
@@ -0,0 +1,64 @@
+#! /usr/bin/env node
+"use strict";
+
+var reporters = require('../cover').reporters;
+
+var reporter = 'text';
+
+var args = process.argv.slice(2);
+for (var i = 0; i < args.length; i++){
+ var arg = args[i];
+
+ if (arg == '--reporter' || arg == '-r'){
+ reporter = args[++i];
+ continue;
+ }
+
+ if (arg == '--help' || arg == '-h'){
+
+ var help = '\n\n' +
+ ' Usage: coverjs-reporter [options]\n\n' +
+ ' Options:\n\n' +
+ ' -r --reporter <reporter> which reporter should be used.\n' +
+ ' possible reporters: text, html\n' +
+ '\n\n';
+
+ console.log(help);
+ process.exit(0);
+ break;
+ }
+
+}
+
+var Reporter;
+switch (reporter){
+ case 'text': Reporter = reporters.Reporter; break;
+ case 'html': Reporter = reporters.HTMLReporter; break;
+ default:
+ console.log(reporter + ' is not a valid reporter. See --help');
+ process.exit(1);
+ break;
+}
+
+var json = '';
+
+process.stdin.resume();
+
+process.stdin.on('data', function(data){
+ json += data;
+});
+
+process.stdin.on('end', function(){
+ report(json);
+});
+
+function report(json){
+
+ var data = JSON.parse(json);
+ var reporter = new Reporter(data);
+
+ var result = reporter.report();
+
+ console.log(result);
+
+}
View
60 lib/Instrument.js
@@ -1,6 +1,5 @@
"use strict";
-
var fs = require('fs');
var esprima = require('esprima');
var escodegen = require('escodegen');
@@ -9,30 +8,38 @@ var escodegen = require('escodegen');
var id = 0;
-var Instrument = function(code, name){
+var Instrument = function(code, options){
- if (!name) name = (id++).toString(36);
+ if (!options) options = {};
this.code = code + '';
- this.name = name + '';
+ this.name = (options.name || (id++).toString(36)) + '';
var quotedName = this.quotedName = JSON.stringify(this.name);
var quotedCode = this.quotedCode = JSON.stringify(this.code);
this.ranges = [];
- this.headCode = ''+
- 'if (typeof __$coverObject === "undefined"){\n' +
- ' if (typeof window !== "undefined") window.__$coverObject = {};\n' +
- ' else if (typeof global !== "undefined") global.__$coverObject = {};\n' +
- ' else throw new Error("cannot find the global scope");\n' +
+ var template = options.template || 'global';
+ var tpls = __dirname + '/../templates/' + template;
+ var headTemplate = fs.readFileSync(tpls + 'Head.js').toString();
+ var tailTemplate = fs.readFileSync(tpls + 'Tail.js').toString();
+
+ if (template == 'node' && options.result){
+ headTemplate = headTemplate.replace(/\{result\}/g, options.result);
+ tailTemplate = tailTemplate.replace(/\{result\}/g, options.result);
+ }
+
+ this.headCode = headTemplate +
+ 'var __$coverCall = function(name, range){\n' +
+ ' __$coverObject[name][range]++;\n' +
'}\n' +
'__$coverObject[' + quotedName + '] = {};\n' +
'__$coverObject[' + quotedName + '].__code = ' + quotedCode + ';\n';
this.rangesCode = '';
- this.tailCode = '';
+ this.tailCode = tailTemplate;
};
@@ -112,29 +119,18 @@ Instrument.prototype = {
return {
"type": "ExpressionStatement",
"expression": {
- "type": "UpdateExpression",
- "operator": "++",
- "argument": {
- "type": "MemberExpression",
- "computed": true,
- "object": {
- "type": "MemberExpression",
- "computed": true,
- "object": {
- "type": "Identifier",
- "name": "__$coverObject"
- },
- "property": {
- "type": "Literal",
- "value": this.name
- }
- },
- "property": {
- "type": "Literal",
- "value": range[0] + ":" + range[1]
- }
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "__$coverCall"
},
- "prefix": false
+ "arguments": [{
+ "type": "Literal",
+ "value": this.name
+ }, {
+ "type": "Literal",
+ "value": range[0] + ":" + range[1]
+ }]
}
};
View
3  package.json
@@ -9,6 +9,7 @@
"main": "cover.js",
"bin": {
"coverjs": "./bin/cover.js"
+ "coverjs-report": "./bin/reporter.js"
},
"dependencies": {
"esprima": "0.9",
@@ -19,7 +20,7 @@
"colors": "0.6"
},
"devDependencies": {
- "mocha": "1.0",
+ "mocha": "1.3",
"expect.js": "0.1"
},
"optionalDependencies": {},
View
5 templates/globalHead.js
@@ -0,0 +1,5 @@
+if (typeof __$coverObject === "undefined"){
+ if (typeof window !== "undefined") window.__$coverObject = {};
+ else if (typeof global !== "undefined") global.__$coverObject = {};
+ else throw new Error("cannot find the global scope");
+}
View
0  templates/globalTail.js
No changes.
View
1  templates/nodeHead.js
@@ -0,0 +1 @@
+var __$coverObject = require("{result}");
View
9 templates/nodeTail.js
@@ -0,0 +1,9 @@
+;(function(fs, call){
+ __$coverCall = function(name, range){
+ var json = fs.readFileSync("{result}");
+ __$coverObject = JSON.parse(json);
+ call(name, range);
+ fs.writeFileSync("{result}", JSON.stringify(__$coverObject, null, 2));
+ };
+ fs.writeFileSync("{result}", JSON.stringify(__$coverObject, null, 2));
+})(require('fs'), __$coverCall);
Please sign in to comment.
Something went wrong with that request. Please try again.