diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..bda468c --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +test/run/truffle-crash.js \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index c3878f7..66e2c2c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -40,7 +40,6 @@ "semi": [2, "always"], "no-unused-vars": 0, "import/extensions": [0], - "import/no-dynamic-require": [0], "arrow-parens":[2, "as-needed"], "no-plusplus":[2, { "allowForLoopAfterthoughts": true }], "no-bitwise": [2], diff --git a/.gitignore b/.gitignore index f5b0cd5..b038cf3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ coverage.json coverage/ node_modules/ .changelog +.DS_Store diff --git a/circle.yml b/circle.yml index 280b523..7ea2dbc 100644 --- a/circle.yml +++ b/circle.yml @@ -3,6 +3,7 @@ machine: version: 6.9.1 dependencies: pre: + - npm install -g truffle - rm -rf node_modules/ test: override: diff --git a/coverageMap.js b/coverageMap.js index d17a0f3..d2880b2 100644 --- a/coverageMap.js +++ b/coverageMap.js @@ -5,11 +5,7 @@ */ const SolidityCoder = require('web3/lib/solidity/coder.js'); const path = require('path'); - -const lineTopic = 'b8995a65f405d9756b41a334f38d8ff0c93c4934e170d3c1429c3e7ca101014d'; -const functionTopic = 'd4ce765fd23c5cc3660249353d61ecd18ca60549dd62cb9ca350a4244de7b87f'; -const branchTopic = 'd4cf56ed5ba572684f02f889f12ac42d9583c8e3097802060e949bfbb3c1bff5'; -const statementTopic = 'b51abbff580b3a34bbc725f2dc6f736e9d4b45a41293fd0084ad865a31fde0c8'; +const keccak = require('keccakjs'); /** * Converts solcover event data into an object that can be @@ -20,6 +16,10 @@ module.exports = class CoverageMap { constructor() { this.coverage = {}; + this.lineTopics = []; + this.functionTopics = []; + this.branchTopics = []; + this.statementTopics = []; } /** @@ -29,6 +29,7 @@ module.exports = class CoverageMap { * @param {String} canonicalContractPath target file location * @return {Object} coverage map with all values set to zero */ + addContract(info, canonicalContractPath) { this.coverage[canonicalContractPath] = { l: {}, @@ -56,6 +57,17 @@ module.exports = class CoverageMap { for (let x = 1; x <= Object.keys(info.statementMap).length; x++) { this.coverage[canonicalContractPath].s[x] = 0; } + + const keccakhex = (x => { + const hash = new keccak(256); // eslint-disable-line new-cap + hash.update(x); + return hash.digest('hex'); + }); + + this.lineTopics.push(keccakhex('__Coverage' + info.contractName + '(string,uint256)')); + this.functionTopics.push(keccakhex('__FunctionCoverage' + info.contractName + '(string,uint256)')); + this.branchTopics.push(keccakhex('__BranchCoverage' + info.contractName + '(string,uint256,uint256)')); + this.statementTopics.push(keccakhex('__StatementCoverage' + info.contractName + '(string,uint256)')); } /** @@ -68,19 +80,20 @@ module.exports = class CoverageMap { generate(events, pathPrefix) { for (let idx = 0; idx < events.length; idx++) { const event = JSON.parse(events[idx]); - if (event.topics.indexOf(lineTopic) >= 0) { + + if (event.topics.filter(t => this.lineTopics.indexOf(t) >= 0).length > 0) { const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', '')); const canonicalContractPath = data[0]; this.coverage[canonicalContractPath].l[data[1].toNumber()] += 1; - } else if (event.topics.indexOf(functionTopic) >= 0) { + } else if (event.topics.filter(t => this.functionTopics.indexOf(t) >= 0).length > 0) { const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', '')); const canonicalContractPath = data[0]; this.coverage[canonicalContractPath].f[data[1].toNumber()] += 1; - } else if (event.topics.indexOf(branchTopic) >= 0) { + } else if (event.topics.filter(t => this.branchTopics.indexOf(t) >= 0).length > 0) { const data = SolidityCoder.decodeParams(['string', 'uint256', 'uint256'], event.data.replace('0x', '')); const canonicalContractPath = data[0]; this.coverage[canonicalContractPath].b[data[1].toNumber()][data[2].toNumber()] += 1; - } else if (event.topics.indexOf(statementTopic) >= 0) { + } else if (event.topics.filter(t => this.statementTopics.indexOf(t) >= 0).length > 0) { const data = SolidityCoder.decodeParams(['string', 'uint256'], event.data.replace('0x', '')); const canonicalContractPath = data[0]; this.coverage[canonicalContractPath].s[data[1].toNumber()] += 1; diff --git a/exec.js b/exec.js index cb5187c..e3d9169 100644 --- a/exec.js +++ b/exec.js @@ -7,11 +7,11 @@ const path = require('path'); const childprocess = require('child_process'); const getInstrumentedVersion = require('./instrumentSolidity.js'); const CoverageMap = require('./coverageMap.js'); - const istanbul = require('istanbul'); + const istanbulCollector = new istanbul.Collector(); const istanbulReporter = new istanbul.Reporter(); - + // Very high gas block limits / contract deployment limits const gasLimitString = '0xfffffffffff'; const gasLimitHex = 0xfffffffffff; @@ -30,8 +30,28 @@ let silence = ''; // Default log level: configurable b let log = console.log; // Default log level: configurable by --silence let testrpcProcess; // ref to testrpc server we need to close on exit -let events; // ref to string loaded from 'allFiredEvents' +let events; // ref to string loaded from 'allFiredEvents' + +// --------------------------------------- Utilities ----------------------------------------------- +/** + * Removes coverage build artifacts, kills testrpc. + * Exits (1) and prints msg on error, exits (0) otherwise. + * @param {String} err error message + */ +function cleanUp(err) { + log('Cleaning up...'); + shell.config.silent = true; + shell.rm('-Rf', `${coverageDir}`); + shell.rm('./allFiredEvents'); + if (testrpcProcess) { testrpcProcess.kill(); } + if (err) { + log(`${err}\nExiting without generating coverage...`); + process.exit(1); + } else { + process.exit(0); + } +} // --------------------------------------- Script -------------------------------------------------- const config = reqCwd.silent(`${workingDir}/.solcover.js`) || {}; @@ -48,7 +68,7 @@ if (config.silent) { if (!config.norpc) { try { log(`Launching testrpc on port ${port}`); - const command = `./node_modules/ethereumjs-testrpc-sc/bin/testrpc`; + const command = './node_modules/ethereumjs-testrpc-sc/bin/testrpc'; const options = `--gasLimit ${gasLimitString} --port ${port}`; testrpcProcess = childprocess.exec(command + options); } catch (err) { @@ -69,19 +89,19 @@ try { const truffleConfig = reqCwd(`${workingDir}/truffle.js`); // Coverage network opts specified: copy truffle.js whole to coverage environment - if (truffleConfig.networks.coverage){ + if (truffleConfig.networks.coverage) { shell.cp(`${workingDir}/truffle.js`, `${coverageDir}/truffle.js`); // Coverage network opts NOT specified: default to the development network w/ modified // port, gasLimit, gasPrice. Export the config object only. - } else { + } else { truffleConfig.networks.development.port = port; truffleConfig.networks.development.gas = gasLimitHex; truffleConfig.networks.development.gasPrice = gasPriceHex; coverageOption = ''; fs.writeFileSync(`${coverageDir}/truffle.js`, `module.exports = ${JSON.stringify(truffleConfig)}`); } -} catch (err){ +} catch (err) { const msg = ('There was a problem generating the coverage environment: '); cleanUp(msg + err); } @@ -99,7 +119,7 @@ try { if (file !== migrations) { log('Instrumenting ', file); const contractPath = path.resolve(file); - const canonicalPath = contractPath.split(`/coverageEnv`).join(''); + const canonicalPath = contractPath.split('/coverageEnv').join(''); const contract = fs.readFileSync(contractPath).toString(); const instrumentedContractInfo = getInstrumentedVersion(contract, canonicalPath); fs.writeFileSync(contractPath, instrumentedContractInfo.contract); @@ -114,9 +134,7 @@ try { // coverage environment folder try { log('Launching Truffle (this can take a few seconds)...'); - const truffle = `./../node_modules/truffle/cli.js`; - const command = `cd coverageEnv && ${truffle} test ${coverageOption} ${silence}`; - //const command = `cd coverageEnv && truffle test ${coverageOption} ${silence}`; + const command = `cd coverageEnv && truffle test ${coverageOption} ${silence}`; shell.exec(command); } catch (err) { cleanUp(err); @@ -139,9 +157,9 @@ try { // Generate coverage / write coverage report / run istanbul try { - //coverage.generate(events, `${coverageDir}/contracts/`); + // coverage.generate(events, `${coverageDir}/contracts/`); coverage.generate(events, './contracts'); - + const json = JSON.stringify(coverage.coverage); fs.writeFileSync('./coverage.json', json); @@ -150,39 +168,16 @@ try { istanbulReporter.add('lcov'); istanbulReporter.add('text'); istanbulReporter.write(istanbulCollector, true, () => { - log('Istanbul coverage reports generated'); + log('Istanbul coverage reports generated'); }); - } catch (err) { - if (config.testing){ - cleanUp() + if (config.testing) { + cleanUp(); } else { const msg = 'There was a problem generating producing the coverage map / running Istanbul.\n'; cleanUp(msg + err); } - } // Finish cleanUp(); - -// --------------------------------------- Utilities ----------------------------------------------- -/** - * Removes coverage build artifacts, kills testrpc. - * Exits (1) and prints msg on error, exits (0) otherwise. - * @param {String} err error message - */ -function cleanUp(err) { - log('Cleaning up...'); - shell.config.silent = true; - shell.rm('-Rf', `${coverageDir}`); - shell.rm('./allFiredEvents'); - if (testrpcProcess) { testrpcProcess.kill(); } - - if (err) { - log(`${err}\nExiting without generating coverage...`); - process.exit(1); - } else { - process.exit(0); - } -} diff --git a/injector.js b/injector.js index c3dd7a5..d3f687d 100644 --- a/injector.js +++ b/injector.js @@ -6,27 +6,27 @@ injector.callEvent = function injectCallEvent(contract, fileName, injectionPoint const linecount = (contract.instrumented.slice(0, injectionPoint).match(/\n/g) || []).length + 1; contract.runnableLines.push(linecount); contract.instrumented = contract.instrumented.slice(0, injectionPoint) + - 'Coverage(\'' + fileName + '\',' + linecount + ');\n' + + '__Coverage' + contract.contractName + '(\'' + fileName + '\',' + linecount + ');\n' + contract.instrumented.slice(injectionPoint); }; injector.callFunctionEvent = function injectCallFunctionEvent(contract, fileName, injectionPoint, injection) { contract.instrumented = contract.instrumented.slice(0, injectionPoint) + - 'FunctionCoverage(\'' + fileName + '\',' + injection.fnId + ');\n' + + '__FunctionCoverage' + contract.contractName + '(\'' + fileName + '\',' + injection.fnId + ');\n' + contract.instrumented.slice(injectionPoint); }; injector.callBranchEvent = function injectCallFunctionEvent(contract, fileName, injectionPoint, injection) { contract.instrumented = contract.instrumented.slice(0, injectionPoint) + (injection.openBracket ? '{' : '') + - 'BranchCoverage(\'' + fileName + '\',' + injection.branchId + ',' + injection.locationIdx + ')' + + '__BranchCoverage' + contract.contractName + '(\'' + fileName + '\',' + injection.branchId + ',' + injection.locationIdx + ')' + (injection.comma ? ',' : ';') + contract.instrumented.slice(injectionPoint); }; injector.callEmptyBranchEvent = function injectCallEmptyBranchEvent(contract, fileName, injectionPoint, injection) { contract.instrumented = contract.instrumented.slice(0, injectionPoint) + - 'else { BranchCoverage(\'' + fileName + '\',' + injection.branchId + ',' + injection.locationIdx + ');}\n' + + 'else { __BranchCoverage' + contract.contractName + '(\'' + fileName + '\',' + injection.branchId + ',' + injection.locationIdx + ');}\n' + contract.instrumented.slice(injectionPoint); }; @@ -44,16 +44,16 @@ injector.literal = function injectLiteral(contract, fileName, injectionPoint, in injector.statement = function injectStatement(contract, fileName, injectionPoint, injection) { contract.instrumented = contract.instrumented.slice(0, injectionPoint) + - ' StatementCoverage(\'' + fileName + '\',' + injection.statementId + ');\n' + + ' __StatementCoverage' + contract.contractName + '(\'' + fileName + '\',' + injection.statementId + ');\n' + contract.instrumented.slice(injectionPoint); }; injector.eventDefinition = function injectEventDefinition(contract, fileName, injectionPoint, injection) { contract.instrumented = contract.instrumented.slice(0, injectionPoint) + - 'event Coverage(string fileName, uint256 lineNumber);\n' + - 'event FunctionCoverage(string fileName, uint256 fnId);\n' + - 'event StatementCoverage(string fileName, uint256 statementId);\n' + - 'event BranchCoverage(string fileName, uint256 branchId, uint256 locationIdx);\n' + + 'event __Coverage' + contract.contractName + '(string fileName, uint256 lineNumber);\n' + + 'event __FunctionCoverage' + contract.contractName + '(string fileName, uint256 fnId);\n' + + 'event __StatementCoverage' + contract.contractName + '(string fileName, uint256 statementId);\n' + + 'event __BranchCoverage' + contract.contractName + '(string fileName, uint256 branchId, uint256 locationIdx);\n' + contract.instrumented.slice(injectionPoint); }; diff --git a/instrumentSolidity.js b/instrumentSolidity.js index 7837a1b..f8cdd6f 100644 --- a/instrumentSolidity.js +++ b/instrumentSolidity.js @@ -38,8 +38,12 @@ module.exports = function instrumentSolidity(contractSource, fileName) { contract.preprocessed = preprocessor.run(contract.source); contract.instrumented = contract.preprocessed; + ast = SolidityParser.parse(contract.preprocessed); + const contractStatement = ast.body.filter(node => node.type === 'ContractStatement'); + contract.contractName = contractStatement[0].name; + parse[ast.type](contract, ast); // var result = solparse.parse(contract); @@ -59,5 +63,7 @@ module.exports = function instrumentSolidity(contractSource, fileName) { }); retValue.runnableLines = contract.runnableLines; retValue.contract = contract.instrumented; + retValue.contractName = contractStatement[0].name; + return retValue; }; diff --git a/package.json b/package.json index a3dddae..7b1b208 100644 --- a/package.json +++ b/package.json @@ -18,16 +18,16 @@ "commander": "^2.9.0", "ethereumjs-testrpc": "https://github.com/sc-forks/testrpc-sc.git", "istanbul": "^0.4.5", + "keccakjs": "^0.2.1", "mkdirp": "^0.5.1", "req-cwd": "^1.0.1", "shelljs": "^0.7.4", "sol-explore": "^1.6.2", - "solidity-parser": "0.3.0", - "truffle": "git+https://github.com/cgewecke/truffle.git" + "solidity-parser": "0.3.0" }, "devDependencies": { "crypto-js": "^3.1.9-1", - "eslint": "^3.13.1", + "eslint": "^3.19.0", "eslint-config-airbnb-base": "^11.0.1", "eslint-plugin-import": "^2.2.0", "eslint-plugin-mocha": "^4.8.0", @@ -37,6 +37,6 @@ "istanbul": "^0.4.5", "merkle-patricia-tree": "~2.1.2", "mocha": "^3.1.0", - "solc": "0.4.6" + "solc": "0.4.8" } } diff --git a/test/conditional.js b/test/conditional.js index 7d0aad3..6385daa 100644 --- a/test/conditional.js +++ b/test/conditional.js @@ -1,6 +1,5 @@ /* eslint-env node, mocha */ -const solc = require('solc'); const path = require('path'); const getInstrumentedVersion = require('./../instrumentSolidity.js'); const util = require('./util/util.js'); @@ -159,9 +158,10 @@ describe('conditional statements', () => { }); // Solcover has trouble with this case. The conditional coverage strategy relies on being able to - // reference the left-hand variable before its value is assigned. Solidity doesn't allow this for 'var'. + // reference the left-hand variable before its value is assigned. Solidity doesn't allow this + // for 'var'. - /* it('should cover a variable delcaration assignment by conditional that reaches the alternate', (done) => { + /* it('should cover a var decl assignment by conditional that reaches the alternate', (done) => { const contract = util.getCode('conditional/variable-decl-assignment-alternate.sol'); const info = getInstrumentedVersion(contract, filePath); const coverage = new CoverageMap(); diff --git a/test/expressions.js b/test/expressions.js index 126e034..d0033d4 100644 --- a/test/expressions.js +++ b/test/expressions.js @@ -3,10 +3,7 @@ const solc = require('solc'); const getInstrumentedVersion = require('./../instrumentSolidity.js'); const util = require('./util/util.js'); -const CoverageMap = require('./../coverageMap'); const path = require('path'); -const vm = require('./util/vm'); -const assert = require('assert'); /** * NB: passing '1' to solc as an option activates the optimiser @@ -15,7 +12,6 @@ const assert = require('assert'); */ describe('generic expressions', () => { const filePath = path.resolve('./test.sol'); - const pathPrefix = './'; it('should compile after instrumenting a single binary expression', () => { const contract = util.getCode('expressions/single-binary-expression.sol'); diff --git a/test/if.js b/test/if.js index ab49b7a..ed3816f 100644 --- a/test/if.js +++ b/test/if.js @@ -1,6 +1,5 @@ /* eslint-env node, mocha */ -const solc = require('solc'); const path = require('path'); const getInstrumentedVersion = require('./../instrumentSolidity.js'); const util = require('./util/util.js'); diff --git a/test/loops.js b/test/loops.js index f929251..186ca28 100644 --- a/test/loops.js +++ b/test/loops.js @@ -1,6 +1,5 @@ /* eslint-env node, mocha */ -const solc = require('solc'); const path = require('path'); const getInstrumentedVersion = require('./../instrumentSolidity.js'); const util = require('./util/util.js'); diff --git a/test/run.js b/test/run.js index 766fe11..fe60bc9 100644 --- a/test/run.js +++ b/test/run.js @@ -1,3 +1,5 @@ +/* eslint-env node, mocha */ + const assert = require('assert'); const shell = require('shelljs'); const fs = require('fs'); @@ -14,13 +16,12 @@ function collectGarbage() { describe('run', () => { let testrpcProcess = null; - let script = 'node ./exec.js' - let launchTestRpc = false; - let port = 8555; + const script = 'node ./exec.js'; + const port = 8555; - config = { - dir: "./mock", - port: port, + const config = { + dir: './mock', + port, testing: true, silent: true, // <-- Set to false to debug tests norpc: true, @@ -38,20 +39,20 @@ describe('run', () => { after(() => { mock.restoreCoverage(); - //testrpcProcess.kill(); + testrpcProcess.kill(); }); - // This pre-test flushes the suite. There's some kind of sequencing issue here in development, + // This pre-test flushes the suite. There's some kind of sequencing issue here in development, // possibly tied to the use of ethereumjs-vm in the coverage tests? // - tests pass w/out this if we only run these test - e.g. it only fails when running the suite. - // - the first test always fails unless there is a fresh testrpc install. + // - the first test always fails unless there is a fresh testrpc install. it('flush test suite', () => { mock.install('Simple.sol', 'simple.js', config); shell.exec(script); // <---- This fails mysteriously, but we don't test here. collectGarbage(); }); - // This test should be positioned first (or second if flushing) in the suite because of + // This test should be positioned first (or second if flushing) in the suite because of // the way we're launching testrpc it('simple contract: should generate coverage, cleanup & exit(0)', () => { // Directory should be clean @@ -95,7 +96,7 @@ describe('run', () => { }); it('contract uses inheritance: should generate coverage, cleanup & exit(0)', () => { - // Run against a contract that 'is' another contract + // Run against a contract that 'is' another contract assert(pathExists('./coverage') === false, 'should start without: coverage'); assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); mock.installInheritanceTest(config); @@ -109,7 +110,7 @@ describe('run', () => { const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); const ownedPath = Object.keys(produced)[0]; const proxyPath = Object.keys(produced)[1]; - + assert(produced[ownedPath].fnMap['1'].name === 'Owned', 'coverage.json should map "Owned"'); assert(produced[proxyPath].fnMap['1'].name === 'isOwner', 'coverage.json should map "isOwner"'); collectGarbage(); diff --git a/test/run/block-gas-limit.js b/test/run/block-gas-limit.js index 641ca76..795933a 100644 --- a/test/run/block-gas-limit.js +++ b/test/run/block-gas-limit.js @@ -1,6 +1,7 @@ - +/* eslint-env node, mocha */ +/* global artifacts, contract */ const Expensive = artifacts.require('./Expensive.sol'); -contract('Expensive', accounts => { +contract('Expensive', () => { it('should deploy', () => Expensive.deployed()); }); diff --git a/test/run/empty.js b/test/run/empty.js index 2401a8c..def0cd0 100644 --- a/test/run/empty.js +++ b/test/run/empty.js @@ -1,6 +1,8 @@ +/* eslint-env node, mocha */ +/* global artifacts, contract */ const Empty = artifacts.require('./Empty.sol'); -contract('Empty', accounts => { +contract('Empty', () => { it('should deploy', () => Empty.deployed()); }); diff --git a/test/run/inheritance.js b/test/run/inheritance.js index 91b0a25..91fba75 100644 --- a/test/run/inheritance.js +++ b/test/run/inheritance.js @@ -1,12 +1,14 @@ +/* eslint-env node, mocha */ +/* global artifacts, contract, assert */ + const Owned = artifacts.require('./Owned.sol'); const Proxy = artifacts.require('./Proxy.sol'); contract('Proxy', accounts => { - it('Should compile and run when one contract inherits from another', () => { - let proxy; - return Owned.deployed() - .then(instance => Proxy.deployed()) - .then(instance => instance.isOwner.call({from: accounts[0]})) - .then(val => assert.equal(val, true)); - }); -}); \ No newline at end of file + it('Should compile and run when one contract inherits from another', () => Owned.deployed() + .then(() => Proxy.deployed()) + .then(instance => instance.isOwner.call({ + from: accounts[0], + })) + .then(val => assert.equal(val, true))); +}); diff --git a/test/run/only-call.js b/test/run/only-call.js index c10a5fb..da72716 100644 --- a/test/run/only-call.js +++ b/test/run/only-call.js @@ -1,13 +1,17 @@ +/* eslint-env node, mocha */ +/* global artifacts, contract, assert */ const OnlyCall = artifacts.require('./OnlyCall.sol'); contract('OnlyCall', accounts => { - it('should return val + 2', function(done){ - OnlyCall.deployed().then(function(instance){ - instance.addTwo.call(5, {from: accounts[0]}).then(function(val){ - assert.equal(val, 7); - done(); - }) - }) + it('should return val + 2', done => { + OnlyCall.deployed().then(instance => { + instance.addTwo.call(5, { + from: accounts[0], + }).then(val => { + assert.equal(val, 7); + done(); + }); + }); }); }); diff --git a/test/run/simple.js b/test/run/simple.js index 9c974ab..1fcf550 100644 --- a/test/run/simple.js +++ b/test/run/simple.js @@ -1,14 +1,16 @@ +/* eslint-env node, mocha */ +/* global artifacts, contract, assert */ const Simple = artifacts.require('./Simple.sol'); -contract('Simple', accounts => { +contract('Simple', () => { it('should set x to 5', () => { let simple; return Simple.deployed().then(instance => { simple = instance; return simple.test(5); }) - .then(val => simple.getX.call()) + .then(() => simple.getX.call()) .then(val => assert.equal(val.toNumber(), 5)); }); }); diff --git a/test/run/sol-parse-fail.js b/test/run/sol-parse-fail.js index 2b09bd1..ff17dba 100644 --- a/test/run/sol-parse-fail.js +++ b/test/run/sol-parse-fail.js @@ -1,16 +1,17 @@ - +/* eslint-env node, mocha */ +/* global artifacts, contract, assert */ const Simple = artifacts.require('./Simple.sol'); // This test is constructed correctly but the SimpleError.sol has a syntax error -contract('SimpleError', accounts => { +contract('SimpleError', () => { it('should set x to 5', () => { let simple; return Simple.deployed().then(instance => { simple = instance; return simple.test(5); }) - .then(val => simple.getX.call()) + .then(() => simple.getX.call()) .then(val => assert.equal(val, 5)); }); }); diff --git a/test/run/truffle-crash.js b/test/run/truffle-crash.js index 6ee35ea..33633aa 100644 --- a/test/run/truffle-crash.js +++ b/test/run/truffle-crash.js @@ -1,9 +1,10 @@ -'use strict' +/* eslint-env node, mocha */ +/* global artifacts, contract */ var Simple = artifacts.require('./Simple.sol'); // This test should break truffle because it has a syntax error. -contract('Simple', function(accounts){ +contract('Simple', () => { it('should crash', function(){ return Simple.deployed().then.why. }) diff --git a/test/run/truffle-test-fail.js b/test/run/truffle-test-fail.js index 211a409..e9457d0 100644 --- a/test/run/truffle-test-fail.js +++ b/test/run/truffle-test-fail.js @@ -1,15 +1,16 @@ - +/* eslint-env node, mocha */ +/* global artifacts, contract, assert */ const Simple = artifacts.require('./Simple.sol'); -contract('Simple', accounts => { +contract('Simple', () => { it('should set x to 5', () => { let simple; return Simple.deployed().then(instance => { simple = instance; return simple.test(5); }) - .then(val => simple.getX.call()) + .then(() => simple.getX.call()) .then(val => assert.equal(val.toNumber(), 4)); // <-- Wrong result: test fails }); }); diff --git a/test/util/mockTruffle.js b/test/util/mockTruffle.js index 5ab7998..75193a2 100644 --- a/test/util/mockTruffle.js +++ b/test/util/mockTruffle.js @@ -3,7 +3,6 @@ This file contains utilities for generating a mock truffle project to test solcover's run script against. */ -const assert = require('assert'); const fs = require('fs'); const shell = require('shelljs'); @@ -11,7 +10,7 @@ const shell = require('shelljs'); * Moves existing coverage reports into a safe place while testing run script which * would overwrite them. Silences shell complaints about non-existent files. */ -module.exports.protectCoverage = function () { +module.exports.protectCoverage = function protectCoverage() { shell.config.silent = true; shell.rm('-Rf', './safe'); shell.mkdir('./safe'); @@ -24,7 +23,7 @@ module.exports.protectCoverage = function () { * Restores pre-existing coverage reports after testing run script. * Silences shell complaints about non-existent files. */ -module.exports.restoreCoverage = function () { +module.exports.restoreCoverage = function restoreCoverage() { shell.config.silent = true; shell.mv('./safe/coverage', './coverage'); shell.mv('./safe/coverage.json', './coverage.json'); @@ -38,17 +37,17 @@ module.exports.restoreCoverage = function () { * @param {String} contract located in /test/sources/run/ * @param {[type]} test located in /test/run/ */ -module.exports.install = function (contract, test, config) { +module.exports.install = function install(contract, test, config) { shell.mkdir('./mock'); shell.mkdir('./mock/contracts'); shell.mkdir('./mock/migrations'); shell.mkdir('./mock/test'); // Mock contracts - if (Array.isArray(contract)){ + if (Array.isArray(contract)) { contract.forEach(item => { shell.cp(`./test/sources/run/${item}`, `./mock/contracts/${item}`); - }) + }); } else { shell.cp(`./test/sources/run/${contract}`, `./mock/contracts/${contract}`); } @@ -62,7 +61,7 @@ module.exports.install = function (contract, test, config) { deployer.deploy(Migrations); };`; - const contractLocation = './' + contract; + const contractLocation = `./${contract}`; const deployContracts = ` var contract = artifacts.require('${contractLocation}'); module.exports = function(deployer) { @@ -97,15 +96,15 @@ module.exports.install = function (contract, test, config) { * @param {String} contract located in /test/sources/run/ * @param {[type]} test located in /test/run/ */ -module.exports.installInheritanceTest = function (config) { +module.exports.installInheritanceTest = function installInheritanceTest(config) { shell.mkdir('./mock'); shell.mkdir('./mock/contracts'); shell.mkdir('./mock/migrations'); shell.mkdir('./mock/test'); // Mock contracts - shell.cp(`./test/sources/run/Proxy.sol`, `./mock/contracts/Proxy.sol`); - shell.cp(`./test/sources/run/Owned.sol`, `./mock/contracts/Owned.sol`); + shell.cp('./test/sources/run/Proxy.sol', './mock/contracts/Proxy.sol'); + shell.cp('./test/sources/run/Owned.sol', './mock/contracts/Owned.sol'); shell.cp('./test/sources/run/Migrations.sol', './mock/contracts/Migrations.sol'); // Mock migrations @@ -128,7 +127,7 @@ module.exports.installInheritanceTest = function (config) { fs.writeFileSync('./mock/migrations/2_deploy_contracts.js', deployContracts); // Mock test - shell.cp(`./test/run/inheritance.js`, `./mock/test/inheritance.js`); + shell.cp('./test/run/inheritance.js', './mock/test/inheritance.js'); // Mock truffle.js const trufflejs = `module.exports = { @@ -149,11 +148,11 @@ module.exports.installInheritanceTest = function (config) { /** * Removes mock truffle project and coverage reports generated by runCovered tests */ -module.exports.remove = function () { +module.exports.remove = function remove() { shell.config.silent = true; shell.rm('./.solcover.js'); shell.rm('-Rf', 'mock'); shell.rm('-Rf', 'coverage'); shell.rm('coverage.json'); shell.config.silent = false; -}; \ No newline at end of file +}; diff --git a/test/util/util.js b/test/util/util.js index c476cce..d7b7c9c 100644 --- a/test/util/util.js +++ b/test/util/util.js @@ -7,11 +7,11 @@ const path = require('path'); * @return {String} contents of a .sol file */ module.exports.getCode = function getCode(_path) { - return fs.readFileSync(path.join(__dirname, './../sources/' + _path), 'utf8'); + return fs.readFileSync(path.join(__dirname, `./../sources/${_path}`), 'utf8'); }; module.exports.report = function report(errors) { if (errors) { - throw new Error('Instrumented solidity invalid: ' + errors); + throw new Error(`Instrumented solidity invalid: ${errors}`); } }; diff --git a/test/util/vm.js b/test/util/vm.js index 28a54b1..61d9057 100644 --- a/test/util/vm.js +++ b/test/util/vm.js @@ -1,5 +1,4 @@ const solc = require('solc'); -const path = require('path'); const VM = require('ethereumjs-vm'); const Account = require('ethereumjs-account'); const Transaction = require('ethereumjs-tx'); @@ -17,12 +16,12 @@ const accountAddress = new Buffer('7caf6f9bc8b3ba5c7824f934c826bd6dc38c8467', 'h * Source: consensys/eth-lightwallet/lib/txutils.js (line 18) */ function encodeFunctionTxData(functionName, types, args) { - const fullName = functionName + '(' + types.join() + ')'; + const fullName = `${functionName}(${types.join()})`; const signature = CryptoJS.SHA3(fullName, { outputLength: 256, }).toString(CryptoJS.enc.Hex).slice(0, 8); const dataHex = signature + coder.encodeParams(types, args); - return '0x' + dataHex; + return `0x${dataHex}`; } /** @@ -112,7 +111,7 @@ function callMethod(vm, abi, address, functionName, args) { const tx = new Transaction(options); tx.sign(new Buffer(secretKey, 'hex')); - return new Promise((resolve, reject) => { + return new Promise(resolve => { vm.runTx({ tx, }, (err, results) => {