parent
92fa5e0f77
commit
c91838793e
@ -0,0 +1,164 @@ |
|||||||
|
const API = require('./../lib/api'); |
||||||
|
const utils = require('./plugin-assets/plugin.utils'); |
||||||
|
const buidlerUtils = require('./plugin-assets/buidler.utils'); |
||||||
|
const PluginUI = require('./plugin-assets/buidler.ui'); |
||||||
|
|
||||||
|
const pkg = require('./../package.json'); |
||||||
|
const death = require('death'); |
||||||
|
const path = require('path'); |
||||||
|
const Web3 = require('web3'); |
||||||
|
const ganache = require('ganache-cli'); |
||||||
|
|
||||||
|
const { task, internalTask, types } = require("@nomiclabs/buidler/config"); |
||||||
|
const { ensurePluginLoadedWithUsePlugin } = require("@nomiclabs/buidler/plugins"); |
||||||
|
const { BuidlerPluginError } = require("@nomiclabs/buidler/internal/core/errors"); |
||||||
|
const { createProvider } = require("@nomiclabs/buidler/internal/core/providers/construction"); |
||||||
|
|
||||||
|
const { |
||||||
|
TASK_TEST_RUN_MOCHA_TESTS, |
||||||
|
TASK_TEST, |
||||||
|
TASK_COMPILE, |
||||||
|
} = require("@nomiclabs/buidler/builtin-tasks/task-names"); |
||||||
|
|
||||||
|
const util = require('util'); |
||||||
|
|
||||||
|
function plugin() { |
||||||
|
let api; |
||||||
|
let address; |
||||||
|
let network; |
||||||
|
let error; |
||||||
|
let testsErrored = false; |
||||||
|
|
||||||
|
const ui = new PluginUI(); |
||||||
|
|
||||||
|
extendEnvironment(env => { |
||||||
|
env.config.logger = {log: null}; |
||||||
|
env.config = buidlerUtils.normalizeConfig(env.config); |
||||||
|
|
||||||
|
api = new API(utils.loadSolcoverJS(env.config)); |
||||||
|
|
||||||
|
const networkConfig = { |
||||||
|
url: `http://${api.host}:${api.port}`, |
||||||
|
gas: api.gasLimit, |
||||||
|
gasPrice: api.gasPrice |
||||||
|
} |
||||||
|
|
||||||
|
const provider = createProvider(api.defaultNetworkName, networkConfig); |
||||||
|
|
||||||
|
env.config.networks[api.defaultNetworkName] = networkConfig; |
||||||
|
env.config.defaultNetwork = api.defaultNetworkName; |
||||||
|
|
||||||
|
env.network = { |
||||||
|
name: api.defaultNetworkName, |
||||||
|
config: networkConfig, |
||||||
|
provider: provider, |
||||||
|
} |
||||||
|
|
||||||
|
env.ethereum = provider; |
||||||
|
|
||||||
|
// Keep a reference so we can set the from account
|
||||||
|
network = env.network; |
||||||
|
}) |
||||||
|
|
||||||
|
function myTimeout(){ |
||||||
|
return new Promise(resolve => { |
||||||
|
setTimeout(()=>{ |
||||||
|
console.log('TIMEOUT') |
||||||
|
}, 2000) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
task("timeout", 'desc').setAction(async function(taskArguments, { config }, runSuper){ |
||||||
|
await myTimeout(); |
||||||
|
}); |
||||||
|
|
||||||
|
task("coverage", "Generates a code coverage report for tests") |
||||||
|
|
||||||
|
.addOptionalParam("file", ui.flags.file, null, types.string) |
||||||
|
.addOptionalParam("solcoverjs", ui.flags.solcoverjs, null, types.string) |
||||||
|
.addOptionalParam('temp', ui.flags.temp, null, types.string) |
||||||
|
|
||||||
|
.setAction(async function(taskArguments, { run, config }, runSuper){ |
||||||
|
console.log(util.inspect()) |
||||||
|
try { |
||||||
|
death(buidlerUtils.finish.bind(null, config, api)); // Catch interrupt signals
|
||||||
|
config.logger = {log: null}; |
||||||
|
config = buidlerUtils.normalizeConfig(config); |
||||||
|
|
||||||
|
api = new API(utils.loadSolcoverJS(config)); |
||||||
|
|
||||||
|
// Server launch
|
||||||
|
const address = await api.ganache(ganache); |
||||||
|
const web3 = new Web3(address); |
||||||
|
const accounts = await web3.eth.getAccounts(); |
||||||
|
const nodeInfo = await web3.eth.getNodeInfo(); |
||||||
|
const ganacheVersion = nodeInfo.split('/')[1]; |
||||||
|
|
||||||
|
// Set default account
|
||||||
|
network.from = accounts[0]; |
||||||
|
|
||||||
|
// Version Info
|
||||||
|
ui.report('versions', [ |
||||||
|
ganacheVersion, |
||||||
|
pkg.version |
||||||
|
]); |
||||||
|
|
||||||
|
// Network Info
|
||||||
|
ui.report('network', [ |
||||||
|
api.defaultNetworkName, |
||||||
|
api.port |
||||||
|
]); |
||||||
|
|
||||||
|
// Run post-launch server hook;
|
||||||
|
await api.onServerReady(config); |
||||||
|
|
||||||
|
// Instrument
|
||||||
|
const skipFiles = api.skipFiles || []; |
||||||
|
|
||||||
|
let { |
||||||
|
targets, |
||||||
|
skipped |
||||||
|
} = utils.assembleFiles(config, skipFiles); |
||||||
|
|
||||||
|
targets = api.instrument(targets); |
||||||
|
utils.reportSkipped(config, skipped); |
||||||
|
|
||||||
|
// Filesystem & Compiler Re-configuration
|
||||||
|
const { |
||||||
|
tempArtifactsDir, |
||||||
|
tempContractsDir |
||||||
|
} = utils.getTempLocations(config); |
||||||
|
|
||||||
|
utils.save(targets, config.paths.sources, tempContractsDir); |
||||||
|
utils.save(skipped, config.paths.sources, tempContractsDir); |
||||||
|
|
||||||
|
config.paths.sources = tempContractsDir; |
||||||
|
config.paths.artifacts = tempArtifactsDir; |
||||||
|
config.paths.cache = buidlerUtils.tempCacheDir(config); |
||||||
|
console.log(config.paths.cache) |
||||||
|
|
||||||
|
config.solc.optimizer.enabled = false; |
||||||
|
await run(TASK_COMPILE); |
||||||
|
|
||||||
|
await api.onCompileComplete(config); |
||||||
|
|
||||||
|
try { |
||||||
|
failures = await run(TASK_TEST, {testFiles: []}) |
||||||
|
} catch (e) { |
||||||
|
error = e.stack; |
||||||
|
console.log(e.message + error) |
||||||
|
} |
||||||
|
await api.onTestsComplete(config); |
||||||
|
|
||||||
|
// Run Istanbul
|
||||||
|
await api.report(); |
||||||
|
await api.onIstanbulComplete(config); |
||||||
|
} catch(e) { |
||||||
|
error = e; |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = plugin; |
||||||
|
|
@ -0,0 +1,83 @@ |
|||||||
|
const UI = require('./../../lib/ui').UI; |
||||||
|
|
||||||
|
/** |
||||||
|
* Truffle Plugin logging |
||||||
|
*/ |
||||||
|
class PluginUI extends UI { |
||||||
|
constructor(log){ |
||||||
|
super(log); |
||||||
|
|
||||||
|
this.flags = { |
||||||
|
file: `Path (or glob) defining a subset of tests to run`, |
||||||
|
|
||||||
|
solcoverjs: `Relative path from working directory to config. ` + |
||||||
|
`Useful for monorepo packages that share settings.`, |
||||||
|
|
||||||
|
temp: `Path to a disposable folder to store compilation artifacts in. ` + |
||||||
|
`Useful when your test setup scripts include hard-coded paths to ` + |
||||||
|
`a build directory.`, |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Writes a formatted message via log |
||||||
|
* @param {String} kind message selector |
||||||
|
* @param {String[]} args info to inject into template |
||||||
|
*/ |
||||||
|
report(kind, args=[]){ |
||||||
|
const c = this.chalk; |
||||||
|
const ct = c.bold.green('>'); |
||||||
|
const ds = c.bold.yellow('>'); |
||||||
|
const w = ":warning:"; |
||||||
|
|
||||||
|
const kinds = { |
||||||
|
|
||||||
|
'instr-skip': `\n${c.bold('Coverage skipped for:')}` + |
||||||
|
`\n${c.bold('=====================')}\n`, |
||||||
|
|
||||||
|
'instr-skipped': `${ds} ${c.grey(args[0])}`, |
||||||
|
|
||||||
|
'versions': `${ct} ${c.bold('ganache-core')}: ${args[0]}\n` + |
||||||
|
`${ct} ${c.bold('solidity-coverage')}: v${args[1]}`, |
||||||
|
|
||||||
|
'network': `\n${c.bold('Network Info')}` + |
||||||
|
`\n${c.bold('============')}\n` + |
||||||
|
`${ct} ${c.bold('port')}: ${args[1]}\n` + |
||||||
|
`${ct} ${c.bold('network')}: ${args[0]}\n`, |
||||||
|
} |
||||||
|
|
||||||
|
this._write(kinds[kind]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a formatted message. Useful for error message. |
||||||
|
* @param {String} kind message selector |
||||||
|
* @param {String[]} args info to inject into template |
||||||
|
* @return {String} message |
||||||
|
*/ |
||||||
|
generate(kind, args=[]){ |
||||||
|
const c = this.chalk; |
||||||
|
const x = ":x:"; |
||||||
|
|
||||||
|
const kinds = { |
||||||
|
|
||||||
|
'sources-fail': `${c.red('Cannot locate expected contract sources folder: ')} ${args[0]}`, |
||||||
|
|
||||||
|
'solcoverjs-fail': `${c.red('Could not load .solcover.js config file. ')}` + |
||||||
|
`${c.red('This can happen if it has a syntax error or ')}` + |
||||||
|
`${c.red('the path you specified for it is wrong.')}`, |
||||||
|
|
||||||
|
'tests-fail': `${x} ${c.bold(args[0])} ${c.red('test(s) failed under coverage.')}`, |
||||||
|
|
||||||
|
'no-network': `${c.red('Network: ')} ${args[0]} ` + |
||||||
|
`${c.red(' is not defined in your truffle-config networks. ')}`, |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return this._format(kinds[kind]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = PluginUI; |
@ -0,0 +1,45 @@ |
|||||||
|
const shell = require('shelljs'); |
||||||
|
const pluginUtils = require("./plugin.utils"); |
||||||
|
const path = require('path') |
||||||
|
const util = require('util') |
||||||
|
|
||||||
|
function normalizeConfig(config){ |
||||||
|
config.workingDir = config.paths.root; |
||||||
|
config.contractsDir = config.paths.sources; |
||||||
|
config.testDir = config.paths.tests; |
||||||
|
config.artifactsDir = config.paths.artifacts; |
||||||
|
|
||||||
|
return config; |
||||||
|
} |
||||||
|
|
||||||
|
function tempCacheDir(config){ |
||||||
|
return path.join(config.paths.root, '.coverage_cache'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Silently removes temporary folders and calls api.finish to shut server down |
||||||
|
* @param {buidlerConfig} config |
||||||
|
* @param {SolidityCoverage} api |
||||||
|
* @return {Promise} |
||||||
|
*/ |
||||||
|
async function finish(config, api){ |
||||||
|
const { |
||||||
|
tempContractsDir, |
||||||
|
tempArtifactsDir |
||||||
|
} = pluginUtils.getTempLocations(config); |
||||||
|
|
||||||
|
shell.config.silent = true; |
||||||
|
shell.rm('-Rf', tempContractsDir); |
||||||
|
shell.rm('-Rf', tempArtifactsDir); |
||||||
|
shell.rm('-Rf', path.join(config.paths.root, '.coverage_cache')); |
||||||
|
shell.config.silent = false; |
||||||
|
|
||||||
|
if (api) await api.finish(); |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
normalizeConfig: normalizeConfig, |
||||||
|
finish: finish, |
||||||
|
tempCacheDir: tempCacheDir |
||||||
|
} |
||||||
|
|
@ -0,0 +1,62 @@ |
|||||||
|
const assert = require('assert'); |
||||||
|
const fs = require('fs'); |
||||||
|
const path = require('path') |
||||||
|
const shell = require('shelljs'); |
||||||
|
|
||||||
|
const verify = require('../../util/verifiers') |
||||||
|
const mock = require('../../util/integration'); |
||||||
|
const plugin = require('../../../dist/buidler.plugin'); |
||||||
|
|
||||||
|
const { |
||||||
|
TASK_TEST |
||||||
|
} = require("@nomiclabs/buidler/builtin-tasks/task-names"); |
||||||
|
|
||||||
|
// =======================
|
||||||
|
// Standard Use-case Tests
|
||||||
|
// =======================
|
||||||
|
|
||||||
|
describe.only('Buidler Plugin: standard use cases', function() { |
||||||
|
let buidlerConfig; |
||||||
|
let solcoverConfig; |
||||||
|
|
||||||
|
beforeEach(() => { |
||||||
|
mock.clean(); |
||||||
|
|
||||||
|
mock.loggerOutput.val = ''; |
||||||
|
solcoverConfig = {}; |
||||||
|
buidlerConfig = mock.getDefaultBuidlerConfig(); |
||||||
|
verify.cleanInitialState(); |
||||||
|
}) |
||||||
|
|
||||||
|
afterEach(() => { |
||||||
|
mock.buidlerTearDownEnv(); |
||||||
|
mock.clean(); |
||||||
|
}); |
||||||
|
|
||||||
|
/*it.only('timeout', async function(){ |
||||||
|
mock.buidlerSetupEnv(this); |
||||||
|
this.env.run('timeout') |
||||||
|
});*/ |
||||||
|
|
||||||
|
it('simple contract', async function(){ |
||||||
|
mock.install('Simple', 'simple.js', solcoverConfig); |
||||||
|
mock.buidlerSetupEnv(this); |
||||||
|
|
||||||
|
await this.env.run("coverage"); |
||||||
|
|
||||||
|
/*verify.coverageGenerated(buidlerConfig); |
||||||
|
|
||||||
|
const output = mock.getOutput(buidlerConfig); |
||||||
|
const path = Object.keys(output)[0]; |
||||||
|
|
||||||
|
assert( |
||||||
|
output[path].fnMap['1'].name === 'test', |
||||||
|
'coverage.json missing "test"' |
||||||
|
); |
||||||
|
|
||||||
|
assert( |
||||||
|
output[path].fnMap['2'].name === 'getX', |
||||||
|
'coverage.json missing "getX"' |
||||||
|
);*/ |
||||||
|
}); |
||||||
|
}) |
Loading…
Reference in new issue