/ lib / modules / coverage / contract_sources.js
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;