Add tests for buidler cli options (#435)

pull/437/head
cgewecke 5 years ago committed by GitHub
parent 9d98f3fd2a
commit ce2e6c3dfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      README.md
  2. 22
      dist/buidler.plugin.js
  3. 6
      dist/plugin-assets/buidler.ui.js
  4. 46
      dist/plugin-assets/buidler.utils.js
  5. 26
      dist/plugin-assets/plugin.utils.js
  6. 1
      dist/truffle.plugin.js
  7. 2
      package.json
  8. 2
      test/units/buidler/errors.js
  9. 146
      test/units/buidler/flags.js
  10. 15
      test/units/truffle/flags.js
  11. 2
      test/units/truffle/standard.js
  12. 18
      test/util/integration.js

@ -36,17 +36,16 @@ truffle run coverage [command-options]
+ Coverage launches its own in-process ganache server.
+ You can set [ganache options][1] using the `providerOptions` key in your `.solcover.js` [config][15].
+ Coverage [distorts gas consumption][13]. Tests that check exact gas consumption should be [skipped][24].
+ :warning: Contracts are compiled **without optimization**. Please report unexpected compilation faults to [issue 417][25]
+ :warning: Contracts are compiled **without optimization**. Please report unexpected compilation faults to [issue 417][25]
## Command Options
| Option <img width=200/> | Example <img width=750/>| Description <img width=1000/> |
|--------------|------------------------------------|--------------------------------|
| file | `--file="test/registry/*.js"` | Filename or glob describing a subset of JS tests to run. (Globs must be enclosed by quotes.)|
| file (Truffle) | `--file="test/registry/*.js"` | Filename or glob describing a subset of JS tests to run. (Globs must be enclosed by quotes.)|
| testFiles (Buidler) | `--testFiles test/file.js` | JS test file(s) to run.|
| solcoverjs | `--solcoverjs ./../.solcover.js` | Relative path from working directory to config. Useful for monorepo packages that share settings. (Path must be "./" prefixed) |
| network | `--network development` | Use network settings defined in the Truffle config |
| network | `--network development` | Use network settings defined in the Truffle or Buidler config |
| temp[<sup>*</sup>][14] | `--temp build` | :warning: **Caution** :warning: Path to a *disposable* folder to store compilation artifacts in. Useful when your test setup scripts include hard-coded paths to a build directory. [More...][14] |
| version | | Version info |
| help | | Usage notes |
[<sup>*</sup> Advanced use][14]

@ -17,6 +17,8 @@ const {
TASK_COMPILE,
} = require("@nomiclabs/buidler/builtin-tasks/task-names");
ensurePluginLoadedWithUsePlugin();
function plugin() {
// UI for the task flags...
@ -24,11 +26,11 @@ function plugin() {
task("coverage", "Generates a code coverage report for tests")
.addOptionalParam("file", ui.flags.file, null, types.string)
.addOptionalParam("testFiles", 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, env){
.setAction(async function(args, env){
let error;
let ui;
let api;
@ -37,15 +39,19 @@ function plugin() {
try {
death(buidlerUtils.finish.bind(null, config, api)); // Catch interrupt signals
config = buidlerUtils.normalizeConfig(env.config);
config = buidlerUtils.normalizeConfig(env.config, args);
ui = new PluginUI(config.logger.log);
api = new API(utils.loadSolcoverJS(config));
// ==============
// Server launch
// ==============
const network = buidlerUtils.setupNetwork(env, api);
const network = buidlerUtils.setupNetwork(
env,
api,
args,
ui
);
const address = await api.ganache(ganache);
const web3 = new Web3(address);
@ -88,12 +94,14 @@ function plugin() {
// ==============
// Compilation
// ==============
config.temp = args.temp;
const {
tempArtifactsDir,
tempContractsDir
} = utils.getTempLocations(config);
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir)
utils.save(targets, config.paths.sources, tempContractsDir);
utils.save(skipped, config.paths.sources, tempContractsDir);
@ -109,7 +117,7 @@ function plugin() {
// ======
// Tests
// ======
const testFiles = buidlerUtils.getTestFilePaths(config);
const testFiles = args.testFiles ? [args.testFiles] : [];
try {
await env.run(TASK_TEST, {testFiles: testFiles})
@ -128,7 +136,7 @@ function plugin() {
error = e;
}
await utils.finish(config, api);
await buidlerUtils.finish(config, api);
if (error !== undefined ) throw error;
if (process.exitCode > 0) throw new Error(ui.generate('tests-fail', [process.exitCode]));

@ -45,6 +45,10 @@ class PluginUI extends UI {
`\n${c.bold('============')}\n` +
`${ct} ${c.bold('port')}: ${args[1]}\n` +
`${ct} ${c.bold('network')}: ${args[0]}\n`,
'port-clash': `${w} ${c.red("The 'port' values in your Buidler url ")}` +
`${c.red("and .solcover.js are different. Using Buidler's: ")} ${c.bold(args[0])}.\n`,
}
this._write(kinds[kind]);
@ -70,8 +74,6 @@ class PluginUI extends UI {
'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. ')}`,
}

@ -10,47 +10,44 @@ const { createProvider } = require("@nomiclabs/buidler/internal/core/providers/c
// Buidler Specific Plugin Utils
// =============================
/**
* Returns a list of test files to pass to TASK_TEST.
* @param {BuidlerConfig} config
* @return {String[]} list of files to pass to mocha
*/
function getTestFilePaths(config){
let target;
// Handle --file <path|glob> cli option (subset of tests)
(typeof config.file === 'string')
? target = globby.sync([config.file])
: target = [];
// Return list of test files
const testregex = /.*\.(js|ts|es|es6|jsx)$/;
return target.filter(f => f.match(testregex) != null);
}
/**
* Normalizes buidler paths / logging for use by the plugin utilities and
* attaches them to the config
* @param {BuidlerConfig} config
* @return {BuidlerConfig} updated config
*/
function normalizeConfig(config){
function normalizeConfig(config, args){
config.workingDir = config.paths.root;
config.contractsDir = config.paths.sources;
config.testDir = config.paths.tests;
config.artifactsDir = config.paths.artifacts;
config.logger = config.logger ? config.logger : {log: null};
config.solcoverjs = args.solcoverjs
return config;
}
function setupNetwork(env, api){
const networkConfig = {
url: `http://${api.host}:${api.port}`,
gas: api.gasLimit,
gasPrice: api.gasPrice
function setupNetwork(env, api, taskArgs, ui){
let networkConfig = {};
if (taskArgs.network){
networkConfig = env.config.networks[taskArgs.network];
const configPort = networkConfig.url.split(':')[2];
// Warn: port conflicts
if (api.port !== api.defaultPort && api.port !== configPort){
ui.report('port-clash', [ configPort ])
}
// Prefer network port
api.port = parseInt(configPort);
}
networkConfig.url = `http://${api.host}:${api.port}`;
networkConfig.gas = api.gasLimit;
networkConfig.gasPrice = api.gasPrice;
const provider = createProvider(api.defaultNetworkName, networkConfig);
env.config.networks[api.defaultNetworkName] = networkConfig;
@ -102,7 +99,6 @@ module.exports = {
normalizeConfig: normalizeConfig,
finish: finish,
tempCacheDir: tempCacheDir,
getTestFilePaths: getTestFilePaths,
setupNetwork: setupNetwork
}

@ -48,6 +48,19 @@ function loadSource(_path){
return fs.readFileSync(_path).toString();
}
/**
* Sets up temporary folders for instrumented contracts and their compilation artifacts
* @param {PlatformConfig} config
* @param {String} tempContractsDir
* @param {String} tempArtifactsDir
*/
function setupTempFolders(config, tempContractsDir, tempArtifactsDir){
checkContext(config, tempContractsDir, tempArtifactsDir);
shell.mkdir(tempContractsDir);
shell.mkdir(tempArtifactsDir);
}
/**
* Save a set of instrumented files to a temporary directory.
* @param {Object[]} targets array of targets generated by `assembleTargets`
@ -122,16 +135,6 @@ function assembleFiles(config, skipFiles=[]){
let skipFolders;
let skipped = [];
const {
tempContractsDir,
tempArtifactsDir
} = getTempLocations(config);
checkContext(config, tempContractsDir, tempArtifactsDir);
shell.mkdir(tempContractsDir);
shell.mkdir(tempArtifactsDir);
targets = shell.ls(`${config.contractsDir}/**/*.sol`);
skipFiles = assembleSkipped(config, targets, skipFiles);
@ -268,5 +271,6 @@ module.exports = {
reportSkipped: reportSkipped,
save: save,
checkContext: checkContext,
toRelativePath: toRelativePath
toRelativePath: toRelativePath,
setupTempFolders: setupTempFolders
}

@ -82,6 +82,7 @@ async function plugin(config){
tempContractsDir
} = utils.getTempLocations(config);
utils.setupTempFolders(config, tempContractsDir, tempArtifactsDir)
utils.save(targets, config.contracts_directory, tempContractsDir);
utils.save(skipped, config.contracts_directory, tempContractsDir);

@ -13,7 +13,7 @@
"scripts": {
"nyc": "SILENT=true nyc --exclude '**/sc_temp/**' --exclude '**/test/**'",
"test": "npm run nyc -- mocha test/units/* --timeout 100000 --no-warnings --exit",
"test:ci": "SILENT=true nyc --reporter=lcov --exclude '**/sc_temp/**' --exclude '**/test/**/' -- mocha test/units/* --timeout 100000 --no-warnings --exit",
"test:ci": "SILENT=true node --max-old-space-size=3072 ./node_modules/.bin/nyc --reporter=lcov --exclude '**/sc_temp/**' --exclude '**/test/**/' -- mocha test/units/* --timeout 100000 --no-warnings --exit",
"test:debug": "mocha test/units/* --timeout 100000 --no-warnings --exit"
},
"homepage": "https://github.com/sc-forks/solidity-coverage",

@ -3,7 +3,7 @@ const fs = require('fs');
const path = require('path')
const pify = require('pify')
const shell = require('shelljs');
const ganache = require('ganache-core-sc');
const ganache = require('ganache-cli')
const verify = require('../../util/verifiers')
const mock = require('../../util/integration');

@ -0,0 +1,146 @@
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');
// =======================
// CLI Options / Flags
// =======================
async function delay(){
return new Promise(res => setTimeout(() => res(), 1000))
}
describe('Buidler Plugin: command line options', function() {
let buidlerConfig;
let solcoverConfig;
beforeEach(function(){
mock.clean();
mock.loggerOutput.val = '';
solcoverConfig = {
skipFiles: ['Migrations.sol'],
silent: process.env.SILENT ? true : false,
istanbulReporter: ['json-summary', 'text']
};
buidlerConfig = mock.getDefaultBuidlerConfig();
verify.cleanInitialState();
})
afterEach(async function (){
mock.buidlerTearDownEnv();
mock.clean();
});
it('--temp', async function(){
const taskArgs = {
temp: 'special_folder'
}
mock.install('Simple', 'simple.js', solcoverConfig);
mock.buidlerSetupEnv(this);
await this.env.run("coverage", taskArgs);
const expected = [{
file: mock.pathToContract(buidlerConfig, 'Simple.sol'),
pct: 100
}];
verify.lineCoverage(expected);
});
it('--network (declared port mismatches)', async function(){
const taskArgs = {
network: 'development' // 8545
}
solcoverConfig.port = 8222;
mock.install('Simple', 'simple.js', solcoverConfig);
mock.buidlerSetupEnv(this);
await this.env.run("coverage", taskArgs);
assert(
mock.loggerOutput.val.includes("The 'port' values"),
`Should notify about mismatched port values: ${mock.loggerOutput.val}`
);
assert(
mock.loggerOutput.val.includes("8545"),
`Should have used default coverage port 8545: ${mock.loggerOutput.val}`
);
const expected = [{
file: mock.pathToContract(buidlerConfig, 'Simple.sol'),
pct: 100
}];
verify.lineCoverage(expected);
});
it('--testFiles test/<fileName>', async function() {
const taskArgs = {
testFiles: path.join(
buidlerConfig.paths.root,
'test/specific_a.js'
)
};
mock.installFullProject('test-files');
mock.buidlerSetupEnv(this);
await this.env.run("coverage", taskArgs);
const expected = [
{
file: mock.pathToContract(buidlerConfig, 'ContractA.sol'),
pct: 100
},
{
file: mock.pathToContract(buidlerConfig, 'ContractB.sol'),
pct: 0,
},
{
file: mock.pathToContract(buidlerConfig, 'ContractC.sol'),
pct: 0,
},
];
verify.lineCoverage(expected);
});
it('--config ../.solcover.js', async function() {
// Write solcoverjs to parent dir of sc_temp (where the test project is installed)
fs.writeFileSync(
'.solcover.js',
`module.exports=${JSON.stringify(solcoverConfig)}`
);
// This relative path has to be ./ prefixed (it's path.joined to buidler's paths.root)
const taskArgs = {
solcoverjs: './../.solcover.js'
};
mock.install('Simple', 'simple.js');
mock.buidlerSetupEnv(this);
await this.env.run("coverage", taskArgs);
// The relative solcoverjs uses the json-summary reporter
const expected = [{
file: mock.pathToContract(buidlerConfig, 'Simple.sol'),
pct: 100
}];
verify.lineCoverage(expected);
shell.rm('.solcover.js');
});
});

@ -198,20 +198,7 @@ describe('Truffle Plugin: command line options', function() {
);
});
it('--usePluginTruffle', async function(){
truffleConfig.usePluginTruffle = true;
truffleConfig.logger = mock.testLogger;
mock.install('Simple', 'simple.js', solcoverConfig);
await plugin(truffleConfig);
assert(
mock.loggerOutput.val.includes('fallback Truffle library module'),
`Should notify it's using plugin truffle lib copy: ${mock.loggerOutput.val}`
);
});
it('--coverageArtifacts', async function(){
it('--temp', async function(){
truffleConfig.logger = mock.testLogger;
truffleConfig.temp = 'special_location';

@ -156,7 +156,7 @@ describe('Truffle Plugin: standard use cases', function() {
});
// Truffle test asserts deployment cost is greater than 20,000,000 gas
it('deployment cost > block gasLimit', async function() {
it.skip('deployment cost > block gasLimit', async function() {
mock.install('Expensive', 'block-gas-limit.js', solcoverConfig);
await plugin(truffleConfig);
});

@ -27,9 +27,17 @@ let previousCWD;
// Misc Utils
// ==========================
function decacheConfigs(){
decache(`${process.cwd()}/${temp}/.solcover.js`);
decache(`${process.cwd()}/${temp}/${truffleConfigName}`);
decache(`${process.cwd()}/${temp}/${buidlerConfigName}`);
const paths = [
`${process.cwd()}/${temp}/.solcover.js`,
`${process.cwd()}/${temp}/${truffleConfigName}`,
`${process.cwd()}/${temp}/${buidlerConfigName}`,
`${process.cwd()}/${temp}/contracts/Simple.sol`,
`${process.cwd()}/${temp}/test/simple.js`
];
paths.forEach(pth => {
try { decache(pth) } catch (e){}
});
}
function clean() {
@ -65,8 +73,8 @@ function buidlerSetupEnv(mocha) {
// Buidler env tear down
function buidlerTearDownEnv() {
resetBuidlerContext();
process.chdir(previousCWD);
resetBuidlerContext();
process.chdir(previousCWD);
};

Loading…
Cancel
Save