diff --git a/lib/parse.js b/lib/parse.js index 187c09a..55cc831 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -68,6 +68,10 @@ parse.ContractOrLibraryStatement = function parseContractOrLibraryStatement(cont } }; +parse.EmitStatement = function parseExpressionStatement(contract, expression){ + instrumenter.instrumentStatement(contract, expression); +}; + parse.ExpressionStatement = function parseExpressionStatement(contract, content) { parse[content.expression.type] && parse[content.expression.type](contract, content.expression); diff --git a/package-lock.json b/package-lock.json index 65650a2..1669585 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5341,9 +5341,9 @@ "integrity": "sha1-Q66MQZ/TrAVqBfip0fsQIs1B7MI=" }, "solc": { - "version": "0.4.21", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.21.tgz", - "integrity": "sha512-8lJmimVjOG9AJOQRWS2ph4rSctPMsPGZ4H360HLs5iI+euUlt7iAvUxSLeFZZzwk0kas4Qta7HmlMXNU3yYwhw==", + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.23.tgz", + "integrity": "sha512-AT7anLHY6uIRg2It6N0UlCHeZ7YeecIkUhnlirrCgCPCUevtnoN48BxvgigN/4jJTRljv5oFhAJtI6gvHzT5DQ==", "dev": true, "requires": { "fs-extra": "0.30.0", @@ -5354,30 +5354,15 @@ } }, "solidity-parser-sc": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/solidity-parser-sc/-/solidity-parser-sc-0.4.7.tgz", - "integrity": "sha512-wbX2806sm6thZME1aniqLcLH9HYwNwuKke6aw/FEgupCvoT9Iq5PdwuN9OyHWKGBOVeczpM5tCrnRXWNQ04YVw==", + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/solidity-parser-sc/-/solidity-parser-sc-0.4.8.tgz", + "integrity": "sha512-Suenp3ireAbJ1E58yXwcFbkxvuhX10VTKdmrPKVzharjMji1jySfvE8PuzIw3FivtkNwUsQtijQ/k6t21RFohg==", "requires": { "mocha": "2.5.3", "pegjs": "0.10.0", "yargs": "4.8.1" }, "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - } - }, "debug": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", @@ -5430,41 +5415,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=" - }, - "window-size": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", - "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" - }, - "yargs": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", - "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", - "requires": { - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "lodash.assign": "4.2.0", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "window-size": "0.2.0", - "y18n": "3.2.1", - "yargs-parser": "2.4.1" - } - }, - "yargs-parser": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", - "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", - "requires": { - "camelcase": "3.0.0", - "lodash.assign": "4.2.0" - } } } }, @@ -5770,14 +5720,14 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, "truffle": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/truffle/-/truffle-4.1.5.tgz", - "integrity": "sha512-6sOVFQ0xNbb52MMWf0nHxv0FiXWPTV+OIbq1B0+I5F3sIS8JJ7pM1+o7chbs+oO/CLqbbC6ggXJqFWzIWaiaQg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/truffle/-/truffle-4.1.7.tgz", + "integrity": "sha512-fe6BIcD9xo6iIJvV1m6ZhOk56kmB8k38kdoWOKYnPPw7ZUUSupgojeTb2K5e+4qIpIHvEvmET4yLUjSGR+hvwA==", "dev": true, "requires": { "mocha": "3.5.3", "original-require": "1.0.1", - "solc": "0.4.21" + "solc": "0.4.23" } }, "tunnel-agent": { @@ -6446,7 +6396,6 @@ "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", - "dev": true, "requires": { "cliui": "3.2.0", "decamelize": "1.2.0", @@ -6468,7 +6417,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, "requires": { "string-width": "1.0.2", "strip-ansi": "3.0.1", @@ -6478,8 +6426,7 @@ "window-size": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", - "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", - "dev": true + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" } } }, @@ -6487,7 +6434,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", - "dev": true, "requires": { "camelcase": "3.0.0", "lodash.assign": "4.2.0" @@ -6496,8 +6442,7 @@ "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" } } }, diff --git a/package.json b/package.json index f96355b..bfdffa8 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "req-cwd": "^1.0.1", "shelljs": "^0.7.4", "sol-explore": "^1.6.2", - "solidity-parser-sc": "0.4.7", + "solidity-parser-sc": "0.4.8", "web3": "^0.18.4" }, "devDependencies": { @@ -44,7 +44,7 @@ "merkle-patricia-tree": "~2.1.2", "mocha": "^3.1.0", "request": "^2.81.0", - "solc": "0.4.21", - "truffle": "4.1.5" + "solc": "0.4.23", + "truffle": "4.1.7" } } diff --git a/test/function.js b/test/function.js index dff9745..d91a9e3 100644 --- a/test/function.js +++ b/test/function.js @@ -89,6 +89,29 @@ describe('function declarations', () => { }).catch(done); }); + it('should cover a constructor that uses the `constructor` keyword', done => { + const contract = util.getCode('function/constructor-keyword.sol'); + const info = getInstrumentedVersion(contract, filePath); + const coverage = new CoverageMap(); + coverage.addContract(info, filePath); + + vm.execute(info.contract, 'a', []).then(events => { + const mapping = coverage.generate(events, pathPrefix); + assert.deepEqual(mapping[filePath].l, { + 6: 1, 11: 1 + }); + assert.deepEqual(mapping[filePath].b, {}); + assert.deepEqual(mapping[filePath].s, { + 1: 1, + }); + assert.deepEqual(mapping[filePath].f, { + 1: 1, + 2: 1, + }); + done(); + }).catch(done); + }); + it('should cover a constructor call that chains to a method call', done => { const contract = util.getCode('function/chainable.sol'); const info = getInstrumentedVersion(contract, filePath); diff --git a/test/sources/function/constructor-keyword.sol b/test/sources/function/constructor-keyword.sol new file mode 100644 index 0000000..ea6ef7e --- /dev/null +++ b/test/sources/function/constructor-keyword.sol @@ -0,0 +1,13 @@ +pragma solidity ^0.4.23; + +contract UsesConstructor { + uint z; + constructor(){ + z = 5; + } +} +contract Test { + function a(){ + new UsesConstructor(); + } +} diff --git a/test/sources/statements/emit-coverage.sol b/test/sources/statements/emit-coverage.sol new file mode 100644 index 0000000..555ebec --- /dev/null +++ b/test/sources/statements/emit-coverage.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.23; + +contract Test { + event TestEvent(); + function a(uint x) { + emit TestEvent(); + } +} \ No newline at end of file diff --git a/test/sources/statements/emit-instrument.sol b/test/sources/statements/emit-instrument.sol new file mode 100644 index 0000000..120f297 --- /dev/null +++ b/test/sources/statements/emit-instrument.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.4.23; + +contract Test { + event TestEvent(); + function a(uint x) { + if(true) + emit TestEvent(); + } +} \ No newline at end of file diff --git a/test/statements.js b/test/statements.js index 5f8b0be..653e7b9 100644 --- a/test/statements.js +++ b/test/statements.js @@ -59,6 +59,8 @@ describe('generic statements', () => { util.report(output.errors); }); + + it('should NOT pass tests if the contract has a compilation error', () => { const contract = util.getCode('statements/compilation-error.sol'); const info = getInstrumentedVersion(contract, filePath); @@ -71,6 +73,35 @@ describe('generic statements', () => { } }); + it('should compile after instrumenting an emit statement after an un-enclosed if statement', () => { + const contract = util.getCode('statements/emit-instrument.sol'); + const info = getInstrumentedVersion(contract, filePath); + const output = solc.compile(info.contract, 1); + util.report(output.errors); + }); + + it('should cover an emitted event statement', done => { + const contract = util.getCode('statements/emit-coverage.sol'); + const info = getInstrumentedVersion(contract, filePath); + const coverage = new CoverageMap(); + coverage.addContract(info, filePath); + + vm.execute(info.contract, 'a', []).then(events => { + const mapping = coverage.generate(events, pathPrefix); + assert.deepEqual(mapping[filePath].l, { + 6: 1 + }); + assert.deepEqual(mapping[filePath].b, {}); + assert.deepEqual(mapping[filePath].s, { + 1: 1 + }); + assert.deepEqual(mapping[filePath].f, { + 1: 1, + }); + done(); + }).catch(done); + }); + it('should cover a statement following a close brace', done => { const contract = util.getCode('statements/post-close-brace.sol'); const info = getInstrumentedVersion(contract, filePath);