Skip to content

Commit 042a99e

Browse files
authored
Add try / catch unit tests (#857)
1 parent 01ab173 commit 042a99e

File tree

6 files changed

+210
-0
lines changed

6 files changed

+210
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pragma solidity >=0.8.0 <0.9.0;
2+
3+
contract Test {
4+
function op(bool y) external {
5+
require(y);
6+
}
7+
8+
function a(bool x) external {
9+
try this.op(x) { } catch { }
10+
}
11+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
pragma solidity >=0.8.0 <0.9.0;
2+
3+
contract Test {
4+
function op(bool y) external returns (uint){
5+
require(y, "sorry");
6+
return 1;
7+
}
8+
9+
function a(bool x) external returns (uint) {
10+
try this.op(x) returns (uint v) {
11+
return v;
12+
} catch Error(string memory /*reason*/) {
13+
return 0;
14+
}
15+
}
16+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
pragma solidity >=0.8.0 <0.9.0;
2+
3+
contract Test {
4+
function op(uint y) external returns (uint){
5+
uint a = 100;
6+
uint b = 0;
7+
8+
if (y == 0)
9+
return 0;
10+
if (y == 1)
11+
require(false, 'sorry');
12+
if (y == 2)
13+
uint x = (a / b);
14+
if (y == 3)
15+
revert();
16+
}
17+
18+
function a(uint x) external returns (uint) {
19+
try this.op(x) returns (uint v) {
20+
return 0;
21+
} catch Error(string memory /*reason*/) {
22+
return 1;
23+
} catch Panic(uint /*errorCode*/) {
24+
return 2;
25+
} catch (bytes memory /*lowLevelData*/) {
26+
return 3;
27+
}
28+
}
29+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
pragma solidity >=0.8.0 <0.9.0;
2+
3+
contract Test {
4+
function op(bool y) external returns (uint){
5+
uint x = 100 / 0;
6+
return x;
7+
}
8+
9+
function a(bool x) external pure returns (uint) {
10+
try this.op(x) returns (uint v) {
11+
return v;
12+
} catch Panic(uint /*errorCode*/) {
13+
return 0;
14+
}
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
pragma solidity >=0.8.0 <0.9.0;
2+
3+
contract Test {
4+
function op(bool y) external returns (uint){
5+
if (y == false) revert();
6+
}
7+
8+
function a(bool x) external pure returns (uint) {
9+
try this.op(x) returns (uint v) {
10+
return v;
11+
} catch (bytes memory /*lowLevelData*/) {
12+
return 0;
13+
}
14+
}
15+
}

test/units/try.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
const assert = require('assert');
2+
const util = require('./../util/util.js');
3+
const Coverage = require('./../../lib/coverage');
4+
const Api = require('./../../lib/api')
5+
6+
describe.only('try / catch branches', () => {
7+
let coverage;
8+
let api;
9+
10+
before(async () => api = new Api({silent: true}));
11+
beforeEach(() => coverage = new Coverage());
12+
after(async() => await api.finish());
13+
14+
it('should cover a try/catch statement with empty blocks (success branch only)', async function() {
15+
const contract = await util.bootstrapCoverage('try/try-catch-empty-blocks', api, this.provider, );
16+
coverage.addContract(contract.instrumented, util.filePath);
17+
await contract.instance.a(true, contract.gas);
18+
const mapping = coverage.generate(contract.data, util.pathPrefix);
19+
20+
assert.deepEqual(mapping[util.filePath].l, {
21+
5:1,9:1
22+
});
23+
assert.deepEqual(mapping[util.filePath].b, {
24+
1:[1,0]
25+
});
26+
assert.deepEqual(mapping[util.filePath].s, {
27+
1:1,2:1
28+
});
29+
assert.deepEqual(mapping[util.filePath].f, {
30+
1:1,2:1
31+
});
32+
});
33+
34+
it('should cover a try/catch statement with empty blocks (both branches)', async function() {
35+
const contract = await util.bootstrapCoverage('try/try-catch-empty-blocks', api, this.provider, );
36+
coverage.addContract(contract.instrumented, util.filePath);
37+
await contract.instance.a(true, contract.gas);
38+
39+
try { await contract.instance.a(false, contract.gas) } catch(err) { /* ignore */ }
40+
41+
const mapping = coverage.generate(contract.data, util.pathPrefix);
42+
43+
assert.deepEqual(mapping[util.filePath].l, {
44+
5:2,9:2
45+
});
46+
assert.deepEqual(mapping[util.filePath].b, {
47+
1:[1,1]
48+
});
49+
assert.deepEqual(mapping[util.filePath].s, {
50+
1:2,2:2
51+
});
52+
assert.deepEqual(mapping[util.filePath].f, {
53+
1:2,2:2
54+
});
55+
});
56+
57+
it('should cover a try/catch statement with an Error block (success branch only)', async function() {
58+
const contract = await util.bootstrapCoverage('try/try-error-block', api, this.provider, );
59+
coverage.addContract(contract.instrumented, util.filePath);
60+
await contract.instance.a(true, contract.gas);
61+
62+
const mapping = coverage.generate(contract.data, util.pathPrefix);
63+
64+
assert.deepEqual(mapping[util.filePath].l, {
65+
5:1,6:1,10:1,11:1,13:0
66+
});
67+
assert.deepEqual(mapping[util.filePath].b, {
68+
1:[1,0]
69+
});
70+
assert.deepEqual(mapping[util.filePath].s, {
71+
1:1,2:1,3:1,4:1,5:0
72+
});
73+
assert.deepEqual(mapping[util.filePath].f, {
74+
1:1,2:1
75+
});
76+
});
77+
78+
it('should cover a try/catch statement with an Error block (both branches)', async function() {
79+
const contract = await util.bootstrapCoverage('try/try-error-block', api, this.provider, );
80+
coverage.addContract(contract.instrumented, util.filePath);
81+
82+
await contract.instance.a(true, contract.gas);
83+
try { await contract.instance.a(false, contract.gas) } catch(err) { /* ignore */ }
84+
85+
const mapping = coverage.generate(contract.data, util.pathPrefix);
86+
87+
assert.deepEqual(mapping[util.filePath].l, {
88+
5:2,6:1,10:2,11:1,13:1
89+
});
90+
assert.deepEqual(mapping[util.filePath].b, {
91+
1:[1,1]
92+
});
93+
assert.deepEqual(mapping[util.filePath].s, {
94+
1:2,2:1,3:2,4:1,5:1
95+
});
96+
assert.deepEqual(mapping[util.filePath].f, {
97+
1:2,2:2
98+
});
99+
});
100+
101+
it('should cover a try/catch statement with multi-block catch clauses (middle-block)', async function() {
102+
const contract = await util.bootstrapCoverage('try/try-multi-block', api, this.provider, );
103+
coverage.addContract(contract.instrumented, util.filePath);
104+
105+
await contract.instance.a(0, contract.gas);
106+
try { await contract.instance.a(2, contract.gas) } catch(err) { /* ignore */ }
107+
108+
const mapping = coverage.generate(contract.data, util.pathPrefix);
109+
110+
assert.deepEqual(mapping[util.filePath].l, {
111+
5:2,6:2,8:2,9:1,10:1,11:0,12:1,13:1,14:0,15:0,19:2,20:1,22:0,24:1,26:0
112+
});
113+
assert.deepEqual(mapping[util.filePath].b, {
114+
1:[1,1],2:[0,1],3:[0,0],4:[1,0],5:[0,0]
115+
});
116+
assert.deepEqual(mapping[util.filePath].s, {
117+
1:2,2:2,3:2,4:1,5:1,6:0,7:1,8:1,9:0,10:0,11:2,12:1,13:0,14:1,15:0
118+
});
119+
assert.deepEqual(mapping[util.filePath].f, {
120+
1:2,2:2
121+
});
122+
});
123+
});

0 commit comments

Comments
 (0)