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/test/util/util.js

128 lines
3.3 KiB

/**
* Setup and reporting helpers for the suites which test instrumentation
* and coverage correctness. (Integration test helpers are elsewhere)
*/
const fs = require('fs');
const path = require('path');
const solc = require('solc');
const TruffleContract = require('@truffle/contract');
const Instrumenter = require('./../../lib/instrumenter');
const DataCollector = require('./../../lib/collector')
// ====================
// Paths / Files
// ====================
const filePath = path.resolve('./test.sol');
const pathPrefix = './';
// ====================
// Contract deployments
// ====================
function getABI(solcOutput, testFile="test.sol", testName="Test"){
return solcOutput.contracts[testFile][testName].abi;
}
function getBytecode(solcOutput, testFile="test.sol", testName="Test"){
return `0x${solcOutput.contracts[testFile][testName].evm.bytecode.object}`;
}
async function getDeployedContractInstance(info, provider){
const contract = TruffleContract({
abi: getABI(info.solcOutput),
bytecode: getBytecode(info.solcOutput)
})
contract.setProvider(provider);
contract.autoGas = false;
const accounts = await contract.web3.eth.getAccounts();
contract.defaults({
gas: 5500000,
gasPrice: 1,
from: accounts[0]
});
return contract.new();
}
// ============
// Compilation
// ============
function getCode(_path) {
const pathToSources = `./../sources/solidity/contracts/${_path}`;
return fs.readFileSync(path.join(__dirname, pathToSources), 'utf8');
};
function compile(source){
const compilerInput = codeToCompilerInput(source);
return JSON.parse(solc.compile(compilerInput));
}
function codeToCompilerInput(code) {
return JSON.stringify({
language: 'Solidity',
sources: { 'test.sol': { content: code } },
settings: { outputSelection: {'*': { '*': [ '*' ] }} }
});
}
// ============================
// Instrumentation Correctness
// ============================
function instrumentAndCompile(sourceName, api={}) {
const contract = getCode(`${sourceName}.sol`)
const instrumenter = new Instrumenter(api.config);
const instrumented = instrumenter.instrument(contract, filePath);
return {
contract: contract,
instrumented: instrumented,
solcOutput: compile(instrumented.contract),
data: instrumenter.instrumentationData
}
}
function report(output=[]) {
output.forEach(item => {
if (item.severity === 'error') {
const errors = JSON.stringify(output, null, ' ');
throw new Error(`Instrumentation fault: ${errors}`);
}
});
}
// =====================
// Coverage Correctness
// =====================
async function bootstrapCoverage(file, api){
const info = instrumentAndCompile(file, api);
info.instance = await getDeployedContractInstance(info, api.server.provider);
api.collector._setInstrumentationData(info.data);
return info;
}
// =========
// Provider
// =========
function initializeProvider(ganache){
const collector = new DataCollector();
const options = { logger: { log: collector.step.bind(collector) }};
const provider = ganache.provider(options);
return {
provider: provider,
collector: collector
}
}
module.exports = {
getCode: getCode,
pathPrefix: pathPrefix,
filePath: filePath,
report: report,
instrumentAndCompile: instrumentAndCompile,
bootstrapCoverage: bootstrapCoverage,
initializeProvider: initializeProvider,
}