Add modifierWhitelist option (#597)

experimental-options
cgewecke 4 years ago
parent 2be29b2edb
commit b2d4a667d5
  1. 1
      README.md
  2. 3
      lib/instrumenter.js
  3. 3
      lib/parse.js
  4. 10
      lib/registrar.js
  5. 5
      lib/validator.js
  6. 24
      test/units/modifiers.js
  7. 1
      test/units/validator.js

@ -102,6 +102,7 @@ module.exports = {
| measureFunctionCoverage | *boolean* | `true` | Computes function coverage. [More...][34] | | measureFunctionCoverage | *boolean* | `true` | Computes function coverage. [More...][34] |
| measureModifierCoverage | *boolean* | `true` | Computes each modifier invocation as a code branch. [More...][34] | | measureModifierCoverage | *boolean* | `true` | Computes each modifier invocation as a code branch. [More...][34] |
| matrixOutputPath | *String* | `./testMatrix.json` | Relative path to write test matrix JSON object to. [More...][39] | | matrixOutputPath | *String* | `./testMatrix.json` | Relative path to write test matrix JSON object to. [More...][39] |
| 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.)) |
| istanbulFolder | *String* | `./coverage` | Folder location for Istanbul coverage reports. | | istanbulFolder | *String* | `./coverage` | Folder location for Istanbul coverage reports. |
| istanbulReporter | *Array* | `['html', 'lcov', 'text', 'json']` | [Istanbul coverage reporters][2] | | istanbulReporter | *Array* | `['html', 'lcov', 'text', 'json']` | [Istanbul coverage reporters][2] |
| mocha | *Object* | `{ }` | [Mocha options][3] to merge into existing mocha config. `grep` and `invert` are useful for skipping certain tests under coverage using tags in the test descriptions.| | mocha | *Object* | `{ }` | [Mocha options][3] to merge into existing mocha config. `grep` and `invert` are useful for skipping certain tests under coverage using tags in the test descriptions.|

@ -15,6 +15,7 @@ class Instrumenter {
constructor(config={}){ constructor(config={}){
this.instrumentationData = {}; this.instrumentationData = {};
this.injector = new Injector(); this.injector = new Injector();
this.modifierWhitelist = config.modifierWhitelist || [];
this.enabled = { this.enabled = {
statements: (config.measureStatementCoverage === false) ? false : true, statements: (config.measureStatementCoverage === false) ? false : true,
functions: (config.measureFunctionCoverage === false) ? false: true, functions: (config.measureFunctionCoverage === false) ? false: true,
@ -62,7 +63,7 @@ class Instrumenter {
const contract = {}; const contract = {};
this.injector.resetModifierMapping(); this.injector.resetModifierMapping();
parse.configure(this.enabled); parse.configure(this.enabled, this.modifierWhitelist);
contract.source = contractSource; contract.source = contractSource;
contract.instrumented = contractSource; contract.instrumented = contractSource;

@ -11,8 +11,9 @@ const FILE_SCOPED_ID = "fileScopedId";
const parse = {}; const parse = {};
// Utilities // Utilities
parse.configure = function(_enabled){ parse.configure = function(_enabled, _whitelist){
register.enabled = Object.assign(register.enabled, _enabled); register.enabled = Object.assign(register.enabled, _enabled);
register.modifierWhitelist = _whitelist;
} }
// Nodes // Nodes

@ -19,6 +19,8 @@ class Registrar {
branches: true, branches: true,
lines: true lines: true
} }
this.modifierWhitelist = [];
} }
/** /**
@ -129,7 +131,13 @@ class Registrar {
} }
// Add modifier branch coverage // Add modifier branch coverage
if (!this.enabled.modifiers || expression.isConstructor) continue; if (
!this.enabled.modifiers ||
expression.isConstructor ||
this.modifierWhitelist.includes(modifier.name)
) {
continue;
}
this.addNewBranch(contract, modifier); this.addNewBranch(contract, modifier);
this._createInjectionPoint( this._createInjectionPoint(

@ -42,6 +42,11 @@ const configSchema = {
type: "array", type: "array",
items: {type: "string"} items: {type: "string"}
}, },
modifierWhitelist: {
type: "array",
items: {type: "string"}
}
}, },
}; };

@ -13,7 +13,10 @@ describe('modifiers', () => {
api = new Api({silent: true}); api = new Api({silent: true});
await api.ganache(client); await api.ganache(client);
}) })
beforeEach(() => coverage = new Coverage()); beforeEach(() => {
api.config = {};
coverage = new Coverage()
});
after(async() => await api.finish()); after(async() => await api.finish());
async function setupAndRun(solidityFile){ async function setupAndRun(solidityFile){
@ -97,6 +100,25 @@ describe('modifiers', () => {
}); });
}); });
// Same test as above - should have 2 fewer branches
it('should exclude whitelisted modifiers', async function() {
api.config.modifierWhitelist = ['mmm', 'nnn'];
const mapping = await setupAndRun('modifiers/multiple-mods-same-fn');
assert.deepEqual(mapping[util.filePath].l, {
5: 1, 6: 1, 10: 1, 11: 1, 15: 1
});
assert.deepEqual(mapping[util.filePath].b, {
1: [1, 0], 2: [1, 0]
});
assert.deepEqual(mapping[util.filePath].s, {
1: 1, 2: 1, 3: 1
});
assert.deepEqual(mapping[util.filePath].f, {
1: 1, 2: 1, 3: 1
});
});
it('should cover multiple functions which use the same modifier', async function() { it('should cover multiple functions which use the same modifier', async function() {
const contract = await util.bootstrapCoverage('modifiers/multiple-fns-same-mod', api); const contract = await util.bootstrapCoverage('modifiers/multiple-fns-same-mod', api);
coverage.addContract(contract.instrumented, util.filePath); coverage.addContract(contract.instrumented, util.filePath);

@ -119,6 +119,7 @@ describe('config validation', () => {
const options = [ const options = [
"skipFiles", "skipFiles",
"istanbulReporter", "istanbulReporter",
"modifierWhitelist"
] ]
options.forEach(name => { options.forEach(name => {

Loading…
Cancel
Save