|
|
|
/*
|
|
|
|
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 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 ganache = require('ganache-core-sc');
|
|
|
|
const globby = require('globby');
|
|
|
|
|
|
|
|
async function plugin(truffleConfig){
|
|
|
|
let app;
|
|
|
|
let error;
|
|
|
|
let truffle;
|
|
|
|
let testsErrored = false;
|
|
|
|
let coverageConfig;
|
|
|
|
let coverageConfigPath;
|
|
|
|
|
|
|
|
// Load truffle lib, .solcover.js & launch app
|
|
|
|
try {
|
|
|
|
truffle = loadTruffleLibrary();
|
|
|
|
|
|
|
|
coverageConfigPath = path.join(truffleConfig.working_directory, '.solcover.js');
|
|
|
|
coverageConfig = req.silent(coverageConfigPath) || {};
|
|
|
|
|
|
|
|
coverageConfig.cwd = truffleConfig.working_directory;
|
|
|
|
coverageConfig.originalContractsDir = truffleConfig.contracts_directory;
|
|
|
|
|
|
|
|
app = new App(coverageConfig);
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instrument and test..
|
|
|
|
try {
|
|
|
|
death(app.cleanUp);
|
|
|
|
|
|
|
|
// Launch in-process provider
|
|
|
|
const provider = await app.provider(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]);
|
|
|
|
|
|
|
|
// 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(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(truffle){
|
|
|
|
let target;
|
|
|
|
|
|
|
|
(typeof truffle.file === 'string')
|
|
|
|
? target = globby.sync([truffle.file])
|
|
|
|
: target = dir.files(truffle.test_directory, { sync: true }) || [];
|
|
|
|
|
|
|
|
const regex = /.*\.(js|ts|es|es6|jsx|sol)$/;
|
|
|
|
return target.filter(f => f.match(regex) != null);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function loadTruffleLibrary(){
|
|
|
|
try { return require("truffle") } catch(err) {};
|
|
|
|
try { return require("./truffle.library")} catch(err) {};
|
|
|
|
|
|
|
|
// TO DO: throw error? This point should never be reached.
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|