Merge branch 'adriamb-master' into truffle3-adriamb

pull/1/head
cgewecke 8 years ago
commit cb833aa386
  1. 31
      coverageMap.js
  2. 18
      injector.js
  3. 6
      instrumentSolidity.js
  4. 3
      package.json
  5. 0
      runCoveredTests.js

@ -5,11 +5,7 @@
*/ */
const SolidityCoder = require('web3/lib/solidity/coder.js'); const SolidityCoder = require('web3/lib/solidity/coder.js');
const path = require('path'); const path = require('path');
const keccak = require('keccakjs');
const lineTopic = 'b8995a65f405d9756b41a334f38d8ff0c93c4934e170d3c1429c3e7ca101014d';
const functionTopic = 'd4ce765fd23c5cc3660249353d61ecd18ca60549dd62cb9ca350a4244de7b87f';
const branchTopic = 'd4cf56ed5ba572684f02f889f12ac42d9583c8e3097802060e949bfbb3c1bff5';
const statementTopic = 'b51abbff580b3a34bbc725f2dc6f736e9d4b45a41293fd0084ad865a31fde0c8';
/** /**
* Converts solcover event data into an object that can be * Converts solcover event data into an object that can be
@ -20,6 +16,10 @@ module.exports = class CoverageMap {
constructor() { constructor() {
this.coverage = {}; this.coverage = {};
this.lineTopics = [];
this.functionTopics = [];
this.branchTopics = [];
this.statementTopics = [];
} }
/** /**
@ -29,6 +29,7 @@ module.exports = class CoverageMap {
* @param {String} canonicalContractPath target file location * @param {String} canonicalContractPath target file location
* @return {Object} coverage map with all values set to zero * @return {Object} coverage map with all values set to zero
*/ */
addContract(info, canonicalContractPath) { addContract(info, canonicalContractPath) {
this.coverage[canonicalContractPath] = { this.coverage[canonicalContractPath] = {
l: {}, l: {},
@ -56,6 +57,17 @@ module.exports = class CoverageMap {
for (let x = 1; x <= Object.keys(info.statementMap).length; x++) { for (let x = 1; x <= Object.keys(info.statementMap).length; x++) {
this.coverage[canonicalContractPath].s[x] = 0; 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) { generate(events, pathPrefix) {
for (let idx = 0; idx < events.length; idx++) { for (let idx = 0; idx < events.length; idx++) {
const event = JSON.parse(events[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 data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = data[0]; const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].l[data[1].toNumber()] += 1; 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 data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = data[0]; const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].f[data[1].toNumber()] += 1; 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 data = SolidityCoder.decodeParams(['string', 'uint256', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = data[0]; const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].b[data[1].toNumber()][data[2].toNumber()] += 1; 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 data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', ''));
const canonicalContractPath = data[0]; const canonicalContractPath = data[0];
this.coverage[canonicalContractPath].s[data[1].toNumber()] += 1; this.coverage[canonicalContractPath].s[data[1].toNumber()] += 1;

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

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

@ -18,6 +18,7 @@
"commander": "^2.9.0", "commander": "^2.9.0",
"ethereumjs-testrpc": "https://github.com/sc-forks/testrpc-sc.git", "ethereumjs-testrpc": "https://github.com/sc-forks/testrpc-sc.git",
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"keccakjs": "^0.2.1",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"req-cwd": "^1.0.1", "req-cwd": "^1.0.1",
"shelljs": "^0.7.4", "shelljs": "^0.7.4",
@ -37,6 +38,6 @@
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"merkle-patricia-tree": "~2.1.2", "merkle-patricia-tree": "~2.1.2",
"mocha": "^3.1.0", "mocha": "^3.1.0",
"solc": "0.4.6" "solc": "0.4.8"
} }
} }

Loading…
Cancel
Save