diff --git a/README.md b/README.md
index 6024ad5f..67bb69ba 100644
--- a/README.md
+++ b/README.md
@@ -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
| Example
| Description
|
|--------------|------------------------------------|--------------------------------|
-| 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[*][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 |
[* Advanced use][14]
diff --git a/dist/buidler.plugin.js b/dist/buidler.plugin.js
index dba89c48..8c005daf 100644
--- a/dist/buidler.plugin.js
+++ b/dist/buidler.plugin.js
@@ -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]));
diff --git a/dist/plugin-assets/buidler.ui.js b/dist/plugin-assets/buidler.ui.js
index 78c39a38..35f35ff5 100644
--- a/dist/plugin-assets/buidler.ui.js
+++ b/dist/plugin-assets/buidler.ui.js
@@ -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. ')}`,
}
diff --git a/dist/plugin-assets/buidler.utils.js b/dist/plugin-assets/buidler.utils.js
index 23fff0c8..9ef5dffa 100644
--- a/dist/plugin-assets/buidler.utils.js
+++ b/dist/plugin-assets/buidler.utils.js
@@ -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 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
}
diff --git a/dist/plugin-assets/plugin.utils.js b/dist/plugin-assets/plugin.utils.js
index d4162eee..1dc50a93 100644
--- a/dist/plugin-assets/plugin.utils.js
+++ b/dist/plugin-assets/plugin.utils.js
@@ -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
}
diff --git a/dist/truffle.plugin.js b/dist/truffle.plugin.js
index 62c4ad33..57445cd0 100644
--- a/dist/truffle.plugin.js
+++ b/dist/truffle.plugin.js
@@ -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);
diff --git a/package.json b/package.json
index bed3e2b5..9f411918 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/test/units/buidler/errors.js b/test/units/buidler/errors.js
index c39c990e..9ab3e485 100644
--- a/test/units/buidler/errors.js
+++ b/test/units/buidler/errors.js
@@ -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');
diff --git a/test/units/buidler/flags.js b/test/units/buidler/flags.js
new file mode 100644
index 00000000..435e2970
--- /dev/null
+++ b/test/units/buidler/flags.js
@@ -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/', 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');
+ });
+});
+
diff --git a/test/units/truffle/flags.js b/test/units/truffle/flags.js
index 92757d5c..5cef07c4 100644
--- a/test/units/truffle/flags.js
+++ b/test/units/truffle/flags.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';
diff --git a/test/units/truffle/standard.js b/test/units/truffle/standard.js
index 4b767bc2..1597a385 100644
--- a/test/units/truffle/standard.js
+++ b/test/units/truffle/standard.js
@@ -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);
});
diff --git a/test/util/integration.js b/test/util/integration.js
index a5313d8d..8f37e5e6 100644
--- a/test/util/integration.js
+++ b/test/util/integration.js
@@ -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);
};