contract_sources.js
1 const fs = require('fs'); 2 const path = require('path'); 3 4 const ContractSource = require('./contract_source'); 5 6 class ContractSources { 7 constructor(files) { 8 this.files = {}; 9 10 switch(Object.prototype.toString.call(files)) { 11 case '[object Object]': 12 Object.keys(files).forEach((file) => { this.addFile(file, files[file]); }); 13 break; 14 15 case '[object String]': 16 // No 'break' statement here on purpose, as it shares 17 // the logic below. 18 files = [files]; 19 // falls through 20 21 case '[object Array]': 22 files.forEach((file) => { 23 var content = fs.readFileSync(file).toString(); 24 this.addFile(file, content); 25 }); 26 break; 27 28 default: 29 throw new Error(`Don't know how to initialize with ${Object.prototype.toString.call(files)}`); 30 } 31 } 32 33 addFile(fullPath, contents) { 34 let basename = path.basename(fullPath); 35 if(this.files[basename]) return; 36 37 this.files[basename] = new ContractSource(basename, fullPath, contents); 38 } 39 40 toSolcInputs() { 41 var inputs = {}; 42 43 for(var file in this.files) { 44 inputs[file] = {content: this.files[file].body}; 45 } 46 47 return inputs; 48 } 49 50 parseSolcOutput(output) { 51 for(var file in output.contracts) { 52 var contractSource = this.files[path.basename(file)]; 53 if(!contractSource) continue; 54 55 contractSource.parseSolcOutput(output.sources[file], output.contracts[file]); 56 } 57 } 58 59 generateCodeCoverage(trace) { 60 var coverageReport = {}; 61 62 for(var file in this.files) { 63 if(this.files[file].isInterface()) continue; 64 coverageReport[file] = this.files[file].generateCodeCoverage(trace); 65 } 66 67 if(!this.coverageReport) { 68 this.coverageReport = coverageReport; 69 return this.coverageReport; 70 } 71 72 // We already have a previous coverage report, so we're merging results here. 73 Object.keys(coverageReport).forEach((file) => { 74 if(!this.coverageReport[file]) { 75 this.coverageReport[file] = coverageReport[file]; 76 return; 77 } 78 79 // Increment counters for statements, functions and lines 80 ['s', 'f', 'l'].forEach((countType) => { 81 Object.keys(coverageReport[file][countType]).forEach((id) => { 82 this.coverageReport[file][countType][id] += coverageReport[file][countType][id]; 83 }); 84 }); 85 86 // Branch counts are tracked in a different manner so we'll do these now 87 Object.keys(coverageReport[file].b).forEach((id) => { 88 // FIXME in solc-tests, this is sometimes empty 89 if (!this.coverageReport[file].b[id] || !this.coverageReport[file].b[id].length) { 90 return; 91 } 92 this.coverageReport[file].b[id][0] += coverageReport[file].b[id][0]; 93 this.coverageReport[file].b[id][1] += coverageReport[file].b[id][1]; 94 }); 95 }); 96 97 return this.coverageReport; 98 } 99 } 100 101 module.exports = ContractSources;