diff --git a/coverageMap.js b/coverageMap.js index d17a0f3..d2880b2 100644 --- a/coverageMap.js +++ b/coverageMap.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,6 +29,7 @@ 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: {}, @@ -56,6 +57,17 @@ module.exports = class CoverageMap { for (let x = 1; x <= Object.keys(info.statementMap).length; x++) { this.coverage[canonicalContractPath].s[x] = 0; } + + const keccakhex = (x => { + const hash = new keccak(256); // eslint-disable-line new-cap + 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,19 +80,20 @@ 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; diff --git a/injector.js b/injector.js index c3dd7a5..d3f687d 100644 --- a/injector.js +++ b/injector.js @@ -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); }; diff --git a/instrumentSolidity.js b/instrumentSolidity.js index 7837a1b..f8cdd6f 100644 --- a/instrumentSolidity.js +++ b/instrumentSolidity.js @@ -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 => 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; }; diff --git a/package.json b/package.json index a3dddae..8db4000 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "commander": "^2.9.0", "ethereumjs-testrpc": "https://github.com/sc-forks/testrpc-sc.git", "istanbul": "^0.4.5", + "keccakjs": "^0.2.1", "mkdirp": "^0.5.1", "req-cwd": "^1.0.1", "shelljs": "^0.7.4", @@ -37,6 +38,6 @@ "istanbul": "^0.4.5", "merkle-patricia-tree": "~2.1.2", "mocha": "^3.1.0", - "solc": "0.4.6" + "solc": "0.4.8" } } diff --git a/runCoveredTests.js b/runCoveredTests.js deleted file mode 100644 index e69de29..0000000