/ lib / modules / tests / solc_test.js
solc_test.js
  1  const Test = require('./test');
  2  const async = require('async');
  3  const fs = require('fs-extra');
  4  const remixTests = require('remix-tests');
  5  const Base = require('mocha/lib/reporters/base');
  6  const color = Base.color;
  7  
  8  class SolcTest extends Test {
  9    constructor(options) {
 10      super(options);
 11      this.assertLibCode = remixTests.assertLibCode;
 12    }
 13  
 14    init(cb) {
 15      const self = this;
 16      super.init(() => {
 17        self.events.request('config:contractsFiles:add', 'remix_tests.sol', (callback) => {
 18          callback(self.assertLibCode);
 19        });
 20        cb();
 21      });
 22    }
 23  
 24    setupTests(files, cb) {
 25      const self = this;
 26  
 27      async.waterfall([
 28        function addContracts(next) {
 29          files.forEach((file) => {
 30            let testFile = self._prepareContractForTest(file);
 31            self.events.request('config:contractsFiles:add', file, (callback) => {
 32              callback(testFile);
 33            });
 34          });
 35          next();
 36        },
 37        function initWeb3Provider(next) {
 38          self.initWeb3Provider(next);
 39        },
 40        function resetContracts(next) {
 41          self.events.request("contracts:reset:dependencies", next);
 42        },
 43        function compile(next) {
 44          console.info('Compiling contracts'.cyan);
 45          self.events.request("contracts:build", false, next);
 46        },
 47        function determineContractsToDeploy(next) {
 48          self.events.request("contracts:list", (err, contracts) => {
 49            let contractsToDeploy = contracts.filter((contract) => {
 50              return contract.filename && contract.filename.indexOf('_test.sol') >= 0;
 51            });
 52            let assertLib = contracts.filter((contract) => contract.filename === 'remix_tests.sol')[0];
 53            next(null, [assertLib].concat(contractsToDeploy));
 54          });
 55        },
 56        function deployContracts(contracts, next) {
 57          console.info('Deploying contracts'.cyan);
 58          let fns = [];
 59          contracts.forEach((contract) => {
 60            contract._gasLimit = self.gasLimit;
 61            let fn = (cb) => {
 62              self.events.request('deploy:contract', contract, cb);
 63            };
 64            fns.push(fn);
 65          });
 66          async.series(fns, next);
 67        }
 68      ], cb);
 69    }
 70  
 71    runTests(file, cb) {
 72      const self = this;
 73      console.info('Running tests'.cyan);
 74      const forwardSlashFile = file.replace(/\\/g, '/');
 75  
 76      async.waterfall([
 77        function getContracts(next) {
 78          self.events.request('contracts:all', (err, contracts) => {
 79            if (err) {
 80              return next(err);
 81            }
 82            const contractsToTest = [];
 83  
 84            Object.keys(contracts).forEach((contract) => {
 85              if (contracts[contract].filename &&
 86                contracts[contract].filename.replace(/\\/g, '/') === forwardSlashFile) {
 87                contractsToTest.push(contracts[contract]);
 88              }
 89            });
 90            next(null, contractsToTest);
 91          });
 92        },
 93        function getWeb3Object(contracts, next) {
 94          self.events.request('blockchain:get', (web3) => {
 95            next(null, contracts, web3);
 96          });
 97        },
 98        function run(contracts, web3, next) {
 99          let fns = [];
100          contracts.forEach((contract) => {
101            let fn = (_callback) => {
102              // TODO: web3 is not injected into the function. Issue has been raised on remixTests.
103              // To fix once web3 has been made injectable.
104              remixTests.runTest(contract.className, Test.getWeb3Contract(contract, web3),
105                self._prettyPrint.bind(self), _callback);
106            };
107            fns.push(fn);
108          });
109          async.series(fns, next);
110        }
111      ], cb);
112    }
113  
114    // dynamically insert Assert library as an import
115    // regexIndexOf has been added to String's prototype in remix-tests module
116    _prepareContractForTest(file) {
117      let c = fs.readFileSync(file).toString();
118      const s = /^(import)\s['"](remix_tests.sol)['"];/gm;
119      if (c.regexIndexOf(s) < 0) {
120        c = c.replace(/(pragma solidity \^\d+\.\d+\.\d+;)/, '$1\nimport \"remix_tests.sol\";');
121      }
122      return c;
123    }
124  
125    _prettyPrint(obj) {
126      if (obj.type === 'contract') {
127        console.info(color('suite', '%s'), obj.value);
128      } else if(obj.type === 'testPass') {
129        let fmt = color('checkmark', '  ' + Base.symbols.ok) + color('pass', ' %s');
130        console.info(fmt, obj.value);
131      } else if(obj.type === 'testFailure') {
132        let fmt = color('fail', '  %s %s');
133        console.info(fmt, Base.symbols.err, obj.value);
134      }
135    }
136  }
137  
138  module.exports = SolcTest;