diff --git a/remix-tests/src/compiler.js b/remix-tests/src/compiler.js deleted file mode 100644 index 7b450e97c4..0000000000 --- a/remix-tests/src/compiler.js +++ /dev/null @@ -1,129 +0,0 @@ -/* eslint no-extend-native: "warn" */ -let fs = require('./fs') -var async = require('async') -var path = require('path') -let RemixCompiler = require('remix-solidity').Compiler - -String.prototype.regexIndexOf = function (regex, startpos) { - var indexOf = this.substring(startpos || 0).search(regex) - return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf -} - -function writeTestAccountsContract (accounts) { - var testAccountContract = require('../sol/tests_accounts.sol.js') - var body = 'address[' + accounts.length + '] memory accounts;' - if (!accounts.length) body += ';' - else { - accounts.map((address, index) => { - body += `\naccounts[${index}] = ${address};\n` - }) - } - return testAccountContract.replace('>accounts<', body) -} - -var userAgent = (typeof (navigator) !== 'undefined') && navigator.userAgent ? navigator.userAgent.toLowerCase() : '-' -var isBrowser = !(typeof (window) === 'undefined' || userAgent.indexOf(' electron/') > -1) - -// TODO: replace this with remix's own compiler code -function compileFileOrFiles (filename, isDirectory, opts, cb) { - let compiler - let accounts = opts.accounts || [] - const sources = { - 'tests.sol': { content: require('../sol/tests.sol.js') }, - 'remix_tests.sol': { content: require('../sol/tests.sol.js') }, - 'remix_accounts.sol': { content: writeTestAccountsContract(accounts) } - } - const filepath = (isDirectory ? filename : path.dirname(filename)) - // TODO: for now assumes filepath dir contains all tests, later all this - // should be replaced with remix's & browser solidity compiler code - - // This logic is wrong - // We should only look into current file if a full file name with path is given - // We should only walk through directory if a directory name is passed - try { - // walkSync only if it is a directory - fs.walkSync(filepath, foundpath => { - // only process .sol files - if (foundpath.split('.').pop() === 'sol') { - let c = fs.readFileSync(foundpath).toString() - const s = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm - let includeTestLibs = '\nimport \'remix_tests.sol\';\n' - if (foundpath.indexOf('_test.sol') > 0 && c.regexIndexOf(s) < 0) { - c = includeTestLibs.concat(c) - } - sources[foundpath] = { content: c } - } - }) - } catch (e) { - throw e - } finally { - async.waterfall([ - function loadCompiler (next) { - compiler = new RemixCompiler() - compiler.onInternalCompilerLoaded() - // compiler.event.register('compilerLoaded', this, function (version) { - next() - // }); - }, - function doCompilation (next) { - compiler.event.register('compilationFinished', this, function (success, data, source) { - next(null, data) - }) - compiler.compile(sources, filepath) - } - ], function (err, result) { - let errors = (result.errors || []).filter((e) => e.type === 'Error' || e.severity === 'error') - if (errors.length > 0) { - if (!isBrowser) require('signale').fatal(errors) - return cb(new Error('errors compiling')) - } - cb(err, result.contracts) - }) - } -} - -function compileContractSources (sources, importFileCb, opts, cb) { - let compiler, filepath - let accounts = opts.accounts || [] - // Iterate over sources keys. Inject test libraries. Inject test library import statements. - if (!('remix_tests.sol' in sources) && !('tests.sol' in sources)) { - sources['remix_tests.sol'] = { content: require('../sol/tests.sol.js') } - sources['remix_accounts.sol'] = { content: writeTestAccountsContract(accounts) } - } - const s = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm - let includeTestLibs = '\nimport \'remix_tests.sol\';\n' - for (let file in sources) { - const c = sources[file].content - if (file.indexOf('_test.sol') > 0 && c && c.regexIndexOf(s) < 0) { - sources[file].content = includeTestLibs.concat(c) - } - } - - async.waterfall([ - function loadCompiler (next) { - compiler = new RemixCompiler(importFileCb) - compiler.onInternalCompilerLoaded() - // compiler.event.register('compilerLoaded', this, function (version) { - next() - // }); - }, - function doCompilation (next) { - compiler.event.register('compilationFinished', this, function (success, data, source) { - next(null, data) - }) - compiler.compile(sources, filepath) - } - ], function (err, result) { - let errors = (result.errors || []).filter((e) => e.type === 'Error' || e.severity === 'error') - if (errors.length > 0) { - if (!isBrowser) require('signale').fatal(errors) - return cb(new Error('errors compiling')) - } - cb(err, result.contracts) - }) -} - -module.exports = { - compileFileOrFiles: compileFileOrFiles, - compileContractSources: compileContractSources -} diff --git a/remix-tests/src/compiler.ts b/remix-tests/src/compiler.ts new file mode 100644 index 0000000000..15d2a62a05 --- /dev/null +++ b/remix-tests/src/compiler.ts @@ -0,0 +1,127 @@ +/* eslint no-extend-native: "warn" */ +let fs = require('../src/fs') +var async = require('async') +var path = require('path') +let RemixCompiler = require('remix-solidity').Compiler + + +function regexIndexOf (inputString, regex, startpos = 0) { + var indexOf = inputString.substring(startpos).search(regex) + return (indexOf >= 0) ? (indexOf + (startpos)) : indexOf +} + +function writeTestAccountsContract (accounts) { + var testAccountContract = require('../sol/tests_accounts.sol.js') + var body = 'address[' + accounts.length + '] memory accounts;' + if (!accounts.length) body += ';' + else { + accounts.map((address, index) => { + body += `\naccounts[${index}] = ${address};\n` + }) + } + return testAccountContract.replace('>accounts<', body) +} + +var userAgent = (typeof (navigator) !== 'undefined') && navigator.userAgent ? navigator.userAgent.toLowerCase() : '-' +var isBrowser = !(typeof (window) === 'undefined' || userAgent.indexOf(' electron/') > -1) + +// TODO: replace this with remix's own compiler code +export function compileFileOrFiles (filename, isDirectory, opts, cb) { + let compiler + let accounts = opts.accounts || [] + const sources = { + 'tests.sol': { content: require('../sol/tests.sol.js') }, + 'remix_tests.sol': { content: require('../sol/tests.sol.js') }, + 'remix_accounts.sol': { content: writeTestAccountsContract(accounts) } + } + const filepath = (isDirectory ? filename : path.dirname(filename)) + // TODO: for now assumes filepath dir contains all tests, later all this + // should be replaced with remix's & browser solidity compiler code + + // This logic is wrong + // We should only look into current file if a full file name with path is given + // We should only walk through directory if a directory name is passed + try { + // walkSync only if it is a directory + fs.walkSync(filepath, foundpath => { + // only process .sol files + if (foundpath.split('.').pop() === 'sol') { + let c = fs.readFileSync(foundpath).toString() + const s = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm + let includeTestLibs = '\nimport \'remix_tests.sol\';\n' + if (foundpath.indexOf('_test.sol') > 0 && regexIndexOf(c, s) < 0) { + c = includeTestLibs.concat(c) + } + sources[foundpath] = { content: c } + } + }) + } catch (e) { + throw e + } finally { + async.waterfall([ + function loadCompiler (next) { + compiler = new RemixCompiler() + compiler.onInternalCompilerLoaded() + // compiler.event.register('compilerLoaded', this, function (version) { + next() + // }); + }, + function doCompilation (next) { + // @ts-ignore + compiler.event.register('compilationFinished', this, function (success, data, source) { + next(null, data) + }) + compiler.compile(sources, filepath) + } + ], function (err, result) { + let errors = (result.errors || []).filter((e) => e.type === 'Error' || e.severity === 'error') + if (errors.length > 0) { + if (!isBrowser) require('signale').fatal(errors) + return cb(new Error('errors compiling')) + } + cb(err, result.contracts) + }) + } +} + +export function compileContractSources (sources, importFileCb, opts, cb) { + let compiler, filepath + let accounts = opts.accounts || [] + // Iterate over sources keys. Inject test libraries. Inject test library import statements. + if (!('remix_tests.sol' in sources) && !('tests.sol' in sources)) { + sources['remix_tests.sol'] = { content: require('../sol/tests.sol.js') } + sources['remix_accounts.sol'] = { content: writeTestAccountsContract(accounts) } + } + const s = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm + let includeTestLibs = '\nimport \'remix_tests.sol\';\n' + for (let file in sources) { + const c = sources[file].content + if (file.indexOf('_test.sol') > 0 && c && regexIndexOf(c, s) < 0) { + sources[file].content = includeTestLibs.concat(c) + } + } + + async.waterfall([ + function loadCompiler (next) { + compiler = new RemixCompiler(importFileCb) + compiler.onInternalCompilerLoaded() + // compiler.event.register('compilerLoaded', this, function (version) { + next() + // }); + }, + function doCompilation (next) { + // @ts-ignore + compiler.event.register('compilationFinished', this, function (success, data, source) { + next(null, data) + }) + compiler.compile(sources, filepath) + } + ], function (err, result) { + let errors = (result.errors || []).filter((e) => e.type === 'Error' || e.severity === 'error') + if (errors.length > 0) { + if (!isBrowser) require('signale').fatal(errors) + return cb(new Error('errors compiling')) + } + cb(err, result.contracts) + }) +} diff --git a/remix-tests/src/deployer.js b/remix-tests/src/deployer.js deleted file mode 100644 index a2bdc0a20e..0000000000 --- a/remix-tests/src/deployer.js +++ /dev/null @@ -1,113 +0,0 @@ -var async = require('async') -var remixLib = require('remix-lib') - -function deployAll (compileResult, web3, callback) { - let compiledObject = {} - let contracts = {} - let accounts = [] - - async.waterfall([ - function getAccountList (next) { - web3.eth.getAccounts((_err, _accounts) => { - accounts = _accounts - next() - }) - }, - function getContractData (next) { - for (let contractFile in compileResult) { - for (let contractName in compileResult[contractFile]) { - let contract = compileResult[contractFile][contractName] - - const className = contractName - const filename = contractFile - - let abi = contract.abi - let code = contract.evm.bytecode.object - - compiledObject[className] = {} - compiledObject[className].abi = abi - compiledObject[className].code = code - compiledObject[className].filename = filename - compiledObject[className].className = className - compiledObject[className].raw = contract - - if (contractFile.indexOf('_test.sol') >= 0) { - compiledObject[className].isTest = true - } - } - } - next() - }, - function determineContractsToDeploy (next) { - let contractsToDeploy = ['Assert'] - let allContracts = Object.keys(compiledObject) - - for (let contractName of allContracts) { - if (contractName === 'Assert') { - continue - } - if (compiledObject[contractName].isTest) { - contractsToDeploy.push(contractName) - } - } - next(null, contractsToDeploy) - }, - function deployContracts (contractsToDeploy, next) { - var deployRunner = (deployObject, contractObject, contractName, filename, callback) => { - deployObject.estimateGas().then((gasValue) => { - deployObject.send({ - from: accounts[0], - gas: Math.ceil(gasValue * 1.2) - }).on('receipt', function (receipt) { - contractObject.options.address = receipt.contractAddress - contractObject.options.from = accounts[0] - contractObject.options.gas = 5000 * 1000 - compiledObject[contractName].deployedAddress = receipt.contractAddress - - contracts[contractName] = contractObject - contracts[contractName].filename = filename - - callback(null, { result: { createdAddress: receipt.contractAddress } }) // TODO this will only work with JavaScriptV VM - }).on('error', function (err) { - console.error(err) - callback(err) - }) - }) - } - - async.eachOfLimit(contractsToDeploy, 1, function (contractName, index, nextEach) { - let contract = compiledObject[contractName] - let encodeDataFinalCallback = (error, contractDeployData) => { - if (error) return nextEach(error) - try { - let contractObject = new web3.eth.Contract(contract.abi) - let deployObject = contractObject.deploy({arguments: [], data: '0x' + contractDeployData.dataHex}) - deployRunner(deployObject, contractObject, contractName, contract.filename, (error) => { nextEach(error) }) - } catch (e) { - throw e - } - } - - let encodeDataStepCallback = (msg) => { console.dir(msg) } - - let encodeDataDeployLibraryCallback = (libData, callback) => { - let abi = compiledObject[libData.data.contractName].abi - let code = compiledObject[libData.data.contractName].code - let libraryObject = new web3.eth.Contract(abi) - let deployObject = libraryObject.deploy({arguments: [], data: '0x' + code}) - deployRunner(deployObject, libraryObject, libData.data.contractName, contract.filename, callback) - } - - let funAbi = null // no need to set the abi for encoding the constructor - let params = '' // we suppose that the test contract does not have any param in the constructor - remixLib.execution.txFormat.encodeConstructorCallAndDeployLibraries(contractName, contract.raw, compileResult, params, funAbi, encodeDataFinalCallback, encodeDataStepCallback, encodeDataDeployLibraryCallback) - }, function () { - next(null, contracts) - }) - } - ], callback) -} - -module.exports = { - deployAll: deployAll -} diff --git a/remix-tests/src/deployer.ts b/remix-tests/src/deployer.ts new file mode 100644 index 0000000000..157926aef6 --- /dev/null +++ b/remix-tests/src/deployer.ts @@ -0,0 +1,109 @@ +var async = require('async') +var remixLib = require('remix-lib') + +export function deployAll (compileResult, web3, callback) { + let compiledObject = {} + let contracts = {} + let accounts = [] + + async.waterfall([ + function getAccountList (next) { + web3.eth.getAccounts((_err, _accounts) => { + accounts = _accounts + next() + }) + }, + function getContractData (next) { + for (let contractFile in compileResult) { + for (let contractName in compileResult[contractFile]) { + let contract = compileResult[contractFile][contractName] + + const className = contractName + const filename = contractFile + + let abi = contract.abi + let code = contract.evm.bytecode.object + + compiledObject[className] = {} + compiledObject[className].abi = abi + compiledObject[className].code = code + compiledObject[className].filename = filename + compiledObject[className].className = className + compiledObject[className].raw = contract + + if (contractFile.indexOf('_test.sol') >= 0) { + compiledObject[className].isTest = true + } + } + } + next() + }, + function determineContractsToDeploy (next) { + let contractsToDeploy = ['Assert'] + let allContracts = Object.keys(compiledObject) + + for (let contractName of allContracts) { + if (contractName === 'Assert') { + continue + } + if (compiledObject[contractName].isTest) { + contractsToDeploy.push(contractName) + } + } + next(null, contractsToDeploy) + }, + function deployContracts (contractsToDeploy, next) { + var deployRunner = (deployObject, contractObject, contractName, filename, callback) => { + deployObject.estimateGas().then((gasValue) => { + deployObject.send({ + from: accounts[0], + gas: Math.ceil(gasValue * 1.2) + }).on('receipt', function (receipt) { + contractObject.options.address = receipt.contractAddress + contractObject.options.from = accounts[0] + contractObject.options.gas = 5000 * 1000 + compiledObject[contractName].deployedAddress = receipt.contractAddress + + contracts[contractName] = contractObject + contracts[contractName].filename = filename + + callback(null, { result: { createdAddress: receipt.contractAddress } }) // TODO this will only work with JavaScriptV VM + }).on('error', function (err) { + console.error(err) + callback(err) + }) + }) + } + + async.eachOfLimit(contractsToDeploy, 1, function (contractName, index, nextEach) { + let contract = compiledObject[contractName] + let encodeDataFinalCallback = (error, contractDeployData) => { + if (error) return nextEach(error) + try { + let contractObject = new web3.eth.Contract(contract.abi) + let deployObject = contractObject.deploy({arguments: [], data: '0x' + contractDeployData.dataHex}) + deployRunner(deployObject, contractObject, contractName, contract.filename, (error) => { nextEach(error) }) + } catch (e) { + throw e + } + } + + let encodeDataStepCallback = (msg) => { console.dir(msg) } + + let encodeDataDeployLibraryCallback = (libData, callback) => { + let abi = compiledObject[libData.data.contractName].abi + let code = compiledObject[libData.data.contractName].code + let libraryObject = new web3.eth.Contract(abi) + let deployObject = libraryObject.deploy({arguments: [], data: '0x' + code}) + deployRunner(deployObject, libraryObject, libData.data.contractName, contract.filename, callback) + } + + let funAbi = null // no need to set the abi for encoding the constructor + let params = '' // we suppose that the test contract does not have any param in the constructor + remixLib.execution.txFormat.encodeConstructorCallAndDeployLibraries(contractName, contract.raw, compileResult, params, funAbi, encodeDataFinalCallback, encodeDataStepCallback, encodeDataDeployLibraryCallback) + }, function () { + next(null, contracts) + }) + } + ], callback) +} diff --git a/remix-tests/src/fs.js b/remix-tests/src/fs.js index fa2dd4dfd7..eafe5339eb 100644 --- a/remix-tests/src/fs.js +++ b/remix-tests/src/fs.js @@ -1,4 +1,5 @@ // Extend fs + var fs = require('fs') const path = require('path') @@ -17,4 +18,4 @@ fs.walkSync = function (start, callback) { }) } -module.exports = fs +module.exports = fs \ No newline at end of file diff --git a/remix-tests/src/logger.js b/remix-tests/src/logger.js deleted file mode 100644 index 6dc6253bf1..0000000000 --- a/remix-tests/src/logger.js +++ /dev/null @@ -1,58 +0,0 @@ -var gray = require('ansi-gray') -const winston = require('winston') -var timestamp = require('time-stamp') -var supportsColor = require('color-support') - -function hasFlag (flag) { - return ((typeof (process) !== 'undefined') && (process.argv.indexOf('--' + flag) !== -1)) -} - -function addColor (str) { - if (hasFlag('no-color')) { - return str - } - - if (hasFlag('color')) { - return gray(str) - } - - if (supportsColor()) { - return gray(str) - } - - return str -} -function getTimestamp () { - return '[' + addColor(timestamp('HH:mm:ss')) + ']' -} -// create winston logger format -const logFmt = winston.format.printf((info) => { - return `${getTimestamp()} ${info.level}: ${info.message}` -}) - -class Log { - constructor () { - this.logger = winston.createLogger({ - level: 'error', - transports: [new winston.transports.Console()], - format: winston.format.combine( - winston.format.colorize({ all: true }), - logFmt - ) - }) - } - setVerbosity (v) { - this.logger.configure({ - level: v, - transports: [new winston.transports.Console()], - format: winston.format.combine( - winston.format.colorize({ all: true }), - logFmt - ) - }) - } -} - -module.exports = { - Log -} diff --git a/remix-tests/src/logger.ts b/remix-tests/src/logger.ts new file mode 100644 index 0000000000..c1e5d13c92 --- /dev/null +++ b/remix-tests/src/logger.ts @@ -0,0 +1,57 @@ +var gray = require('ansi-gray') +const winston = require('winston') +var timestamp = require('time-stamp') +var supportsColor = require('color-support') + +function hasFlag (flag) { + return ((typeof (process) !== 'undefined') && (process.argv.indexOf('--' + flag) !== -1)) +} + +function addColor (str) { + if (hasFlag('no-color')) { + return str + } + + if (hasFlag('color')) { + return gray(str) + } + + if (supportsColor()) { + return gray(str) + } + + return str +} +function getTimestamp () { + return '[' + addColor(timestamp('HH:mm:ss')) + ']' +} +// create winston logger format +const logFmt = winston.format.printf((info) => { + return `${getTimestamp()} ${info.level}: ${info.message}` +}) + +class Log { + logger: any; + constructor () { + this.logger = winston.createLogger({ + level: 'error', + transports: [new winston.transports.Console()], + format: winston.format.combine( + winston.format.colorize({ all: true }), + logFmt + ) + }) + } + setVerbosity (v) { + this.logger.configure({ + level: v, + transports: [new winston.transports.Console()], + format: winston.format.combine( + winston.format.colorize({ all: true }), + logFmt + ) + }) + } +} + +export = Log diff --git a/remix-tests/src/run.js b/remix-tests/src/run.js index e0aefb97f6..31e478dd82 100644 --- a/remix-tests/src/run.js +++ b/remix-tests/src/run.js @@ -3,7 +3,7 @@ const Web3 = require('web3') const RemixTests = require('./index.js') const fs = require('fs') const Provider = require('remix-simulator').Provider -const { Log } = require('./logger.js') +const { Log } = require('./logger') const logger = new Log() const log = logger.logger require('colors') diff --git a/remix-tests/src/runTestFiles.ts b/remix-tests/src/runTestFiles.ts index 50146766be..0b0b7dd7ea 100644 --- a/remix-tests/src/runTestFiles.ts +++ b/remix-tests/src/runTestFiles.ts @@ -4,8 +4,8 @@ import fs = require('./fs') import runTest from './testRunner' require('colors') -import Compiler = require('./compiler.js') -import Deployer = require('./deployer.js') +import Compiler = require('./compiler') +import Deployer = require('./deployer') function runTestFiles(filepath, isDirectory, web3, opts) { opts = opts || {} diff --git a/remix-tests/src/runTestSources.ts b/remix-tests/src/runTestSources.ts index 389f8ce1cb..867b1687c2 100644 --- a/remix-tests/src/runTestSources.ts +++ b/remix-tests/src/runTestSources.ts @@ -34,7 +34,7 @@ function runTestSources(contractSources, testCallback, resultCallback, finalCall }) }, function compile (next) { - Compiler.compileContractSources(contractSources, importFileCb, next) + Compiler.compileContractSources(contractSources, importFileCb, opts, next) }, function deployAllContracts (compilationResult, next) { Deployer.deployAll(compilationResult, web3, function (err, contracts) { diff --git a/remix-tests/tests/testRunner.ts b/remix-tests/tests/testRunner.ts index 3cf18875eb..129d719b3e 100644 --- a/remix-tests/tests/testRunner.ts +++ b/remix-tests/tests/testRunner.ts @@ -3,8 +3,8 @@ import Web3 from 'web3' import * as assert from 'assert' import { Provider } from 'remix-simulator' -let Compiler = require('../src/compiler.js') -let Deployer = require('../src/deployer.js') +let Compiler = require('../dist/compiler.js') +let Deployer = require('../dist/deployer.js') import runTest, { ResultsInterface, TestCbInterface, ResultCbInterface } from '../dist/testRunner.js' function compileAndDeploy(filename: string, callback: Function) {