Authors: Mathieu Rene & Steve Venzerul
A great talk by Alan Shreve
Parse input
Instrument AST
Run instrumented code
Output coverage report
Reparse input into AST, use report to remove nodes that weren't executed
Output modified AST back to disk.
function someFunction(someValue) {
if (someValue % 2 === 0) console.log('foo');
else console.log('bar');
switch(someValue) {
case 0:
case 20:
console.log('nope');
break;
case 11:
try {
console.log('maybe', 1234 / 0);
throw new Error(':)');
} catch(e) {
void 0;
console.log('e', e);
}
break;
case 42:
fs.readFile('./nonexistant', (err, data) => {
if (err) {
return 10;
}
console.log('Data:', data);
});
}
}
someFunction(42);
var __coverage__ = { /* ... */ };
__coverage__ = __coverage__['fixtures/test.js'];
__coverage__.s['1']++;
var fs = require('fs');
function someFunction(someValue) {
__coverage__.f['1']++;__coverage__.s['3']++;
if (someValue % 2 === 0) {
__coverage__.b['1'][0]++;__coverage__.s['4']++;console.log('foo');
} else {
__coverage__.b['1'][1]++;__coverage__.s['5']++;console.log('bar');
}
__coverage__.s['6']++;switch (someValue) {
case 0:
__coverage__.b['2'][0]++;case 20:
__coverage__.b['2'][1]++;__coverage__.s['7']++;console.log('nope');__coverage__.s['8']++;
break;case 11:
__coverage__.b['2'][2]++;__coverage__.s['9']++;try {
__coverage__.s['10']++;console.log('maybe', 1234 / 0);__coverage__.s['11']++;
throw new Error(':)');
} catch ( e ) {
__coverage__.s['12']++;void 0;__coverage__.s['13']++;console.log('e', e);
} __coverage__.s['14']++;
break;case 42:
__coverage__.b['2'][3]++;__coverage__.s['15']++;fs.readFile('./nonexistant', (err, data) => {
__coverage__.s['16']++;
if (err) {
__coverage__.b['3'][0]++;__coverage__.s['17']++;return 10;
} else {
__coverage__.b['3'][1]++;
}
__coverage__.s['18']++;console.log('Data:', data);
});
}
}
__coverage__.s['19']++;someFunction(42);
process.on('beforeExit', () => {
require('fs').writeFileSync('coverage-fixtures_test.js.json', JSON.stringify(__coverage__), 'utf8');
});
{
"fixtures/test.js": {
"path": "fixtures/test.js",
....
"s": {
"1": 1,
"2": 1,
"3": 1,
....
},
....
"statementMap": {
"1": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"2": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 37,
"column": 1
}
}
}
}
}
var fs = require('fs');
function someFunction(someValue) {
if (someValue % 2 === 0) {
console.log('foo');
} else {}
switch(someValue) {
case 0:
case 20:
break;
case 11:
break;
case 42:
fs.readFile('./nonexistant', (err, data) => {
if (err) {
return 10;
}
});
}
}
someFunction(42);
var fs = require('fs');
function someFunction(someValue) {
if (someValue % 2 === 0) {
console.log('foo');
}
fs.readFile('./nonexistant', (err, data) => {
if (err) {
return 10;
}
});
}
someFunction(42);