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/dist/truffle.plugin.js

209 lines
5.7 KiB

/*
TruffleConfig Paths
===========================
build_directory /users/myPath/to/someProject/build
contracts_directory. /users/myPath/to/someProject/contracts
working_directory /users/myPath/to/someProject
contracts_build_directory /users/myPath/to/someProject/build/contracts
Compilation options override
----------------------------
build_directory /users/myPath/to/someProject/.coverageArtifacts
contracts_directory /users/myPath/to/someProject/.coverageContracts
Test options override
---------------------
contracts_directory, /users/myPath/to/someProject/.coverageContracts
contracts_build_directory, /users/myPath/to/someProject/.coverageArtifacts/contracts
provider ganache.provider (async b/c vm must be resolved)
logger add filter for unused variables...
Truffle Lib API
===============
load: const truffle = require("truffle") (or require("sc-truffle"))
compilation: await truffle.contracts.compile(config)
test: await truffle.test.run(config)
*/
const App = require('./../lib/app');
const pkg = require('./../package.json');
const req = require('req-cwd');
const death = require('death');
const path = require('path');
const dir = require('node-dir');
const Web3 = require('web3');
const util = require('util');
const globby = require('globby');
const globalModules = require('global-modules');
async function plugin(truffleConfig){
let app;
let error;
let truffle;
let testsErrored = false;
let coverageConfig;
let solcoverjs;
// Load truffle lib, .solcover.js & launch app
try {
(truffleConfig.solcoverjs)
? solcoverjs = path.join(truffleConfig.working_directory, truffleConfig.solcoverjs)
: solcoverjs = path.join(truffleConfig.working_directory, '.solcover.js');
coverageConfig = req.silent(solcoverjs) || {};
coverageConfig.cwd = truffleConfig.working_directory;
coverageConfig.originalContractsDir = truffleConfig.contracts_directory;
coverageConfig.log = coverageConfig.log || truffleConfig.logger.log;
app = new App(coverageConfig);
if (truffleConfig.help){
return app.ui.report('truffle-help')
}
truffle = loadTruffleLibrary(app);
} catch (err) {
throw err;
}
// Instrument and test..
try {
death(app.cleanUp); // This doesn't work...
// Launch in-process provider
const provider = await app.provider(truffle.ganache);
const web3 = new Web3(provider);
const accounts = await web3.eth.getAccounts();
const nodeInfo = await web3.eth.getNodeInfo();
const ganacheVersion = nodeInfo.split('/')[1];
app.ui.report('truffle-version', [truffle.version]);
app.ui.report('ganache-version', [ganacheVersion]);
app.ui.report('coverage-version',[pkg.version]);
// Bail early if user ran: --version
if (truffleConfig.version) return;
// Write instrumented sources to temp folder
app.instrument();
// Ask truffle to use temp folders
truffleConfig.contracts_directory = app.contractsDir;
truffleConfig.build_directory = app.artifactsDir;
truffleConfig.contracts_build_directory = paths.artifacts(truffleConfig, app);
// Additional config
truffleConfig.all = true;
truffleConfig.test_files = tests(app, truffleConfig);
truffleConfig.compilers.solc.settings.optimizer.enabled = false;
// Compile
await truffle.contracts.compile(truffleConfig);
// Launch in-process provider
const networkName = 'soliditycoverage';
truffleConfig.network = networkName;
// Truffle alternately complains that fields are and
// are not manually set
try {
truffleConfig.network_id = "*";
truffleConfig.provider = provider;
} catch (err){}
truffleConfig.networks[networkName] = {
network_id: "*",
provider: provider,
gas: app.gasLimit,
gasPrice: app.gasPrice,
from: accounts[0]
}
// Run tests
try {
failures = await truffle.test.run(truffleConfig)
} catch (e) {
error = e.stack;
}
// Run Istanbul
await app.report();
} catch(e){
error = e;
}
// Finish
await app.cleanUp();
if (error !== undefined) throw error;
if (failures > 0) throw new Error(`${failures} test(s) failed under coverage.`)
}
// -------------------------------------- Helpers --------------------------------------------------
function tests(app, truffle){
let target;
(typeof truffle.file === 'string')
? target = globby.sync([truffle.file])
: target = dir.files(truffle.test_directory, { sync: true }) || [];
const solregex = /.*\.(sol)$/;
const hasSols = target.filter(f => f.match(solregex) != null);
if (hasSols.length > 0) app.ui.report('sol-tests', [hasSols.length]);
const testregex = /.*\.(js|ts|es|es6|jsx)$/;
return target.filter(f => f.match(testregex) != null);
}
function loadTruffleLibrary(app){
// Case: from local node_modules
try {
const lib = require("truffle");
app.ui.report('truffle-local');
return lib;
} catch(err) {};
// Case: global
try {
const globalTruffle = path.join(globalModules, 'truffle');
const lib = require(globalTruffle);
app.ui.report('truffle-global');
return lib;
} catch(err) {};
// Default: fallback
try {
app.ui.report('truffle-warn');
return require("./truffle.library")}
catch(err) {
const msg = app.ui.generate('truffle-fail', [err]);
throw new Error(msg);
};
}
/**
* Functions to generate substitute paths for instrumented contracts and artifacts.
* @type {Object}
*/
const paths = {
// "contracts_build_directory":
artifacts: (truffle, app) => {
return path.join(
app.artifactsDir,
path.basename(truffle.contracts_build_directory)
)
}
}
module.exports = plugin;