Istanbul reporter (#388)

* Make istanbul reporter configurable

* Add coverage expectations to plugin integration tests

* Add kandrianov to contributors list
pull/389/head
Kanstantsin Andryanau 5 years ago committed by cgewecke
parent 3f59e8ae3b
commit cc3e18a34a
  1. 6
      README.md
  2. 7
      lib/app.js
  3. 3
      test/integration/projects/import-paths/.solcover.js
  4. 1
      test/integration/projects/multiple-migrations/.solcover.js
  5. 3
      test/integration/projects/skipping/.solcover.js
  6. 1
      test/integration/projects/test-files/.solcover.js
  7. 94
      test/units/app.js

@ -38,7 +38,7 @@ a local dependency, please see [this section](https://github.com/sc-forks/solidi
### Network Configuration ### Network Configuration
By default, this tool connects to a coverage-enabled fork of ganache-cli By default, this tool connects to a coverage-enabled fork of ganache-cli
called **testrpc-sc** on port 8555. called **testrpc-sc** on port 8555.
+ it's a dependency - there's nothing extra to download. + it's a dependency - there's nothing extra to download.
+ the solidity-coverage command launches it automatically in the background. (See [this section of the FAQ](https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#running-testrpc-sc-on-its-own) if you need to launch it separately yourself) + the solidity-coverage command launches it automatically in the background. (See [this section of the FAQ](https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#running-testrpc-sc-on-its-own) if you need to launch it separately yourself)
@ -95,7 +95,8 @@ module.exports = {
| skipFiles | *Array* | `['Migrations.sol']` | Array of contracts or folders (with paths expressed relative to the `contracts` directory) that should be skipped when doing instrumentation. `Migrations.sol` is skipped by default, and does not need to be added to this configuration option if it is used. | | skipFiles | *Array* | `['Migrations.sol']` | Array of contracts or folders (with paths expressed relative to the `contracts` directory) that should be skipped when doing instrumentation. `Migrations.sol` is skipped by default, and does not need to be added to this configuration option if it is used. |
| deepSkip | boolean | false | Use this if instrumentation hangs on large, skipped files (like Oraclize). It's faster. | | deepSkip | boolean | false | Use this if instrumentation hangs on large, skipped files (like Oraclize). It's faster. |
| dir | *String* | `.` | Solidity-coverage copies all the assets in your root directory (except `node_modules`) to a special folder where it instruments the contracts and executes the tests. `dir` allows you to define a relative path from the root directory to those assets. Useful if your contracts & tests are within their own folder as part of a larger project.| | dir | *String* | `.` | Solidity-coverage copies all the assets in your root directory (except `node_modules`) to a special folder where it instruments the contracts and executes the tests. `dir` allows you to define a relative path from the root directory to those assets. Useful if your contracts & tests are within their own folder as part of a larger project.|
| buildDirPath | *String* | `/build/contracts` | Build directory path for compiled smart contracts | buildDirPath | *String* | `/build/contracts` | Build directory path for compiled smart contracts |
| istanbulReporter | *Array* | ['html', 'lcov', 'text'] | Coverage reporters for Istanbul. Optional reporter replaces the default reporters. |
### FAQ ### FAQ
@ -146,3 +147,4 @@ $ yarn
+ [@pinkiebell](https://github.com/pinkiebell) + [@pinkiebell](https://github.com/pinkiebell)
+ [@obernardovieira](https://github.com/obernardovieira) + [@obernardovieira](https://github.com/obernardovieira)
+ [@angus-hamill](https://github.com/angus-hamill) + [@angus-hamill](https://github.com/angus-hamill)
+ [@kandrianov](https://github.com/kandrianov)

@ -42,6 +42,8 @@ class App {
this.gasLimit = 0xfffffffffff; this.gasLimit = 0xfffffffffff;
this.gasLimitString = "0xfffffffffff"; this.gasLimitString = "0xfffffffffff";
this.gasPrice = 0x01; this.gasPrice = 0x01;
this.istanbulReporter = config.istanbulReporter || ['html', 'lcov', 'text'];
} }
// -------------------------------------- Methods ----------------------------------------------- // -------------------------------------- Methods -----------------------------------------------
@ -122,9 +124,8 @@ class App {
this.saveCoverage(relativeMapping); this.saveCoverage(relativeMapping);
collector.add(relativeMapping); collector.add(relativeMapping);
reporter.add('html');
reporter.add('lcov'); this.istanbulReporter.forEach(report => reporter.add(report));
reporter.add('text');
reporter.write(collector, true, () => { reporter.write(collector, true, () => {
this.log('Istanbul coverage reports generated'); this.log('Istanbul coverage reports generated');

@ -1,3 +1,4 @@
module.exports = { module.exports = {
silent: process.env.SILENT ? true : false, silent: process.env.SILENT ? true : false,
}; istanbulReporter: ['json-summary', 'text']
}

@ -1,3 +1,4 @@
module.exports = { module.exports = {
silent: process.env.SILENT ? true : false, silent: process.env.SILENT ? true : false,
istanbulReporter: ['json-summary', 'text']
}; };

@ -1,4 +1,5 @@
module.exports = { module.exports = {
silent: process.env.SILENT ? true : false, silent: process.env.SILENT ? true : false,
skipFiles: ['skipped-folder'] skipFiles: ['skipped-folder'],
istanbulReporter: ['json-summary', 'text']
} }

@ -1,3 +1,4 @@
module.exports = { module.exports = {
silent: process.env.SILENT ? true : false, silent: process.env.SILENT ? true : false,
istanbulReporter: ['json-summary', 'text']
} }

@ -12,6 +12,20 @@ const opts = { compact: false, depth: 5, breakLength: 80 };
// ======= // =======
function pathExists(path) { return shell.test('-e', path); } function pathExists(path) { return shell.test('-e', path); }
function pathToContract(config, file) {
return path.join('contracts', file);
}
function assertLineCoverage(expected=[]){
let summary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json'));
expected.forEach(item => assert(summary[item.file].lines.pct === item.pct))
}
function assertCoverageMissing(expected=[]){
let summary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json'));
expected.forEach(item => assert(summary[item.file] === undefined))
}
function assertCleanInitialState(){ function assertCleanInitialState(){
assert(pathExists('./coverage') === false, 'should start without: coverage'); assert(pathExists('./coverage') === false, 'should start without: coverage');
assert(pathExists('./coverage.json') === false, 'should start without: coverage.json'); assert(pathExists('./coverage.json') === false, 'should start without: coverage.json');
@ -88,12 +102,41 @@ describe('app', function() {
assertCleanInitialState(); assertCleanInitialState();
mock.installFullProject('multiple-migrations'); mock.installFullProject('multiple-migrations');
await plugin(truffleConfig); await plugin(truffleConfig);
const expected = [
{
file: pathToContract(truffleConfig, 'ContractA.sol'),
pct: 100
},
{
file: pathToContract(truffleConfig, 'ContractB.sol'),
pct: 100,
},
{
file: pathToContract(truffleConfig, 'ContractC.sol'),
pct: 100,
},
];
assertLineCoverage(expected);
}); });
it('project skips a folder', async function() { it('project skips a folder', async function() {
assertCleanInitialState(); assertCleanInitialState();
mock.installFullProject('skipping'); mock.installFullProject('skipping');
await plugin(truffleConfig); await plugin(truffleConfig);
const expected = [{
file: pathToContract(truffleConfig, 'ContractA.sol'),
pct: 100
}];
const missing = [{
file: pathToContract(truffleConfig, 'ContractB.sol'),
}];
assertLineCoverage(expected);
assertCoverageMissing(missing);
}); });
it('project with relative path solidity imports', async function() { it('project with relative path solidity imports', async function() {
@ -109,6 +152,23 @@ describe('app', function() {
truffleConfig.file = testPath; truffleConfig.file = testPath;
mock.installFullProject('test-files'); mock.installFullProject('test-files');
await plugin(truffleConfig); await plugin(truffleConfig);
const expected = [
{
file: pathToContract(truffleConfig, 'ContractA.sol'),
pct: 100
},
{
file: pathToContract(truffleConfig, 'ContractB.sol'),
pct: 0,
},
{
file: pathToContract(truffleConfig, 'ContractC.sol'),
pct: 0,
},
];
assertLineCoverage(expected);
}); });
it('truffle run coverage --file test/<glob*>', async function() { it('truffle run coverage --file test/<glob*>', async function() {
@ -118,6 +178,23 @@ describe('app', function() {
truffleConfig.file = testPath; truffleConfig.file = testPath;
mock.installFullProject('test-files'); mock.installFullProject('test-files');
await plugin(truffleConfig); await plugin(truffleConfig);
const expected = [
{
file: pathToContract(truffleConfig, 'ContractA.sol'),
pct: 0,
},
{
file: pathToContract(truffleConfig, 'ContractB.sol'),
pct: 100,
},
{
file: pathToContract(truffleConfig, 'ContractC.sol'),
pct: 100,
},
];
assertLineCoverage(expected);
}); });
it('truffle run coverage --file test/gl{o,b}*.js', async function() { it('truffle run coverage --file test/gl{o,b}*.js', async function() {
@ -127,6 +204,23 @@ describe('app', function() {
truffleConfig.file = testPath; truffleConfig.file = testPath;
mock.installFullProject('test-files'); mock.installFullProject('test-files');
await plugin(truffleConfig); await plugin(truffleConfig);
const expected = [
{
file: pathToContract(truffleConfig, 'ContractA.sol'),
pct: 0,
},
{
file: pathToContract(truffleConfig, 'ContractB.sol'),
pct: 100,
},
{
file: pathToContract(truffleConfig, 'ContractC.sol'),
pct: 100,
},
];
assertLineCoverage(expected);
}); });
it('contract only uses ".call"', async function(){ it('contract only uses ".call"', async function(){

Loading…
Cancel
Save