diff --git a/test/sources/solidity/contracts/modifiers/postconditions.sol b/test/sources/solidity/contracts/modifiers/postconditions.sol new file mode 100644 index 0000000..01572df --- /dev/null +++ b/test/sources/solidity/contracts/modifiers/postconditions.sol @@ -0,0 +1,24 @@ +pragma solidity ^0.7.0; + +contract Test { + bool precondition = true; + bool postcondition = true; + + modifier m { + require(precondition); + _; + require(postcondition); + } + + function flip_precondition() public { + precondition = !precondition; + } + + function flip_postcondition() public { + postcondition = !postcondition; + } + + function a() m public { + uint x = 5; + } +} diff --git a/test/units/modifiers.js b/test/units/modifiers.js index 7d8c6a3..6606e84 100644 --- a/test/units/modifiers.js +++ b/test/units/modifiers.js @@ -166,6 +166,44 @@ describe('modifiers', () => { }); }); + it('should cover when there are post-conditions', async function() { + const contract = await util.bootstrapCoverage('modifiers/postconditions', api); + coverage.addContract(contract.instrumented, util.filePath); + + // Both true + await contract.instance.a(); + + // Precondition false + await contract.instance.flip_precondition(); + try { + await contract.instance.a(); + } catch(e) { /*ignore*/ } + + // Reset precondition to true, set postcondition false + await contract.instance.flip_precondition(); + await contract.instance.flip_postcondition(); + + // Postcondition false + try { + await contract.instance.a(); + } catch(e) { /*ignore*/ } + + const mapping = coverage.generate(contract.data, util.pathPrefix); + + assert.deepEqual(mapping[util.filePath].l, { + 8:5, 9:3, 10:3, 14:2, 18:1, 22:3 + }); + assert.deepEqual(mapping[util.filePath].b, { + 1:[3,2], 2:[1,2], 3:[3,2], + }); + assert.deepEqual(mapping[util.filePath].s, { + 1:5, 2:3, 3:3 + }); + assert.deepEqual(mapping[util.filePath].f, { + 1:5, 2:2, 3:1, 4:3 + }); + }); + // Case: when first modifier always suceeds but a subsequent modifier succeeds and fails, // there should be a missing `else` branch on first modifier it('should not be influenced by revert from a subsequent modifier', async function() {