2018-08-01 15:48:17 +00:00
|
|
|
const fs = require('fs');
|
2018-08-07 19:26:39 +00:00
|
|
|
const path = require('path');
|
2018-08-01 15:48:17 +00:00
|
|
|
|
|
|
|
const ContractSource = require('./contract_source');
|
|
|
|
|
|
|
|
class ContractSources {
|
|
|
|
constructor(files) {
|
|
|
|
this.files = {};
|
|
|
|
|
2018-08-07 19:26:39 +00:00
|
|
|
switch(Object.prototype.toString.call(files)) {
|
|
|
|
case '[object Object]':
|
2018-08-28 17:39:18 +00:00
|
|
|
Object.keys(files).forEach((file) => { this.addFile(file, files[file]); });
|
2018-08-07 19:26:39 +00:00
|
|
|
break;
|
2018-08-28 17:39:18 +00:00
|
|
|
|
2018-08-07 19:26:39 +00:00
|
|
|
case '[object String]':
|
|
|
|
// No 'break' statement here on purpose, as it shares
|
|
|
|
// the logic below.
|
|
|
|
files = [files];
|
2018-08-09 20:46:20 +00:00
|
|
|
// falls through
|
2018-08-07 19:26:39 +00:00
|
|
|
|
|
|
|
case '[object Array]':
|
|
|
|
files.forEach((file) => {
|
2018-08-28 17:39:18 +00:00
|
|
|
var content = fs.readFileSync(file).toString();
|
|
|
|
this.addFile(file, content);
|
2018-08-07 19:26:39 +00:00
|
|
|
});
|
|
|
|
break;
|
2018-08-09 20:46:20 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
throw new Error(`Don't know how to initialize with ${Object.prototype.toString.call(files)}`);
|
2018-08-07 19:26:39 +00:00
|
|
|
}
|
2018-08-01 15:48:17 +00:00
|
|
|
}
|
|
|
|
|
2018-08-28 17:39:18 +00:00
|
|
|
addFile(fullPath, contents) {
|
|
|
|
let basename = path.basename(fullPath);
|
|
|
|
if(this.files[basename]) return;
|
|
|
|
|
|
|
|
this.files[basename] = new ContractSource(basename, fullPath, contents);
|
|
|
|
}
|
|
|
|
|
2018-08-01 15:48:17 +00:00
|
|
|
toSolcInputs() {
|
|
|
|
var inputs = {};
|
|
|
|
|
|
|
|
for(var file in this.files) {
|
|
|
|
inputs[file] = {content: this.files[file].body};
|
|
|
|
}
|
|
|
|
|
|
|
|
return inputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
parseSolcOutput(output) {
|
|
|
|
for(var file in output.contracts) {
|
2018-08-10 14:58:18 +00:00
|
|
|
var contractSource = this.files[path.basename(file)];
|
2018-08-09 20:46:20 +00:00
|
|
|
if(!contractSource) continue;
|
2018-08-07 19:26:39 +00:00
|
|
|
|
|
|
|
contractSource.parseSolcOutput(output.sources[file], output.contracts[file]);
|
2018-08-01 15:48:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
generateCodeCoverage(trace) {
|
|
|
|
var coverageReport = {};
|
|
|
|
|
|
|
|
for(var file in this.files) {
|
2018-09-23 23:07:57 +00:00
|
|
|
if(this.files[file].isInterface()) continue;
|
2018-08-10 14:58:18 +00:00
|
|
|
coverageReport[file] = this.files[file].generateCodeCoverage(trace);
|
2018-08-01 15:48:17 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 19:26:39 +00:00
|
|
|
if(!this.coverageReport) {
|
|
|
|
this.coverageReport = coverageReport;
|
|
|
|
return this.coverageReport;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We already have a previous coverage report, so we're merging results here.
|
|
|
|
Object.keys(coverageReport).forEach((file) => {
|
|
|
|
if(!this.coverageReport[file]) {
|
|
|
|
this.coverageReport[file] = coverageReport[file];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increment counters for statements, functions and lines
|
|
|
|
['s', 'f', 'l'].forEach((countType) => {
|
|
|
|
Object.keys(coverageReport[file][countType]).forEach((id) => {
|
|
|
|
this.coverageReport[file][countType][id] += coverageReport[file][countType][id];
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Branch counts are tracked in a different manner so we'll do these now
|
|
|
|
Object.keys(coverageReport[file].b).forEach((id) => {
|
2018-10-18 12:37:28 +00:00
|
|
|
// FIXME in solc-tests, this is sometimes empty
|
|
|
|
if (!this.coverageReport[file].b[id] || !this.coverageReport[file].b[id].length) {
|
|
|
|
return;
|
|
|
|
}
|
2018-08-07 19:26:39 +00:00
|
|
|
this.coverageReport[file].b[id][0] += coverageReport[file].b[id][0];
|
|
|
|
this.coverageReport[file].b[id][1] += coverageReport[file].b[id][1];
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return this.coverageReport;
|
2018-08-01 15:48:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = ContractSources;
|