Skip to content

Commit 9b169aa

Browse files
committed
Add logicalOR branch highlighting for html report
1 parent 0763bd6 commit 9b169aa

File tree

11 files changed

+206
-8
lines changed

11 files changed

+206
-8
lines changed

lib/registrar.js

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,29 +182,50 @@ class Registrar {
182182
* @param {Object} expression AST node
183183
*/
184184
addNewLogicalORBranch(contract, expression) {
185-
const startContract = contract.instrumented.slice(0, expression.range[0]);
186-
const startline = ( startContract.match(/\n/g) || [] ).length + 1;
185+
let start;
186+
187+
// Instabul HTML highlighting location data...
188+
const leftZero = expression.left.range[0];
189+
const leftOne = expression.left.range[1];
190+
const rightZero = expression.right.range[0];
191+
const rightOne = expression.right.range[1];
192+
193+
start = contract.instrumented.slice(0, leftZero);
194+
const leftStartLine = ( start.match(/\n/g) || [] ).length + 1;
195+
const leftStartCol = leftZero - start.lastIndexOf('\n') - 1;
196+
197+
start = contract.instrumented.slice(0, leftOne);
198+
const leftEndLine = ( start.match(/\n/g) || [] ).length + 1;
199+
const leftEndCol = leftOne - start.lastIndexOf('\n') - 1;
200+
201+
start = contract.instrumented.slice(0, rightZero);
202+
const rightStartLine = ( start.match(/\n/g) || [] ).length + 1;
203+
const rightStartCol = rightZero - start.lastIndexOf('\n') - 1;
204+
205+
start = contract.instrumented.slice(0, rightOne);
206+
const rightEndLine = ( start.match(/\n/g) || [] ).length + 1;
207+
const rightEndCol = rightOne - start.lastIndexOf('\n') - 1;
187208

188209
contract.branchId += 1;
189210

190211
// NB locations for if branches in istanbul are zero
191212
// length and associated with the start of the if.
192213
contract.branchMap[contract.branchId] = {
193-
line: startline,
214+
line: leftStartLine,
194215
type: 'cond-expr',
195216
locations: [{
196217
start: {
197-
line: startline, column: expression.left.range[0],
218+
line: leftStartLine, column: leftStartCol,
198219
},
199220
end: {
200-
line: startline, column: expression.left.range[1],
221+
line: leftEndLine, column: leftEndCol,
201222
},
202223
}, {
203224
start: {
204-
line: startline, column: expression.right.range[0],
225+
line: rightStartLine, column: rightStartCol,
205226
},
206227
end: {
207-
line: startline, column: expression.right.range[1],
228+
line: rightEndLine, column: rightEndCol,
208229
},
209230
}],
210231
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Testing hooks
2+
const fn = (msg, config) => config.logger.log(msg);
3+
4+
module.exports = {
5+
skipFiles: ['Migrations.sol'],
6+
silent: process.env.SILENT ? true : false,
7+
istanbulReporter: ['json-summary', 'text'],
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const { loadPluginFile } = require("@nomiclabs/buidler/plugins-testing");
2+
loadPluginFile(__dirname + "/../plugins/buidler.plugin");
3+
usePlugin("@nomiclabs/buidler-truffle5");
4+
5+
module.exports={
6+
defaultNetwork: "buidlerevm"
7+
};
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
pragma solidity ^0.5.0;
2+
3+
4+
contract ContractA {
5+
6+
function _if(uint i) public pure {
7+
if (i == 0 || i > 5){
8+
/* ignore */
9+
}
10+
}
11+
12+
function _if_and(uint i) public pure {
13+
if (i != 0 && (i < 2 || i > 5)){
14+
/* ignore */
15+
}
16+
}
17+
18+
function _return(uint i) public pure returns (bool){
19+
return (i != 0 && i != 1 ) ||
20+
((i + 1) == 2);
21+
}
22+
23+
function _while(uint i) public pure returns (bool){
24+
uint counter;
25+
while( (i == 1 || i == 2) && counter < 2 ){
26+
counter++;
27+
}
28+
}
29+
30+
function _require(uint x) public {
31+
require(x == 1 || x == 2);
32+
}
33+
34+
function _require_multi_line(uint x) public {
35+
require(
36+
(x == 1 || x == 2) ||
37+
x == 3
38+
);
39+
}
40+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const ContractA = artifacts.require("ContractA");
2+
3+
contract("contracta", function(accounts) {
4+
let instance;
5+
6+
before(async () => instance = await ContractA.new())
7+
8+
it('_if', async function(){
9+
await instance._if(0);
10+
await instance._if(7);
11+
});
12+
13+
it('_if_and', async function(){
14+
await instance._if_and(1);
15+
});
16+
17+
it('_return', async function(){
18+
await instance._return(4);
19+
});
20+
21+
it('_while', async function(){
22+
await instance._while(1);
23+
});
24+
25+
it('_require', async function(){
26+
await instance._require(2);
27+
})
28+
29+
it('_require_multi_line', async function(){
30+
await instance._require_multi_line(1);
31+
await instance._require_multi_line(3);
32+
})
33+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
networks: {},
3+
mocha: {},
4+
compilers: {
5+
solc: {}
6+
}
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pragma solidity ^0.5.0;
2+
3+
contract Test {
4+
function a(uint x) public {
5+
require(
6+
x == 1 ||
7+
x == 2 ||
8+
x == 3
9+
);
10+
}
11+
}

test/units/buidler/standard.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,20 @@ describe('Buidler Plugin: standard use cases', function() {
294294

295295
verify.lineCoverage(expected);
296296
})
297-
})
297+
298+
it('logicalOR', async function(){
299+
mock.installFullProject('logical-or');
300+
mock.buidlerSetupEnv(this);
301+
302+
await this.env.run("coverage");
303+
304+
const expected = [
305+
{
306+
file: mock.pathToContract(buidlerConfig, 'ContractA.sol'),
307+
pct: 59.09
308+
}
309+
];
310+
311+
verify.branchCoverage(expected);
312+
})
313+
})

test/units/or.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,33 @@ describe('logical OR branches', () => {
7979
});
8080
});
8181

82+
// require(
83+
// x == 1 ||
84+
// x == 2 ||
85+
// x == 3
86+
// )
87+
it('should cover a require statement with multiline OR condition (two branches)', async function() {
88+
const contract = await util.bootstrapCoverage('or/require-multiline-or', provider, collector);
89+
coverage.addContract(contract.instrumented, util.filePath);
90+
await contract.instance.a(1);
91+
await contract.instance.a(3);
92+
93+
const mapping = coverage.generate(contract.data, util.pathPrefix);
94+
95+
assert.deepEqual(mapping[util.filePath].l, {
96+
5: 2,
97+
});
98+
assert.deepEqual(mapping[util.filePath].b, {
99+
1: [2, 0], 2: [1, 0], 3: [0, 1]
100+
});
101+
assert.deepEqual(mapping[util.filePath].s, {
102+
1: 2,
103+
});
104+
assert.deepEqual(mapping[util.filePath].f, {
105+
1: 2,
106+
});
107+
});
108+
82109
// require(x == 1 || x == 2)
83110
it('should cover a require statement with a simple OR condition (both branches)', async function() {
84111
const contract = await util.bootstrapCoverage('or/require-or', provider, collector);

test/units/truffle/standard.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,4 +433,18 @@ describe('Truffle Plugin: standard use cases', function() {
433433

434434
verify.lineCoverage(expected);
435435
})
436+
437+
it('logicalOR', async function(){
438+
mock.installFullProject('logical-or');
439+
await plugin(truffleConfig);
440+
441+
const expected = [
442+
{
443+
file: mock.pathToContract(truffleConfig, 'ContractA.sol'),
444+
pct: 59.09
445+
}
446+
];
447+
448+
verify.branchCoverage(expected);
449+
})
436450
})

0 commit comments

Comments
 (0)