compiler, deployer, logger migrated to ts

pull/5370/head
Sab94 6 years ago
parent 2d55e3398b
commit 9a54458f3a
  1. 129
      remix-tests/src/compiler.js
  2. 127
      remix-tests/src/compiler.ts
  3. 113
      remix-tests/src/deployer.js
  4. 109
      remix-tests/src/deployer.ts
  5. 3
      remix-tests/src/fs.js
  6. 58
      remix-tests/src/logger.js
  7. 57
      remix-tests/src/logger.ts
  8. 2
      remix-tests/src/run.js
  9. 4
      remix-tests/src/runTestFiles.ts
  10. 2
      remix-tests/src/runTestSources.ts
  11. 4
      remix-tests/tests/testRunner.ts

@ -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
}

@ -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)
})
}

@ -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
}

@ -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)
}

@ -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

@ -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
}

@ -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

@ -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')

@ -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 || {}

@ -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) {

@ -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) {

Loading…
Cancel
Save