From 58a216cb85a31579c13d078f115e84d04627fc6a Mon Sep 17 00:00:00 2001 From: Alex Rea Date: Thu, 16 Nov 2017 17:39:04 +0000 Subject: [PATCH 1/2] Only remove pure/view/constant from functions Uses the preprocessor walking over the AST rather than a regex --- lib/app.js | 10 +++------- lib/preprocessor.js | 9 +++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/app.js b/lib/app.js index ae9bbad..8020bbe 100644 --- a/lib/app.js +++ b/lib/app.js @@ -8,6 +8,7 @@ const istanbul = require('istanbul'); const getInstrumentedVersion = require('./instrumentSolidity.js'); const CoverageMap = require('./coverageMap.js'); const defaultTruffleConfig = require('./truffleConfig.js'); +const preprocessor = require('./preprocessor'); const isWin = /^win/.test(process.platform); @@ -284,16 +285,11 @@ class App { */ postProcessPure(env) { shell.ls(`${env}/**/*.sol`).forEach(file => { - const pureRe = /\spure\s/gi; - const viewRe = /\sview\s/gi; - const constantRe = /\sconstant\s/gi; const contractPath = this.platformNeutralPath(file); let contract = fs.readFileSync(contractPath).toString(); - contract = contract.replace(pureRe, ' '); - contract = contract.replace(viewRe, ' '); - contract = contract.replace(constantRe, ' '); + contract = preprocessor.run(contract); fs.writeFileSync(contractPath, contract); - }) + }); } /** diff --git a/lib/preprocessor.js b/lib/preprocessor.js index dabaad6..c6dcf22 100644 --- a/lib/preprocessor.js +++ b/lib/preprocessor.js @@ -50,6 +50,15 @@ module.exports.run = function r(contract) { contract = blockWrap(contract, node.body); keepRunning = true; this.stopTraversal(); + } else if (node.type === 'FunctionDeclaration' && node.modifiers) { + // We want to remove constant / pure / view from functions + for (let i = 0; i < node.modifiers.length; i++) { + if (['pure', 'constant', 'view'].indexOf(node.modifiers[i].name) > -1) { + contract = contract.slice(0, node.modifiers[i].start) + contract.slice(node.modifiers[i].end); + keepRunning = true; + this.stopTraversal(); + } + } } }, }); From c2dd7878f4137e2a943cb27c455516ae78036a62 Mon Sep 17 00:00:00 2001 From: Alex Rea Date: Fri, 17 Nov 2017 11:51:19 +0000 Subject: [PATCH 2/2] Add test with library with constant variable --- test/app.js | 6 ++-- test/sources/cli/CLibrary.sol | 8 +++++ test/sources/cli/TotallyPure.sol | 5 +++ test/util/mockTruffle.js | 58 +++++++++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 test/sources/cli/CLibrary.sol diff --git a/test/app.js b/test/app.js index 202155d..0ce67b7 100644 --- a/test/app.js +++ b/test/app.js @@ -240,13 +240,13 @@ describe('app', () => { collectGarbage(); }); - it('tests use pure and view modifiers', () => { + it('tests use pure and view modifiers, including with libraries', () => { // Directory should be clean assert(pathExists('./coverage') === false, 'should start without: coverage'); assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); // Run script (exits 0); - mock.install('TotallyPure.sol', 'totallyPure.js', config); + mock.installLibraryTest(config); shell.exec(script); assert(shell.error() === null, 'script should not error'); @@ -255,7 +255,7 @@ describe('app', () => { assert(pathExists('./coverage.json') === true, 'script should gen coverage.json'); // Coverage should be real. - // This test is tightly bound to the function names in Simple.sol + // This test is tightly bound to the function names in TotallyPure.sol const produced = JSON.parse(fs.readFileSync('./coverage.json', 'utf8')); const path = Object.keys(produced)[0]; assert(produced[path].fnMap['1'].name === 'usesThem', 'coverage.json should map "usesThem"'); diff --git a/test/sources/cli/CLibrary.sol b/test/sources/cli/CLibrary.sol new file mode 100644 index 0000000..faece74 --- /dev/null +++ b/test/sources/cli/CLibrary.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.17; + +library CLibrary { + uint constant x = 1; + function a() constant returns (uint) { + return x; + } +} \ No newline at end of file diff --git a/test/sources/cli/TotallyPure.sol b/test/sources/cli/TotallyPure.sol index cb46fda..d6178fe 100644 --- a/test/sources/cli/TotallyPure.sol +++ b/test/sources/cli/TotallyPure.sol @@ -2,6 +2,7 @@ pragma solidity ^0.4.17; import "./../assets/PureView.sol"; +import "./../assets/CLibrary.sol"; contract TotallyPure is PureView { uint onehundred = 99; @@ -34,4 +35,8 @@ contract TotallyPure is PureView { function beView() view returns (uint){ return onehundred; } + + function usesLibrary() constant returns (uint){ + return CLibrary.a(); + } } \ No newline at end of file diff --git a/test/util/mockTruffle.js b/test/util/mockTruffle.js index feeafcd..c333a58 100644 --- a/test/util/mockTruffle.js +++ b/test/util/mockTruffle.js @@ -69,7 +69,6 @@ module.exports.install = function install(contract, test, config, _trufflejs, _t fs.writeFileSync('./mock/assets/asset.js', asset); fs.writeFileSync('./.solcover.js', configjs); - shell.cp(`./test/sources/cli/PureView.sol`, `./mock/assets/PureView.sol`); shell.cp(`./test/cli/${test}`, `./mock/test/${test}`); }; @@ -127,6 +126,63 @@ module.exports.installInheritanceTest = function installInheritanceTest(config) fs.writeFileSync('./.solcover.js', configjs); }; + +/** + * Installs mock truffle project at ./mock with two contracts - one is a library the other + * uses, and test specified by the params. + * @param {config} .solcover.js configuration + */ +module.exports.installLibraryTest = function installInheritanceTest(config) { + shell.mkdir('./mock'); + shell.mkdir('./mock/contracts'); + shell.mkdir('./mock/migrations'); + shell.mkdir('./mock/test'); + shell.mkdir('./mock/assets'); + + // Mock contracts + shell.cp('./test/sources/cli/TotallyPure.sol', './mock/contracts/TotallyPure.sol'); + shell.cp('./test/sources/cli/Migrations.sol', './mock/contracts/Migrations.sol'); + + // Mock migrations + const initialMigration = ` + let Migrations = artifacts.require('Migrations.sol'); + module.exports = function(deployer) { + deployer.deploy(Migrations); + };`; + + const deployContracts = ` + var CLibrary = artifacts.require('CLibrary.sol'); + var TotallyPure = artifacts.require('./TotallyPure.sol'); + module.exports = function(deployer) { + deployer.deploy(CLibrary); + deployer.link(CLibrary, TotallyPure); + deployer.deploy(TotallyPure); + };`; + + fs.writeFileSync('./mock/migrations/1_initial_migration.js', initialMigration); + fs.writeFileSync('./mock/migrations/2_deploy_contracts.js', deployContracts); + + // Mock test + shell.cp('./test/cli/totallyPure.js', './mock/test/totallyPure.js'); + shell.cp('./test/sources/cli/PureView.sol', './mock/assets/PureView.sol'); + shell.cp('./test/sources/cli/CLibrary.sol', './mock/assets/CLibrary.sol'); + + // Mock truffle.js + const trufflejs = `module.exports = { + networks: { + development: { + host: "localhost", + port: 8545, + network_id: "*" + }}};` + ; + + const configjs = `module.exports = ${JSON.stringify(config)}`; + + fs.writeFileSync('./mock/truffle.js', trufflejs); + fs.writeFileSync('./.solcover.js', configjs); +}; + /** * Removes mock truffle project and coverage reports generated by exec.js */