From f7986717132de3641e60e34c0421e1aae66da9f5 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Thu, 17 Oct 2019 15:11:41 -0700 Subject: [PATCH] Passing: standard test suite --- dist/buidler.plugin.js | 107 ++++----- dist/plugin-assets/buidler.utils.js | 71 +++++- .../projects/bad-solcoverjs/buidler.config.js | 9 +- .../projects/import-paths/buidler.config.js | 9 +- .../node_modules/package/package.json | 1 + .../projects/libraries/buidler.config.js | 8 +- .../multiple-migrations/buidler.config.js | 2 +- .../projects/multiple-suites/.solcover.js | 4 + .../multiple-suites/buidler.config.js | 8 + .../multiple-suites/contracts/ContractA.sol | 17 ++ .../multiple-suites/contracts/ContractB.sol | 17 ++ .../multiple-suites/contracts/ContractC.sol | 17 ++ .../multiple-suites/contracts/Migrations.sol | 23 ++ .../multiple-suites/test/contracta.js | 15 ++ .../multiple-suites/test/contractb.js | 15 ++ .../multiple-suites/test/contractc.js | 20 ++ .../multiple-suites/truffle-config.js | 7 + .../projects/no-sources/buidler.config.js | 8 +- .../projects/skipping/buidler.config.js | 9 +- .../projects/test-files/.solcover.js | 1 + .../projects/test-files/buidler.config.js | 8 +- test/sources/js/truffle-test-fail.js | 7 + test/units/buidler/standard.js | 222 +++++++++++++++++- test/util/integration.js | 24 +- test/util/verifiers.js | 12 +- 25 files changed, 536 insertions(+), 105 deletions(-) create mode 100644 test/integration/projects/import-paths/node_modules/package/package.json create mode 100644 test/integration/projects/multiple-suites/.solcover.js create mode 100644 test/integration/projects/multiple-suites/buidler.config.js create mode 100644 test/integration/projects/multiple-suites/contracts/ContractA.sol create mode 100644 test/integration/projects/multiple-suites/contracts/ContractB.sol create mode 100644 test/integration/projects/multiple-suites/contracts/ContractC.sol create mode 100644 test/integration/projects/multiple-suites/contracts/Migrations.sol create mode 100644 test/integration/projects/multiple-suites/test/contracta.js create mode 100644 test/integration/projects/multiple-suites/test/contractb.js create mode 100644 test/integration/projects/multiple-suites/test/contractc.js create mode 100644 test/integration/projects/multiple-suites/truffle-config.js diff --git a/dist/buidler.plugin.js b/dist/buidler.plugin.js index 7fe3934..dba89c4 100644 --- a/dist/buidler.plugin.js +++ b/dist/buidler.plugin.js @@ -9,86 +9,44 @@ const path = require('path'); const Web3 = require('web3'); const ganache = require('ganache-cli'); -const { task, internalTask, types } = require("@nomiclabs/buidler/config"); +const { task, 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; + // UI for the task flags... 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()) + .setAction(async function(taskArguments, env){ + let error; + let ui; + let api; + let config; + try { death(buidlerUtils.finish.bind(null, config, api)); // Catch interrupt signals - config.logger = {log: null}; - config = buidlerUtils.normalizeConfig(config); + config = buidlerUtils.normalizeConfig(env.config); + ui = new PluginUI(config.logger.log); api = new API(utils.loadSolcoverJS(config)); + // ============== // Server launch + // ============== + + const network = buidlerUtils.setupNetwork(env, api); + const address = await api.ganache(ganache); const web3 = new Web3(address); const accounts = await web3.eth.getAccounts(); @@ -113,7 +71,10 @@ function plugin() { // Run post-launch server hook; await api.onServerReady(config); - // Instrument + // ================ + // Instrumentation + // ================ + const skipFiles = api.skipFiles || []; let { @@ -124,7 +85,10 @@ function plugin() { targets = api.instrument(targets); utils.reportSkipped(config, skipped); - // Filesystem & Compiler Re-configuration + // ============== + // Compilation + // ============== + const { tempArtifactsDir, tempContractsDir @@ -136,27 +100,38 @@ function plugin() { 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 env.run(TASK_COMPILE); await api.onCompileComplete(config); + // ====== + // Tests + // ====== + const testFiles = buidlerUtils.getTestFilePaths(config); + try { - failures = await run(TASK_TEST, {testFiles: []}) + await env.run(TASK_TEST, {testFiles: testFiles}) } catch (e) { - error = e.stack; - console.log(e.message + error) + error = e; } await api.onTestsComplete(config); - // Run Istanbul + // ======== + // Istanbul + // ======== await api.report(); await api.onIstanbulComplete(config); + } catch(e) { error = e; } + + await utils.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.utils.js b/dist/plugin-assets/buidler.utils.js index 34382ae..23fff0c 100644 --- a/dist/plugin-assets/buidler.utils.js +++ b/dist/plugin-assets/buidler.utils.js @@ -1,24 +1,85 @@ const shell = require('shelljs'); +const globby = require('globby'); const pluginUtils = require("./plugin.utils"); -const path = require('path') -const util = require('util') +const path = require('path'); +const util = require('util'); +const { createProvider } = require("@nomiclabs/buidler/internal/core/providers/construction"); + +// ============================= +// 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){ 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}; return config; } +function setupNetwork(env, api){ + 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; + + // Return a reference so we can set the from account + return env.network; +} + +/** + * Generates a path to a temporary compilation cache directory + * @param {BuidlerConfig} config + * @return {String} .../.coverage_cache + */ 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 {BuidlerConfig} config * @param {SolidityCoverage} api * @return {Promise} */ @@ -40,6 +101,8 @@ async function finish(config, api){ module.exports = { normalizeConfig: normalizeConfig, finish: finish, - tempCacheDir: tempCacheDir + tempCacheDir: tempCacheDir, + getTestFilePaths: getTestFilePaths, + setupNetwork: setupNetwork } diff --git a/test/integration/projects/bad-solcoverjs/buidler.config.js b/test/integration/projects/bad-solcoverjs/buidler.config.js index 0e56363..084a9f2 100644 --- a/test/integration/projects/bad-solcoverjs/buidler.config.js +++ b/test/integration/projects/bad-solcoverjs/buidler.config.js @@ -1 +1,8 @@ -modules.exports={}; +const { loadPluginFile } = require("@nomiclabs/buidler/plugins-testing"); +loadPluginFile(__dirname + "/../dist/buidler.plugin"); +usePlugin("@nomiclabs/buidler-truffle5"); + +module.exports={ + defaultNetwork: "buidlerevm", + logger: process.env.SILENT ? { log: () => {} } : console, +}; \ No newline at end of file diff --git a/test/integration/projects/import-paths/buidler.config.js b/test/integration/projects/import-paths/buidler.config.js index 0e56363..f170d4c 100644 --- a/test/integration/projects/import-paths/buidler.config.js +++ b/test/integration/projects/import-paths/buidler.config.js @@ -1 +1,8 @@ -modules.exports={}; +const { loadPluginFile } = require("@nomiclabs/buidler/plugins-testing"); +loadPluginFile(__dirname + "/../dist/buidler.plugin"); +usePlugin("@nomiclabs/buidler-truffle5"); + +module.exports={ + defaultNetwork: "buidlerevm", + logger: process.env.SILENT ? { log: () => {} } : console, +}; diff --git a/test/integration/projects/import-paths/node_modules/package/package.json b/test/integration/projects/import-paths/node_modules/package/package.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/test/integration/projects/import-paths/node_modules/package/package.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/test/integration/projects/libraries/buidler.config.js b/test/integration/projects/libraries/buidler.config.js index 0e56363..46ea0f5 100644 --- a/test/integration/projects/libraries/buidler.config.js +++ b/test/integration/projects/libraries/buidler.config.js @@ -1 +1,7 @@ -modules.exports={}; +const { loadPluginFile } = require("@nomiclabs/buidler/plugins-testing"); +loadPluginFile(__dirname + "/../dist/buidler.plugin"); +usePlugin("@nomiclabs/buidler-truffle5"); + +module.exports={ + logger: process.env.SILENT ? { log: () => {} } : console, +}; \ No newline at end of file diff --git a/test/integration/projects/multiple-migrations/buidler.config.js b/test/integration/projects/multiple-migrations/buidler.config.js index 0e56363..2ed08bf 100644 --- a/test/integration/projects/multiple-migrations/buidler.config.js +++ b/test/integration/projects/multiple-migrations/buidler.config.js @@ -1 +1 @@ -modules.exports={}; +module.exports={}; diff --git a/test/integration/projects/multiple-suites/.solcover.js b/test/integration/projects/multiple-suites/.solcover.js new file mode 100644 index 0000000..71b990c --- /dev/null +++ b/test/integration/projects/multiple-suites/.solcover.js @@ -0,0 +1,4 @@ +module.exports = { + "silent": false, + "istanbulReporter": [ "json-summary", "text"] +} diff --git a/test/integration/projects/multiple-suites/buidler.config.js b/test/integration/projects/multiple-suites/buidler.config.js new file mode 100644 index 0000000..084a9f2 --- /dev/null +++ b/test/integration/projects/multiple-suites/buidler.config.js @@ -0,0 +1,8 @@ +const { loadPluginFile } = require("@nomiclabs/buidler/plugins-testing"); +loadPluginFile(__dirname + "/../dist/buidler.plugin"); +usePlugin("@nomiclabs/buidler-truffle5"); + +module.exports={ + defaultNetwork: "buidlerevm", + logger: process.env.SILENT ? { log: () => {} } : console, +}; \ No newline at end of file diff --git a/test/integration/projects/multiple-suites/contracts/ContractA.sol b/test/integration/projects/multiple-suites/contracts/ContractA.sol new file mode 100644 index 0000000..9d8d134 --- /dev/null +++ b/test/integration/projects/multiple-suites/contracts/ContractA.sol @@ -0,0 +1,17 @@ +pragma solidity ^0.5.0; + + +contract ContractA { + uint x; + constructor() public { + } + + function sendFn() public { + x = 5; + } + + function callFn() public pure returns (uint){ + uint y = 5; + return y; + } +} diff --git a/test/integration/projects/multiple-suites/contracts/ContractB.sol b/test/integration/projects/multiple-suites/contracts/ContractB.sol new file mode 100644 index 0000000..daa42f7 --- /dev/null +++ b/test/integration/projects/multiple-suites/contracts/ContractB.sol @@ -0,0 +1,17 @@ +pragma solidity ^0.5.0; + + +contract ContractB { + uint x; + constructor() public { + } + + function sendFn() public { + x = 5; + } + + function callFn() public pure returns (uint){ + uint y = 5; + return y; + } +} diff --git a/test/integration/projects/multiple-suites/contracts/ContractC.sol b/test/integration/projects/multiple-suites/contracts/ContractC.sol new file mode 100644 index 0000000..454c86c --- /dev/null +++ b/test/integration/projects/multiple-suites/contracts/ContractC.sol @@ -0,0 +1,17 @@ +pragma solidity ^0.5.0; + + +contract ContractC { + uint x; + constructor() public { + } + + function sendFn() public { + x = 5; + } + + function callFn() public pure returns (uint){ + uint y = 5; + return y; + } +} diff --git a/test/integration/projects/multiple-suites/contracts/Migrations.sol b/test/integration/projects/multiple-suites/contracts/Migrations.sol new file mode 100644 index 0000000..c378ffb --- /dev/null +++ b/test/integration/projects/multiple-suites/contracts/Migrations.sol @@ -0,0 +1,23 @@ +pragma solidity >=0.4.21 <0.6.0; + +contract Migrations { + address public owner; + uint public last_completed_migration; + + constructor() public { + owner = msg.sender; + } + + modifier restricted() { + if (msg.sender == owner) _; + } + + function setCompleted(uint completed) public restricted { + last_completed_migration = completed; + } + + function upgrade(address new_address) public restricted { + Migrations upgraded = Migrations(new_address); + upgraded.setCompleted(last_completed_migration); + } +} diff --git a/test/integration/projects/multiple-suites/test/contracta.js b/test/integration/projects/multiple-suites/test/contracta.js new file mode 100644 index 0000000..cc77802 --- /dev/null +++ b/test/integration/projects/multiple-suites/test/contracta.js @@ -0,0 +1,15 @@ +const ContractA = artifacts.require("ContractA"); + +contract("contracta", function(accounts) { + let instance; + + before(async () => instance = await ContractA.new()) + + it('sends [ @skipForCoverage ]', async function(){ + await instance.sendFn(); + }); + + it('calls [ @skipForCoverage ]', async function(){ + await instance.callFn(); + }) +}); diff --git a/test/integration/projects/multiple-suites/test/contractb.js b/test/integration/projects/multiple-suites/test/contractb.js new file mode 100644 index 0000000..71ebfb7 --- /dev/null +++ b/test/integration/projects/multiple-suites/test/contractb.js @@ -0,0 +1,15 @@ +const ContractB = artifacts.require("ContractB"); + +contract("contractB [ @skipForCoverage ]", function(accounts) { + let instance; + + before(async () => instance = await ContractB.new()) + + it('sends', async function(){ + await instance.sendFn(); + }); + + it('calls', async function(){ + await instance.callFn(); + }) +}); diff --git a/test/integration/projects/multiple-suites/test/contractc.js b/test/integration/projects/multiple-suites/test/contractc.js new file mode 100644 index 0000000..9b3d950 --- /dev/null +++ b/test/integration/projects/multiple-suites/test/contractc.js @@ -0,0 +1,20 @@ +const ContractC = artifacts.require("ContractC"); + +contract("contractc", function(accounts) { + let instance; + + before(async () => instance = await ContractC.new()) + + it('sends', async function(){ + await instance.sendFn(); + }); + + it('calls', async function(){ + await instance.callFn(); + }) + + it('sends', async function(){ + await instance.sendFn(); + }); + +}); diff --git a/test/integration/projects/multiple-suites/truffle-config.js b/test/integration/projects/multiple-suites/truffle-config.js new file mode 100644 index 0000000..b398b07 --- /dev/null +++ b/test/integration/projects/multiple-suites/truffle-config.js @@ -0,0 +1,7 @@ +module.exports = { + networks: {}, + mocha: {}, + compilers: { + solc: {} + } +} diff --git a/test/integration/projects/no-sources/buidler.config.js b/test/integration/projects/no-sources/buidler.config.js index 0e56363..46ea0f5 100644 --- a/test/integration/projects/no-sources/buidler.config.js +++ b/test/integration/projects/no-sources/buidler.config.js @@ -1 +1,7 @@ -modules.exports={}; +const { loadPluginFile } = require("@nomiclabs/buidler/plugins-testing"); +loadPluginFile(__dirname + "/../dist/buidler.plugin"); +usePlugin("@nomiclabs/buidler-truffle5"); + +module.exports={ + logger: process.env.SILENT ? { log: () => {} } : console, +}; \ No newline at end of file diff --git a/test/integration/projects/skipping/buidler.config.js b/test/integration/projects/skipping/buidler.config.js index 0e56363..084a9f2 100644 --- a/test/integration/projects/skipping/buidler.config.js +++ b/test/integration/projects/skipping/buidler.config.js @@ -1 +1,8 @@ -modules.exports={}; +const { loadPluginFile } = require("@nomiclabs/buidler/plugins-testing"); +loadPluginFile(__dirname + "/../dist/buidler.plugin"); +usePlugin("@nomiclabs/buidler-truffle5"); + +module.exports={ + defaultNetwork: "buidlerevm", + logger: process.env.SILENT ? { log: () => {} } : console, +}; \ No newline at end of file diff --git a/test/integration/projects/test-files/.solcover.js b/test/integration/projects/test-files/.solcover.js index f73c861..42903c8 100644 --- a/test/integration/projects/test-files/.solcover.js +++ b/test/integration/projects/test-files/.solcover.js @@ -2,6 +2,7 @@ const fn = (msg, config) => config.logger.log(msg); module.exports = { + skipFiles: ['Migrations.sol'], silent: process.env.SILENT ? true : false, istanbulReporter: ['json-summary', 'text'], onServerReady: fn.bind(null, 'running onServerReady'), diff --git a/test/integration/projects/test-files/buidler.config.js b/test/integration/projects/test-files/buidler.config.js index 0e56363..817a3eb 100644 --- a/test/integration/projects/test-files/buidler.config.js +++ b/test/integration/projects/test-files/buidler.config.js @@ -1 +1,7 @@ -modules.exports={}; +const { loadPluginFile } = require("@nomiclabs/buidler/plugins-testing"); +loadPluginFile(__dirname + "/../dist/buidler.plugin"); +usePlugin("@nomiclabs/buidler-truffle5"); + +module.exports={ + defaultNetwork: "buidlerevm", +}; diff --git a/test/sources/js/truffle-test-fail.js b/test/sources/js/truffle-test-fail.js index cb08d55..5e8b79c 100644 --- a/test/sources/js/truffle-test-fail.js +++ b/test/sources/js/truffle-test-fail.js @@ -10,4 +10,11 @@ contract('Simple', () => { const val = await simple.getX(); assert.equal(val.toNumber(), 4) // <-- Wrong result: test fails }); + + it('should set x to 2', async function() { + let simple = await Simple.new(); + await simple.test(5); + const val = await simple.getX(); + assert.equal(val.toNumber(), 2) // <-- Wrong result: test fails + }); }); diff --git a/test/units/buidler/standard.js b/test/units/buidler/standard.js index 42d4818..527cca1 100644 --- a/test/units/buidler/standard.js +++ b/test/units/buidler/standard.js @@ -7,15 +7,11 @@ 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() { +describe('Buidler Plugin: standard use cases', function() { let buidlerConfig; let solcoverConfig; @@ -23,7 +19,7 @@ describe.only('Buidler Plugin: standard use cases', function() { mock.clean(); mock.loggerOutput.val = ''; - solcoverConfig = {}; + solcoverConfig = { skipFiles: ['Migrations.sol']}; buidlerConfig = mock.getDefaultBuidlerConfig(); verify.cleanInitialState(); }) @@ -33,18 +29,13 @@ describe.only('Buidler Plugin: standard use cases', function() { 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); + verify.coverageGenerated(buidlerConfig); const output = mock.getOutput(buidlerConfig); const path = Object.keys(output)[0]; @@ -57,6 +48,211 @@ describe.only('Buidler Plugin: standard use cases', function() { assert( output[path].fnMap['2'].name === 'getX', 'coverage.json missing "getX"' - );*/ + ); + }); + + it('with relative path solidity imports', async function() { + mock.installFullProject('import-paths'); + mock.buidlerSetupEnv(this); + + await this.env.run("coverage"); + }); + + it('uses inheritance', async function() { + mock.installDouble( + ['Proxy', 'Owned'], + 'inheritance.js', + solcoverConfig + ); + + mock.buidlerSetupEnv(this); + + await this.env.run("coverage"); + + verify.coverageGenerated(buidlerConfig); + + const output = mock.getOutput(buidlerConfig); + const ownedPath = Object.keys(output)[0]; + const proxyPath = Object.keys(output)[1]; + + assert( + output[ownedPath].fnMap['1'].name === 'constructor', + '"constructor" not covered' + ); + + assert( + output[proxyPath].fnMap['1'].name === 'isOwner', + '"isOwner" not covered' + ); + }); + + it('only uses ".call"', async function(){ + mock.install('OnlyCall', 'only-call.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 === 'addTwo', + 'cov should map "addTwo"' + ); + }); + + it('sends / transfers to instrumented fallback', async function(){ + mock.install('Wallet', 'wallet.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 === 'transferPayment', + 'cov should map "transferPayment"' + ); + }); + + // Truffle test asserts deployment cost is greater than 20,000,000 gas + it('deployment cost > block gasLimit', async function() { + mock.install('Expensive', 'block-gas-limit.js', solcoverConfig); + mock.buidlerSetupEnv(this); + + await this.env.run("coverage"); + }); + + // Simple.sol with a failing assertion in a truffle test + it('unit tests failing', async function() { + mock.install('Simple', 'truffle-test-fail.js', solcoverConfig); + mock.buidlerSetupEnv(this); + + try { + await this.env.run("coverage"); + assert.fail() + } catch(err){ + assert(err.message.includes('failed under coverage')); + } + + verify.coverageGenerated(buidlerConfig); + + const output = mock.getOutput(buidlerConfig); + const path = Object.keys(output)[0]; + + assert(output[path].fnMap['1'].name === 'test', 'cov missing "test"'); + assert(output[path].fnMap['2'].name === 'getX', 'cov missing "getX"'); + }); + + // This project has [ @skipForCoverage ] tags in the test descriptions + // at selected 'contract' and 'it' blocks. + it('config: mocha options', async function() { + solcoverConfig.mocha = { + grep: '@skipForCoverage', + invert: true, + }; + + solcoverConfig.silent = process.env.SILENT ? true : false, + solcoverConfig.istanbulReporter = ['json-summary', 'text'] + + mock.installFullProject('multiple-suites', solcoverConfig); + mock.buidlerSetupEnv(this); + + await this.env.run("coverage"); + + const expected = [ + { + file: mock.pathToContract(buidlerConfig, 'ContractA.sol'), + pct: 0 + }, + { + file: mock.pathToContract(buidlerConfig, 'ContractB.sol'), + pct: 0, + }, + { + file: mock.pathToContract(buidlerConfig, 'ContractC.sol'), + pct: 100, + }, + ]; + + verify.lineCoverage(expected); + }); + + // Truffle test asserts balance is 777 ether + it('config: providerOptions', async function() { + solcoverConfig.providerOptions = { default_balance_ether: 777 } + + mock.install('Simple', 'testrpc-options.js', solcoverConfig); + mock.buidlerSetupEnv(this); + + await this.env.run("coverage"); + }); + + it('config: skipped file', async function() { + solcoverConfig.skipFiles = ['Migrations.sol', 'Owned.sol']; + + mock.installDouble( + ['Proxy', 'Owned'], + 'inheritance.js', + solcoverConfig + ); + + mock.buidlerSetupEnv(this); + + await this.env.run("coverage"); + + verify.coverageGenerated(buidlerConfig); + + const output = mock.getOutput(buidlerConfig); + const firstKey = Object.keys(output)[0]; + + assert( + Object.keys(output).length === 1, + 'Wrong # of contracts covered' + ); + + assert( + firstKey.substr(firstKey.length - 9) === 'Proxy.sol', + 'Wrong contract covered' + ); + }); + + it('config: skipped folder', async function() { + mock.installFullProject('skipping'); + mock.buidlerSetupEnv(this); + + await this.env.run("coverage"); + + const expected = [{ + file: mock.pathToContract(buidlerConfig, 'ContractA.sol'), + pct: 100 + }]; + + const missing = [{ + file: mock.pathToContract(buidlerConfig, 'skipped-folder/ContractB.sol'), + }]; + + verify.lineCoverage(expected); + verify.coverageMissing(missing); + }); + + it('config: "onServerReady", "onTestsComplete", ...', async function() { + mock.installFullProject('test-files'); + + mock.buidlerSetupEnv(this); + + await this.env.run("coverage"); + + assert( + mock.loggerOutput.val.includes('running onServerReady') && + mock.loggerOutput.val.includes('running onTestsComplete') && + mock.loggerOutput.val.includes('running onCompileComplete') && + mock.loggerOutput.val.includes('running onIstanbulComplete'), + + `Should run "on" hooks : ${mock.loggerOutput.val}` + ); }); }) \ No newline at end of file diff --git a/test/util/integration.js b/test/util/integration.js index dcdaadb..a5313d8 100644 --- a/test/util/integration.js +++ b/test/util/integration.js @@ -47,8 +47,9 @@ function pathToContract(config, file) { return path.join('contracts', file); } -function getOutput(truffleConfig){ - const jsonPath = path.join(truffleConfig.working_directory, "coverage.json"); +function getOutput(config){ + const workingDir = config.working_directory || config.paths.root; + const jsonPath = path.join(workingDir, "coverage.json"); return JSON.parse(fs.readFileSync(jsonPath, 'utf8')); } @@ -58,6 +59,8 @@ function buidlerSetupEnv(mocha) { previousCWD = process.cwd(); process.chdir(mockwd); mocha.env = require("@nomiclabs/buidler"); + mocha.env.config.logger = testLogger + mocha.logger = testLogger }; // Buidler env tear down @@ -119,24 +122,23 @@ function getDefaultBuidlerConfig() { const mockwd = path.join(process.cwd(), temp); const vals = { - root: mockwd, - artifacts: path.join(mockwd, 'artifacts'), - cache: path.join(mockwd, 'cache'), - sources: path.join(mockwd, 'contracts'), - tests: path.join(mockwd, 'test'), + paths : { + root: mockwd, + artifacts: path.join(mockwd, 'artifacts'), + cache: path.join(mockwd, 'cache'), + sources: path.join(mockwd, 'contracts'), + tests: path.join(mockwd, 'test'), + }, logger: logger, mocha: { reporter: reporter }, + defaultNetwork: "buidlerevm", networks: { development: { url: "http://127.0.0.1:8545", } }, - solc: { - version: "0.5.3", - optimizer: {} - } } return vals; diff --git a/test/util/verifiers.js b/test/util/verifiers.js index 3d3afa5..38bbb5c 100644 --- a/test/util/verifiers.js +++ b/test/util/verifiers.js @@ -28,14 +28,18 @@ function cleanInitialState(){ assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); } -function coverageGenerated(truffleConfig){ - const jsonPath = path.join(truffleConfig.working_directory, "coverage.json"); +function coverageGenerated(config){ + const workingDir = config.working_directory || config.paths.root; + const jsonPath = path.join(workingDir, "coverage.json"); + assert(pathExists('./coverage') === true, 'should gen coverage folder'); assert(pathExists(jsonPath) === true, 'should gen coverage.json'); } -function coverageNotGenerated(truffleConfig){ - const jsonPath = path.join(truffleConfig.working_directory, "coverage.json"); +function coverageNotGenerated(config){ + const workingDir = config.working_directory || config.paths.root; + const jsonPath = path.join(workingDir, "coverage.json"); + assert(pathExists('./coverage') !== true, 'should NOT gen coverage folder'); assert(pathExists(jsonPath) !== true, 'should NOT gen coverage.json'); }