Add function tracking

uport
Alex Rea 8 years ago
parent b5ca8b3da8
commit c6db87ff44
  1. 278
      instrumentSolidity.js
  2. 42
      runCoveredTests.js

@ -3,7 +3,7 @@ var solparse = require("solparse");
var fs = require('fs'); var fs = require('fs');
var path = require("path"); var path = require("path");
module.exports = function(pathToFile, instrument){ module.exports = function(pathToFile, instrumentingActive){
// var result = SolidityParser.parseFile("./" + pathToFile); // var result = SolidityParser.parseFile("./" + pathToFile);
var contract = fs.readFileSync("./" + pathToFile).toString(); var contract = fs.readFileSync("./" + pathToFile).toString();
@ -12,40 +12,38 @@ module.exports = function(pathToFile, instrument){
const __INDENTATION__ = " "; const __INDENTATION__ = " ";
var parse = {}; var parse = {};
var runnableLines=[]; var runnableLines=[];
var fnMap = {};
var fnId = 0;
var linecount = 1; var linecount = 1;
var fileName = path.basename(pathToFile); var fileName = path.basename(pathToFile);
var dottable = ['msg', 'tx', 'this', 'bytes']; var injectionPoints = {};
function addInstrumentationEvent(charcount){
function addInstrumentationEvent(){ injectionPoints[charcount] = {type:"callEvent"};
runnableLines.push(linecount);
return "Coverage('" + fileName + "'," + linecount + ");\n"; return "Coverage('" + fileName + "'," + linecount + ");\n";
} }
parse["AssignmentExpression"] = function (expression, instrument){ parse["AssignmentExpression"] = function (expression, instrument){
if (instrument){ retval += addInstrumentationEvent(); } if (instrument){ retval += addInstrumentationEvent(expression.start); }
var retval = ""; var retval = "";
retval += parse[expression.left.type](expression.left, instrument); retval += parse[expression.left.type](expression.left, instrument);
retval += expression.operator; retval += expression.operator;
retval += parse[expression.right.type](expression.right, instrument) + ';'; retval += parse[expression.right.type](expression.right, instrument) + ';';
if (dottable.indexOf(expression.right.name)>=0){
dottable.push(expression.left.name);
}
return retval; return retval;
} }
parse["ConditionalExpression"] = function(expression){ parse["ConditionalExpression"] = function(expression, instrument){
return parse[expression.test.left.type](expression.test.left) + expression.test.operator + parse[expression.test.right.type](expression.test.right) + '?' + parse[expression.consequent.type](expression.consequent) + ":" + parse[expression.alternate.type](expression.alternate); return parse[expression.test.left.type](expression.test.left) + expression.test.operator + parse[expression.test.right.type](expression.test.right) + '?' + parse[expression.consequent.type](expression.consequent) + ":" + parse[expression.alternate.type](expression.alternate);
} }
parse["Identifier"] = function(expression){ parse["Identifier"] = function(expression, instrument){
return expression.name; return expression.name;
} }
parse["InformalParameter"] = function(expression){ parse["InformalParameter"] = function(expression, instrument){
return expression.literal.literal; return expression.literal.literal;
} }
parse["Literal"] = function(expression){ parse["Literal"] = function(expression, instrument){
if (typeof expression.value==='string' && expression.value.slice(0,2)!=="0x"){ if (typeof expression.value==='string' && expression.value.slice(0,2)!=="0x"){
return '"' + expression.value + '"'; return '"' + expression.value + '"';
}else{ }else{
@ -53,7 +51,7 @@ module.exports = function(pathToFile, instrument){
} }
} }
parse["ModifierName"] = function(expression){ parse["ModifierName"] = function(expression, instrument){
var retvalue = expression.name var retvalue = expression.name
if (expression.params && expression.params.length>0){ if (expression.params && expression.params.length>0){
retvalue += '('; retvalue += '(';
@ -98,18 +96,18 @@ module.exports = function(pathToFile, instrument){
} }
parse["ThisExpression"] = function(expression){ parse["ThisExpression"] = function(expression, instrument){
return 'this' return 'this'
} }
parse["ReturnStatement"] = function(expression, instrument){ parse["ReturnStatement"] = function(expression, instrument){
var retval = ""; var retval = "";
if (instrument){ retval += addInstrumentationEvent(); } if (instrument){ retval += addInstrumentationEvent(expression.start); }
return retval + 'return ' + parse[expression.argument.type](expression.argument, instrument) + ';'; return retval + 'return ' + parse[expression.argument.type](expression.argument, instrument) + ';';
} }
parse["NewExpression"] = function(expression){ parse["NewExpression"] = function(expression, instrument){
var retval = 'new ' + parse[expression.callee.type](expression.callee); var retval = 'new ' + parse[expression.callee.type](expression.callee);
retval += '('; retval += '(';
for (x in expression.arguments){ for (x in expression.arguments){
@ -124,12 +122,6 @@ module.exports = function(pathToFile, instrument){
} }
parse["MemberExpression"] = function (expression){ parse["MemberExpression"] = function (expression){
// return contract.slice(expression.start, expression.end);
// var shouldDot = false;
// if (dottable.indexOf(expression.object.name)>=0){shouldDot = true;}
// if (expression.object.callee){
// if (dottable.indexOf(expression.object.callee.name)>=0){shouldDot=true;}
// }
if (!expression.computed){ if (!expression.computed){
return parse[expression.object.type](expression.object) + "." + parse[expression.property.type](expression.property); return parse[expression.object.type](expression.object) + "." + parse[expression.property.type](expression.property);
}else{ }else{
@ -150,7 +142,7 @@ module.exports = function(pathToFile, instrument){
return retval return retval
} }
parse["UnaryExpression"] = function(expression){ parse["UnaryExpression"] = function(expression, instrument){
if (expression.operator==='delete'){ if (expression.operator==='delete'){
return expression.operator + ' ' + parse[expression.argument.type](expression.argument); return expression.operator + ' ' + parse[expression.argument.type](expression.argument);
@ -160,17 +152,17 @@ module.exports = function(pathToFile, instrument){
parse["ThrowStatement"] = function(expression, instrument){ parse["ThrowStatement"] = function(expression, instrument){
var retval = ""; var retval = "";
if (instrument){ retval += addInstrumentationEvent(); } if (instrument){ retval += addInstrumentationEvent(expression.start); }
return retval + 'throw' return retval + 'throw'
} }
parse["BinaryExpression"] = function(expression){ parse["BinaryExpression"] = function(expression, instrument){
return '(' + parse[expression.left.type](expression.left) + expression.operator + parse[expression.right.type](expression.right) + ')'; return '(' + parse[expression.left.type](expression.left) + expression.operator + parse[expression.right.type](expression.right) + ')';
} }
parse["IfStatement"] = function(expression, instrument){ parse["IfStatement"] = function(expression, instrument){
var retval = ""; var retval = "";
if (instrument){ retval += addInstrumentationEvent(); } if (instrument){ retval += addInstrumentationEvent(expression.start); }
retval += "if ("; retval += "if (";
retval += parse[expression.test.type](expression.test, instrument) + "){" retval += parse[expression.test.type](expression.test, instrument) + "){"
retval += newLine('{'); retval += newLine('{');
@ -192,7 +184,7 @@ module.exports = function(pathToFile, instrument){
return retval; return retval;
} }
parse["SequenceExpression"] = function(expression){ parse["SequenceExpression"] = function(expression, instrument){
retval = "("; retval = "(";
for (x in expression.expressions){ for (x in expression.expressions){
retval += parse[expression.expressions[x].type](expression.expressions[x]) + ', '; retval += parse[expression.expressions[x].type](expression.expressions[x]) + ', ';
@ -205,18 +197,17 @@ module.exports = function(pathToFile, instrument){
return retval; return retval;
} }
parse["ImportStatement"] = function(expression){ parse["ImportStatement"] = function(expression, instrument){
dottable.push(expression.from.slice(0,-4));
return 'import "' + expression.from + '"'; return 'import "' + expression.from + '"';
} }
parse["DeclarativeExpression"] = function(expression){ parse["DeclarativeExpression"] = function(expression, instrument){
return expression.literal.literal + ' ' + (expression.is_public ? "public " : "") + (expression.is_constant ? "constant " : "") + expression.name; return expression.literal.literal + ' ' + (expression.is_public ? "public " : "") + (expression.is_constant ? "constant " : "") + expression.name;
} }
parse["ExpressionStatement"] = function(content, instrument){ parse["ExpressionStatement"] = function(content, instrument){
var retval = ""; var retval = "";
if (instrument){ retval += addInstrumentationEvent(); } if (instrument){ retval += addInstrumentationEvent(content.start); }
if (content.expression.literal && content.expression.literal.literal && content.expression.literal.literal.type==="MappingExpression"){ if (content.expression.literal && content.expression.literal.literal && content.expression.literal.literal.type==="MappingExpression"){
return retval + 'mapping (' + content.expression.literal.literal.from.literal + ' => ' + content.expression.literal.literal.to.literal + ') '+ content.expression.name; return retval + 'mapping (' + content.expression.literal.literal.from.literal + ' => ' + content.expression.literal.literal.to.literal + ') '+ content.expression.name;
}else { }else {
@ -224,9 +215,8 @@ module.exports = function(pathToFile, instrument){
} }
} }
parse["EnumDeclaration"] = function(expression){ parse["EnumDeclaration"] = function(expression, instrument){
var retvalue = 'enum ' + expression.name + ' {'; var retvalue = 'enum ' + expression.name + ' {';
dottable.push(expression.name);
for (x in expression.members){ for (x in expression.members){
retvalue += expression.members[x] + ', '; retvalue += expression.members[x] + ', ';
} }
@ -235,7 +225,7 @@ module.exports = function(pathToFile, instrument){
return retvalue; return retvalue;
} }
parse["EventDeclaration"]=function(expression){ parse["EventDeclaration"]=function(expression, instrument){
var retval = 'event ' + expression.name + '('; var retval = 'event ' + expression.name + '(';
for (x in expression.params){ for (x in expression.params){
var param = expression.params[x]; var param = expression.params[x];
@ -249,9 +239,9 @@ module.exports = function(pathToFile, instrument){
return retval return retval
} }
parse["VariableDeclarationTuple"] = function(expression){ parse["VariableDeclarationTuple"] = function(expression, instrument){
var retval = ""; var retval = "";
if (instrument){ retval += addInstrumentationEvent(); } if (instrument){ retval += addInstrumentationEvent(expression.start); }
retval += "var ("; retval += "var (";
for (x in expression.declarations){ for (x in expression.declarations){
@ -277,19 +267,20 @@ module.exports = function(pathToFile, instrument){
console.log('more than one declaration') console.log('more than one declaration')
} }
retval = ""; retval = "";
if (instrument){ retval += addInstrumentationEvent(); } if (instrument){ retval += addInstrumentationEvent(expression.start); }
return retval + "var " + parse[expression.declarations[0].id.type](expression.declarations[0].id) + " = " + parse[expression.declarations[0].init.type](expression.declarations[0].init); return retval + "var " + parse[expression.declarations[0].id.type](expression.declarations[0].id) + " = " + parse[expression.declarations[0].init.type](expression.declarations[0].init);
} }
parse["Type"] = function(expression){ parse["Type"] = function(expression, instrument){
return expression.literal; return expression.literal;
} }
parse["UsingStatement"] = function(expression){ parse["UsingStatement"] = function(expression, instrument){
return "using " + expression.library + " for " + parse[expression.for.type](expression.for) + ";"; return "using " + expression.library + " for " + parse[expression.for.type](expression.for) + ";";
} }
parse["FunctionDeclaration"] = function(expression){ parse["FunctionDeclaration"] = function(expression, instrument){
retval = 'function ' + (expression.name ? expression.name : "") + '(' retval = 'function ' + (expression.name ? expression.name : "") + '('
for (x in expression.params){ for (x in expression.params){
var param = expression.params[x]; var param = expression.params[x];
@ -301,123 +292,154 @@ module.exports = function(pathToFile, instrument){
retval += ')'; retval += ')';
retval += parse["Modifiers"](expression.modifiers); retval += parse["Modifiers"](expression.modifiers);
if (expression.body){ if (expression.body){
fnId+=1;
linecount = (contract.slice(0,expression.start).match(/\n/g)||[]).length + 1;
//We need to work out the lines and columns the function declaration starts and ends
var startline = linecount;
var startcol = expression.start - contract.slice(0,expression.start).lastIndexOf('\n');
var endlineDelta = contract.slice(expression.start).indexOf('{')+1;
var functionDefinition = contract.slice(expression.start, expression.start + endlineDelta);
var endline = startline + (functionDefinition.match(/\n/g)||[]).length;
var endcol = functionDefinition.length - functionDefinition.lastIndexOf('\n')
fnMap[fnId] = {name: expression.name, line: linecount, loc:{start:{line: startline, col:startcol},end:{line:endline, col:endcol}}}
injectionPoints[expression.start + endlineDelta +1] = {type: "callFunctionEvent", fnId: fnId};
retval+='{' + newLine('{'); retval+='{' + newLine('{');
retval += parse[expression.body.type](expression.body, instrument); retval += parse[expression.body.type](expression.body, instrumentingActive);
retval+='}' + newLine('}'); retval+='}' + newLine('}');
} }
return retval; return retval;
} }
function newLine(lastchar){ parse["ContractStatement"] = function(expression, instrument){
linecount+=1; var retval = "";
if (['}','{',';','_','\n'].indexOf(lastchar)>-1){ retval += 'contract ' + expression.name
return '\n';
}else{
return ';\n';
}
if (expression.is.length>0){
retval += ' is '
for (x in expression.is){
retval += expression.is[x].name + ', '
}
retval = retval.slice(0,-2);
} }
printBody(result,0, false); retval += ' {' + newLine('{');
//Inject our coverage event if we're covering
function printBody(content, indented, cover){ if (instrumentingActive){
if (content.body){ //This is harder because of where .start and .end represent, and how documented comments are validated
if (content.type === "ContractStatement"){ //by solc upon compilation. From the start of this contract statement, find the first '{', and inject
instrumented += 'contract ' + content.name //there.
injectionPoints[expression.start + contract.slice(expression.start).indexOf('{')+2] = {type:"eventDefinition"};
retval += "event Coverage(string fileName, uint256 lineNumber);\n"; //We're injecting this, so don't count the newline
}
if (content.is.length>0){ for (x in expression.body){
instrumented += ' is ' retval+=parse[expression.body[x].type](expression.body[x], instrument);
for (x in content.is){ retval += newLine(retval.slice(-1));
instrumented += content.is[x].name + ', '
} }
instrumented = instrumented.slice(0,-2); retval += '}' + newLine('}');
return retval;
} }
instrumented += ' {' + newLine('{'); parse["LibraryStatement"] = function(expression, instrument){
//Inject our coverage event if we're covering var retval = "";
if (instrument){ retval += 'library ' + expression.name + ' {' + newLine('{');
instrumented += "event Coverage(string fileName, uint256 lineNumber);\n"; //We're injecting this, so don't count the newline
}
for (x in content.body){
printBody(content.body[x], indented+1, cover);
}
instrumented += '}' + newLine('}');
}else if (content.type === "FunctionDeclaration"){
instrumented += parse[content.type](content);
// instrumented += __INDENTATION__.repeat(indented) + 'function ' + (content.name ? content.name : "") + '('
// for (x in content.params){
// var param = content.params[x];
// instrumented += param.literal.literal + ' ' + (param.isIndexed ? 'true' : '') + param.id + ', ';
// if (param.literal.literal==='address'){
// dottable.push(param.id);
// }
// }
// if (content.params && content.params.length>0){
// instrumented = instrumented.slice(0,-2);
// }
// instrumented += ')';
// instrumented += parse["Modifiers"](content.modifiers);
// instrumented+='{' + newLine('{');
// printBody(content.body, indented+1, instrument);
// instrumented+=__INDENTATION__.repeat(indented) +'}' + newLine('}');
}else if (content.type === "LibraryStatement"){
instrumented += 'library ' + content.name + ' {' + newLine('{');
//Inject our coverage event; //Inject our coverage event;
instrumented += "event Coverage(string fileName, uint256 lineNumber);\n"; //We're injecting this, so don't count the newline if(instrumentingActive){
for (x in content.body){ //This is harder because of where .start and .end represent, and how documented comments are validated
printBody(content.body[x], indented+1, cover); //by solc upon compilation. From the start of this contract statement, find the first '{', and inject
//there.
injectionPoints[expression.start + contract.slice(expression.start).indexOf('{')+2] = {type:"eventDefinition"};
retval += "event Coverage(string fileName, uint256 lineNumber);\n"; //We're injecting this, so don't count the newline
} }
instrumented += '}' + newLine('}');
}else if (content.type === "ModifierDeclaration"){ for (x in expression.body){
instrumented += 'modifier ' + content.name + '('; retval+=parse[expression.body[x].type](expression.body[x], instrument);
for (x in content.params){ retval += newLine(retval.slice(-1));
var param = content.params[x];
instrumented += param.literal.literal + ' ' + (param.isIndexed ? 'true' : '') + param.id + ', ';
} }
if (content.params && content.params.length>0){ retval += '}' + newLine('}');
instrumented = instrumented.slice(0,-2);
return retval;
} }
instrumented += '){';
instrumented += newLine(instrumented.slice(-1));
instrumented += parse[content.body.type](content.body, instrument);
instrumented += newLine(instrumented.slice(-1));
instrumented +='}';
instrumented += newLine(instrumented.slice(-1));
}else if (content.type === "BlockStatement"){ parse["ModifierDeclaration"] = function(expression, instrument){
instrumented += parse['BlockStatement'](content, cover); var retval = "";
}else if (content.type ==="Program"){ retval += 'modifier ' + expression.name + '(';
//I don't think we need to do anything here... for (x in expression.params){
for (x in content.body){ var param = expression.params[x];
printBody(content.body[x], indented, cover); retval += param.literal.literal + ' ' + (param.isIndexed ? 'true' : '') + param.id + ', ';
}
if (expression.params && expression.params.length>0){
retval = retval.slice(0,-2);
}
retval += '){';
retval += newLine(retval.slice(-1));
retval += parse[expression.body.type](expression.body, instrumentingActive);
retval += newLine(retval.slice(-1));
retval +='}';
retval += newLine(retval.slice(-1));
return retval;
} }
}else{ parse["Program"] = function(expression, instrument){
console.log(content); retval = "";
process.exit() for (x in expression.body){
for (x in content.body){ retval+=parse[expression.body[x].type](expression.body[x], instrument);
printBody(content.body[x], indented, cover); retval += newLine(retval.slice(-1));
} }
return retval;
} }
function newLine(lastchar){
linecount+=1;
if (['}','{',';','_','\n'].indexOf(lastchar)>-1){
return '\n';
}else{ }else{
if (parse[content.type]!==undefined){ return ';\n';
if (cover){
instrumented += __INDENTATION__.repeat(indented) +"Coverage('" + fileName + "'," + linecount + ");\n";
runnableLines.push(linecount);
} }
instrumented += __INDENTATION__.repeat(indented) + parse[content.type](content);
instrumented += newLine(instrumented.slice(-1));
}else{
console.log(content);
} }
var instrumented = parse[result.type](result);
//We have to iterate through these injection points in descending order to not mess up
//the injection process.
var sortedPoints = Object.keys(injectionPoints).sort(function(a,b){return a-b});
for (x = sortedPoints.length-1; x>=0; x--){
injectionPoint = sortedPoints[x];
if (injectionPoints[injectionPoint].type==='callEvent'){
linecount = (contract.slice(0, injectionPoint).match(/\n/g)||[]).length + 1;
runnableLines.push(linecount);
contract = contract.slice(0, injectionPoint) + "Coverage('" + fileName + "'," + linecount + ");\n" + contract.slice(injectionPoint);
}else if (injectionPoints[injectionPoint].type==='callFunctionEvent'){
contract = contract.slice(0, injectionPoint) + "FunctionCoverage('" + fileName + "'," + injectionPoints[injectionPoint].fnId + ");\n" + contract.slice(injectionPoint);
}else{
contract = contract.slice(0, injectionPoint) + "event Coverage(string fileName, uint256 lineNumber);\nevent FunctionCoverage(string fileName, uint256 fnId);\n" + contract.slice(injectionPoint);
} }
} }
return {contract: contract, runnableLines: runnableLines, fnMap: fnMap};
}
return {contract: instrumented, runnableLines: runnableLines};
}

@ -9,23 +9,28 @@ var path = require('path');
var getInstrumentedVersion = require('./instrumentSolidity.js'); var getInstrumentedVersion = require('./instrumentSolidity.js');
shell.mkdir('./canonicalContracts/');
shell.mv('./contracts/', './originalContracts'); shell.mv('./contracts/', './originalContracts');
shell.mkdir('./contracts/'); shell.mkdir('./contracts/');
//For each contract in originalContracts, get the canonical version and the instrumented version //For each contract in originalContracts, get the instrumented version
shell.ls('./originalContracts/*.sol').forEach(function(file) { shell.ls('./originalContracts/*.sol').forEach(function(file) {
if (file !== 'originalContracts/Migrations.sol') { if (file !== 'originalContracts/Migrations.sol') {
console.log("=================") console.log("=================")
console.log(file); console.log(file);
console.log("=================") console.log("=================")
var instrumentedContractInfo = getInstrumentedVersion(file, true); var instrumentedContractInfo = getInstrumentedVersion(file, true);
var canonicalContractInfo = getInstrumentedVersion(file, false);
fs.writeFileSync('./canonicalContracts/' + path.basename(file), canonicalContractInfo.contract);
fs.writeFileSync('./contracts/' + path.basename(file), instrumentedContractInfo.contract); fs.writeFileSync('./contracts/' + path.basename(file), instrumentedContractInfo.contract);
var canonicalContractPath = path.resolve('./originalContracts/' + path.basename(file));
coverage[canonicalContractPath] = { "l": {}, "path": canonicalContractPath, "s": {}, "b": {}, "f": {}, "fnMap": {}, "statementMap": {}, "branchMap": {} };
for (idx in instrumentedContractInfo.runnableLines) {
coverage[canonicalContractPath]["l"][instrumentedContractInfo.runnableLines[idx]] = 0;
}
coverage[canonicalContractPath].fnMap = instrumentedContractInfo.fnMap;
for (x=1; x<=Object.keys(instrumentedContractInfo.fnMap).length; x++ ){
coverage[canonicalContractPath]["f"][x] = 0;
}
} }
}); });
shell.cp("./originalContracts/Migrations.sol", "./contracts/Migrations.sol"); shell.cp("./originalContracts/Migrations.sol", "./contracts/Migrations.sol");
shell.cp("./originalContracts/Migrations.sol", "./canonicalContracts/Migrations.sol");
var filter = web3.eth.filter('latest'); var filter = web3.eth.filter('latest');
var res = web3.currentProvider.send({ var res = web3.currentProvider.send({
@ -36,18 +41,7 @@ var res = web3.currentProvider.send({
}); });
var filterid = res.result; var filterid = res.result;
shell.exec("truffle test"); shell.exec("truffle test");
//Again, once that truffle issue gets solved, we don't have to call these again here
shell.ls('./originalContracts/*.sol').forEach(function(file) {
if (file !== './originalContracts/Migrations.sol') {
var canonicalContractPath = path.resolve('./canonicalContracts/' + path.basename(file));
coverage[canonicalContractPath] = { "l": {}, "path": canonicalContractPath, "s": {}, "b": {}, "f": {}, "fnMap": {}, "statementMap": {}, "branchMap": {} };
var instrumentedContractInfo = getInstrumentedVersion(file, true);
var canonicalContractInfo = getInstrumentedVersion(file, false);
for (idx in instrumentedContractInfo.runnableLines) {
coverage[canonicalContractPath]["l"][instrumentedContractInfo.runnableLines[idx]] = 0;
}
}
})
var res = web3.currentProvider.send({ var res = web3.currentProvider.send({
jsonrpc: '2.0', jsonrpc: '2.0',
@ -61,16 +55,20 @@ for (idx in res.result) {
var event = res.result[idx]; var event = res.result[idx];
if (event.topics.indexOf("0xb8995a65f405d9756b41a334f38d8ff0c93c4934e170d3c1429c3e7ca101014d") >= 0) { if (event.topics.indexOf("0xb8995a65f405d9756b41a334f38d8ff0c93c4934e170d3c1429c3e7ca101014d") >= 0) {
var data = SolidityCoder.decodeParams(["string", "uint256"], event.data.replace("0x", "")); var data = SolidityCoder.decodeParams(["string", "uint256"], event.data.replace("0x", ""));
var canonicalContractPath = path.resolve('./canonicalContracts/' + path.basename(data[0])); var canonicalContractPath = path.resolve('./originalContracts/' + path.basename(data[0]));
coverage[canonicalContractPath]["l"][data[1].toNumber()] += 1; coverage[canonicalContractPath]["l"][data[1].toNumber()] += 1;
}else if(event.topics.indexOf("0xd4ce765fd23c5cc3660249353d61ecd18ca60549dd62cb9ca350a4244de7b87f")>=0){
var data = SolidityCoder.decodeParams(["string", "uint256"], event.data.replace("0x", ""));
var canonicalContractPath = path.resolve('./originalContracts/' + path.basename(data[0]));
coverage[canonicalContractPath]["f"][data[1].toNumber()] += 1;
} }
} }
fs.writeFileSync('./coverage.json', JSON.stringify(coverage)); fs.writeFileSync('./coverage.json', JSON.stringify(coverage));
shell.exec("istanbul report html") shell.exec("istanbul report html")
shell.rm('-rf', './contracts'); // shell.rm('-rf', './contracts');
shell.rm('-rf', './canonicalContracts'); // shell.rm('-rf', './canonicalContracts');
shell.mv('./originalContracts', './contracts'); // shell.mv('./originalContracts', './contracts');

Loading…
Cancel
Save