Allows contract inheritance

pull/1/head
Adria Massanet 8 years ago
parent 5228fe7054
commit da24a90e0d
  1. 37
      coverageMap.js
  2. 18
      injector.js
  3. 6
      instrumentSolidity.js

@ -5,11 +5,7 @@
*/
const SolidityCoder = require('web3/lib/solidity/coder.js');
const path = require('path');
const lineTopic = 'b8995a65f405d9756b41a334f38d8ff0c93c4934e170d3c1429c3e7ca101014d';
const functionTopic = 'd4ce765fd23c5cc3660249353d61ecd18ca60549dd62cb9ca350a4244de7b87f';
const branchTopic = 'd4cf56ed5ba572684f02f889f12ac42d9583c8e3097802060e949bfbb3c1bff5';
const statementTopic = 'b51abbff580b3a34bbc725f2dc6f736e9d4b45a41293fd0084ad865a31fde0c8';
const keccak = require('keccakjs')
/**
* Converts solcover event data into an object that can be
@ -20,6 +16,10 @@ module.exports = class CoverageMap {
constructor() {
this.coverage = {};
this.lineTopics = []
this.functionTopics = []
this.branchTopics = []
this.statementTopics = []
}
/**
@ -29,7 +29,9 @@ module.exports = class CoverageMap {
* @param {String} canonicalContractPath target file location
* @return {Object} coverage map with all values set to zero
*/
addContract(info, canonicalContractPath) {
this.coverage[canonicalContractPath] = {
l: {},
path: canonicalContractPath,
@ -56,6 +58,18 @@ module.exports = class CoverageMap {
for (let x = 1; x <= Object.keys(info.statementMap).length; x++) {
this.coverage[canonicalContractPath].s[x] = 0;
}
const keccakhex = (x => {
var hash = new keccak(256)
hash.update(x)
return hash.digest('hex')
});
this.lineTopics.push(keccakhex("__Coverage"+info.contractName+"(string,uint256)"));
this.functionTopics.push(keccakhex("__FunctionCoverage"+info.contractName+"(string,uint256)"));
this.branchTopics.push(keccakhex("__BranchCoverage"+info.contractName+"(string,uint256,uint256)"));
this.statementTopics.push(keccakhex("__StatementCoverage"+info.contractName+"(string,uint256)"));
}
/**
@ -68,22 +82,27 @@ module.exports = class CoverageMap {
generate(events, pathPrefix) {
for (let idx = 0; idx < events.length; idx++) {
const event = JSON.parse(events[idx]);
if (event.topics.indexOf(lineTopic) >= 0) {
if (event.topics.filter( t => this.lineTopics.indexOf(t) >= 0 ).length > 0) {
const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].l[data[1].toNumber()] += 1;
} else if (event.topics.indexOf(functionTopic) >= 0) {
} else if (event.topics.filter( t => this.functionTopics.indexOf(t) >= 0 ).length > 0) {
const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].f[data[1].toNumber()] += 1;
} else if (event.topics.indexOf(branchTopic) >= 0) {
} else if (event.topics.filter( t => this.branchTopics.indexOf(t) >= 0 ).length > 0) {
const data = SolidityCoder.decodeParams(['string', 'uint256', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].b[data[1].toNumber()][data[2].toNumber()] += 1;
} else if (event.topics.indexOf(statementTopic) >= 0) {
} else if (event.topics.filter( t => this.statementTopics.indexOf(t) >= 0 ).length > 0) {
const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].s[data[1].toNumber()] += 1;
}
}
return Object.assign({}, this.coverage);

@ -6,27 +6,27 @@ injector.callEvent = function injectCallEvent(contract, fileName, injectionPoint
const linecount = (contract.instrumented.slice(0, injectionPoint).match(/\n/g) || []).length + 1;
contract.runnableLines.push(linecount);
contract.instrumented = contract.instrumented.slice(0, injectionPoint) +
'Coverage(\'' + fileName + '\',' + linecount + ');\n' +
'__Coverage'+contract.contractName+'(\'' + fileName + '\',' + linecount + ');\n' +
contract.instrumented.slice(injectionPoint);
};
injector.callFunctionEvent = function injectCallFunctionEvent(contract, fileName, injectionPoint, injection) {
contract.instrumented = contract.instrumented.slice(0, injectionPoint) +
'FunctionCoverage(\'' + fileName + '\',' + injection.fnId + ');\n' +
'__FunctionCoverage'+contract.contractName+'(\'' + fileName + '\',' + injection.fnId + ');\n' +
contract.instrumented.slice(injectionPoint);
};
injector.callBranchEvent = function injectCallFunctionEvent(contract, fileName, injectionPoint, injection) {
contract.instrumented = contract.instrumented.slice(0, injectionPoint) +
(injection.openBracket ? '{' : '') +
'BranchCoverage(\'' + fileName + '\',' + injection.branchId + ',' + injection.locationIdx + ')' +
'__BranchCoverage'+contract.contractName+'(\'' + fileName + '\',' + injection.branchId + ',' + injection.locationIdx + ')' +
(injection.comma ? ',' : ';') +
contract.instrumented.slice(injectionPoint);
};
injector.callEmptyBranchEvent = function injectCallEmptyBranchEvent(contract, fileName, injectionPoint, injection) {
contract.instrumented = contract.instrumented.slice(0, injectionPoint) +
'else { BranchCoverage(\'' + fileName + '\',' + injection.branchId + ',' + injection.locationIdx + ');}\n' +
'else { __BranchCoverage'+contract.contractName+'(\'' + fileName + '\',' + injection.branchId + ',' + injection.locationIdx + ');}\n' +
contract.instrumented.slice(injectionPoint);
};
@ -44,16 +44,16 @@ injector.literal = function injectLiteral(contract, fileName, injectionPoint, in
injector.statement = function injectStatement(contract, fileName, injectionPoint, injection) {
contract.instrumented = contract.instrumented.slice(0, injectionPoint) +
' StatementCoverage(\'' + fileName + '\',' + injection.statementId + ');\n' +
' __StatementCoverage'+contract.contractName+'(\'' + fileName + '\',' + injection.statementId + ');\n' +
contract.instrumented.slice(injectionPoint);
};
injector.eventDefinition = function injectEventDefinition(contract, fileName, injectionPoint, injection) {
contract.instrumented = contract.instrumented.slice(0, injectionPoint) +
'event Coverage(string fileName, uint256 lineNumber);\n' +
'event FunctionCoverage(string fileName, uint256 fnId);\n' +
'event StatementCoverage(string fileName, uint256 statementId);\n' +
'event BranchCoverage(string fileName, uint256 branchId, uint256 locationIdx);\n' +
'event __Coverage'+contract.contractName+'(string fileName, uint256 lineNumber);\n' +
'event __FunctionCoverage'+contract.contractName+'(string fileName, uint256 fnId);\n' +
'event __StatementCoverage'+contract.contractName+'(string fileName, uint256 statementId);\n' +
'event __BranchCoverage'+contract.contractName+'(string fileName, uint256 branchId, uint256 locationIdx);\n' +
contract.instrumented.slice(injectionPoint);
};

@ -38,8 +38,12 @@ module.exports = function instrumentSolidity(contractSource, fileName) {
contract.preprocessed = preprocessor.run(contract.source);
contract.instrumented = contract.preprocessed;
ast = SolidityParser.parse(contract.preprocessed);
const contractStatement = ast['body'].filter( node => { return node.type == 'ContractStatement' });
contract.contractName = contractStatement[0].name
parse[ast.type](contract, ast);
// var result = solparse.parse(contract);
@ -59,5 +63,7 @@ module.exports = function instrumentSolidity(contractSource, fileName) {
});
retValue.runnableLines = contract.runnableLines;
retValue.contract = contract.instrumented;
retValue.contractName = contractStatement[0].name
return retValue;
};

Loading…
Cancel
Save