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;