Code coverage for Solidity smart-contracts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
solidity-coverage/instrumentSolidity.js

69 lines
2.4 KiB

const SolidityParser = require('solidity-parser');
const preprocessor = require('./preprocessor');
const injector = require('./injector');
const parse = require('./parse');
// var solparse = require("solparse");
const path = require('path');
module.exports = function instrumentSolidity(contractSource, fileName) {
const contract = {};
contract.source = contractSource;
contract.instrumented = contractSource;
contract.runnableLines = [];
contract.fnMap = {};
contract.fnId = 0;
contract.branchMap = {};
contract.branchId = 0;
contract.statementMap = {};
contract.statementId = 0;
contract.injectionPoints = {};
// First, we run over the original contract to get the source mapping.
let ast = SolidityParser.parse(contract.source);
parse[ast.type](contract, ast);
const retValue = JSON.parse(JSON.stringify(contract));
// Now, we reset almost everything and use the preprocessor first to increase our effectiveness.
contract.runnableLines = [];
contract.fnMap = {};
contract.fnId = 0;
contract.branchMap = {};
contract.branchId = 0;
contract.statementMap = {};
contract.statementId = 0;
contract.injectionPoints = {};
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);
// We have to iterate through these injection points in descending order to not mess up
// the injection process.
const sortedPoints = Object.keys(contract.injectionPoints).sort((a, b) => b - a);
sortedPoints.forEach(injectionPoint => {
// Line instrumentation has to happen first
contract.injectionPoints[injectionPoint].sort((a, b) => {
const eventTypes = ['openParen', 'callBranchEvent', 'callEmptyBranchEvent', 'callEvent'];
return eventTypes.indexOf(b.type) - eventTypes.indexOf(a.type);
});
contract.injectionPoints[injectionPoint].forEach(injection => {
injector[injection.type](contract, fileName, injectionPoint, injection);
});
});
retValue.runnableLines = contract.runnableLines;
retValue.contract = contract.instrumented;
retValue.contractName = contractStatement[0].name;
return retValue;
};