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