Skip to content

Commit ecde305

Browse files
authored
Add modifierWhitelist option (#597)
1 parent b348134 commit ecde305

File tree

7 files changed

+43
-4
lines changed

7 files changed

+43
-4
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ module.exports = {
125125
| measureStatementCoverage | *boolean* | `true` | Computes statement (in addition to line) coverage. [More...][34] |
126126
| measureFunctionCoverage | *boolean* | `true` | Computes function coverage. [More...][34] |
127127
| measureModifierCoverage | *boolean* | `true` | Computes each modifier invocation as a code branch. [More...][34] |
128+
| modifierWhitelist | *String[]* | `[]` | List of modifier names (ex: "onlyOwner") to exclude from branch measurement. (Useful for modifiers which prepare something instead of acting as a gate.)) |
128129
| matrixOutputPath | *String* | `./testMatrix.json` | Relative path to write test matrix JSON object to. [More...][38] |
129130
| istanbulFolder | *String* | `./coverage` | Folder location for Istanbul coverage reports. |
130131
| istanbulReporter | *Array* | `['html', 'lcov', 'text', 'json']` | [Istanbul coverage reporters][2] |

lib/instrumenter.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Instrumenter {
1515
constructor(config={}){
1616
this.instrumentationData = {};
1717
this.injector = new Injector();
18+
this.modifierWhitelist = config.modifierWhitelist || [];
1819
this.enabled = {
1920
statements: (config.measureStatementCoverage === false) ? false : true,
2021
functions: (config.measureFunctionCoverage === false) ? false: true,
@@ -62,7 +63,7 @@ class Instrumenter {
6263
const contract = {};
6364

6465
this.injector.resetModifierMapping();
65-
parse.configure(this.enabled);
66+
parse.configure(this.enabled, this.modifierWhitelist);
6667

6768
contract.source = contractSource;
6869
contract.instrumented = contractSource;

lib/parse.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ const register = new Registrar();
99
const parse = {};
1010

1111
// Utilities
12-
parse.configure = function(_enabled){
12+
parse.configure = function(_enabled, _whitelist){
1313
register.enabled = Object.assign(register.enabled, _enabled);
14+
register.modifierWhitelist = _whitelist;
1415
}
1516

1617
// Nodes

lib/registrar.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class Registrar {
1919
branches: true,
2020
lines: true
2121
}
22+
23+
this.modifierWhitelist = [];
2224
}
2325

2426
/**
@@ -129,7 +131,13 @@ class Registrar {
129131
}
130132

131133
// Add modifier branch coverage
132-
if (!this.enabled.modifiers || expression.isConstructor) continue;
134+
if (
135+
!this.enabled.modifiers ||
136+
expression.isConstructor ||
137+
this.modifierWhitelist.includes(modifier.name)
138+
) {
139+
continue;
140+
}
133141

134142
this.addNewBranch(contract, modifier);
135143
this._createInjectionPoint(

lib/validator.js

+5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ const configSchema = {
4242
type: "array",
4343
items: {type: "string"}
4444
},
45+
46+
modifierWhitelist: {
47+
type: "array",
48+
items: {type: "string"}
49+
}
4550
},
4651
};
4752

test/units/modifiers.js

+23-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ describe('modifiers', () => {
1313
api = new Api({silent: true});
1414
await api.ganache(client);
1515
})
16-
beforeEach(() => coverage = new Coverage());
16+
beforeEach(() => {
17+
api.config = {};
18+
coverage = new Coverage()
19+
});
1720
after(async() => await api.finish());
1821

1922
async function setupAndRun(solidityFile){
@@ -97,6 +100,25 @@ describe('modifiers', () => {
97100
});
98101
});
99102

103+
// Same test as above - should have 2 fewer branches
104+
it('should exclude whitelisted modifiers', async function() {
105+
api.config.modifierWhitelist = ['mmm', 'nnn'];
106+
const mapping = await setupAndRun('modifiers/multiple-mods-same-fn');
107+
108+
assert.deepEqual(mapping[util.filePath].l, {
109+
5: 1, 6: 1, 10: 1, 11: 1, 15: 1
110+
});
111+
assert.deepEqual(mapping[util.filePath].b, {
112+
1: [1, 0], 2: [1, 0]
113+
});
114+
assert.deepEqual(mapping[util.filePath].s, {
115+
1: 1, 2: 1, 3: 1
116+
});
117+
assert.deepEqual(mapping[util.filePath].f, {
118+
1: 1, 2: 1, 3: 1
119+
});
120+
});
121+
100122
it('should cover multiple functions which use the same modifier', async function() {
101123
const contract = await util.bootstrapCoverage('modifiers/multiple-fns-same-mod', api);
102124
coverage.addContract(contract.instrumented, util.filePath);

test/units/validator.js

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ describe('config validation', () => {
119119
const options = [
120120
"skipFiles",
121121
"istanbulReporter",
122+
"modifierWhitelist"
122123
]
123124

124125
options.forEach(name => {

0 commit comments

Comments
 (0)