Merge pull request #1128 from 0mkara/remix-tests-ts
Remix Tests Typescript implementationpull/7/head
commit
af9aae696e
@ -1,4 +1,4 @@ |
||||
#!/usr/bin/env node |
||||
|
||||
require('../src/run.js'); |
||||
require('../dist/run.js'); |
||||
|
||||
|
@ -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) { // eslint-disable-line
|
||||
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,126 @@ |
||||
import fs from './fileSystem' |
||||
import async from 'async' |
||||
import path from 'path' |
||||
let RemixCompiler = require('remix-solidity').Compiler |
||||
import { SrcIfc } from './types' |
||||
|
||||
function regexIndexOf (inputString: string, regex: RegExp, startpos: number = 0) { |
||||
const indexOf = inputString.substring(startpos).search(regex) |
||||
return (indexOf >= 0) ? (indexOf + (startpos)) : indexOf |
||||
} |
||||
|
||||
function writeTestAccountsContract (accounts: string[]) { |
||||
const testAccountContract = require('../sol/tests_accounts.sol.js') |
||||
let 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) |
||||
} |
||||
|
||||
const userAgent = (typeof (navigator) !== 'undefined') && navigator.userAgent ? navigator.userAgent.toLowerCase() : '-' |
||||
const isBrowser = !(typeof (window) === 'undefined' || userAgent.indexOf(' electron/') > -1) |
||||
|
||||
// TODO: replace this with remix's own compiler code
|
||||
export function compileFileOrFiles(filename: string, isDirectory: boolean, opts: any, cb: Function) { |
||||
let compiler: any |
||||
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: string) => { |
||||
// 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: Function) { |
||||
compiler = new RemixCompiler() |
||||
compiler.onInternalCompilerLoaded() |
||||
// compiler.event.register('compilerLoaded', this, function (version) {
|
||||
next() |
||||
// });
|
||||
}, |
||||
function doCompilation(next: Function) { |
||||
// @ts-ignore
|
||||
compiler.event.register('compilationFinished', this, (success, data, source) => { |
||||
next(null, data) |
||||
}) |
||||
compiler.compile(sources, filepath) |
||||
} |
||||
], function (err: Error | null | undefined, result: any) { |
||||
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: SrcIfc, importFileCb: any, opts: any, cb: Function) { |
||||
let compiler, filepath: string |
||||
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: Function) { |
||||
compiler = new RemixCompiler(importFileCb) |
||||
compiler.onInternalCompilerLoaded() |
||||
// compiler.event.register('compilerLoaded', this, function (version) {
|
||||
next() |
||||
// });
|
||||
}, |
||||
function doCompilation (next: Function) { |
||||
// @ts-ignore
|
||||
compiler.event.register('compilationFinished', this, (success, data, source) => { |
||||
next(null, data) |
||||
}) |
||||
compiler.compile(sources, filepath) |
||||
} |
||||
], function (err: Error | null | undefined , result: any) { |
||||
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,109 +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.dir(err) |
||||
callback(err) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
async.eachOfLimit(contractsToDeploy, 1, function (contractName, index, nextEach) { |
||||
let contract = compiledObject[contractName] |
||||
let encodeDataFinalCallback = (error, contractDeployData) => { |
||||
if (error) return nextEach(error) |
||||
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) }) |
||||
} |
||||
|
||||
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,110 @@ |
||||
import async from 'async' |
||||
var remixLib = require('remix-lib') |
||||
import Web3 from 'web3' |
||||
|
||||
export function deployAll(compileResult: object, web3: Web3, callback) { |
||||
let compiledObject = {} |
||||
let contracts = {} |
||||
let accounts: string[] = [] |
||||
|
||||
async.waterfall([ |
||||
function getAccountList(next: Function) { |
||||
web3.eth.getAccounts((_err, _accounts) => { |
||||
accounts = _accounts |
||||
next() |
||||
}) |
||||
}, |
||||
function getContractData(next: Function) { |
||||
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: Function) { |
||||
let contractsToDeploy: string[] = ['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: string[], next: Function) { |
||||
const 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) |
||||
} |
@ -0,0 +1,20 @@ |
||||
// Extend fs
|
||||
let fs: any = require('fs') |
||||
import path from 'path' |
||||
|
||||
// https://github.com/mikeal/node-utils/blob/master/file/lib/main.js
|
||||
fs.walkSync = function (start: string, callback: Function) { |
||||
fs.readdirSync(start).forEach((name: string) => { |
||||
if (name === 'node_modules') { |
||||
return // hack
|
||||
} |
||||
const abspath = path.join(start, name) |
||||
if (fs.statSync(abspath).isDirectory()) { |
||||
fs.walkSync(abspath, callback) |
||||
} else { |
||||
callback(abspath) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
export = fs |
@ -1,20 +0,0 @@ |
||||
// Extend fs
|
||||
var fs = require('fs') |
||||
const path = require('path') |
||||
|
||||
// https://github.com/mikeal/node-utils/blob/master/file/lib/main.js
|
||||
fs.walkSync = function (start, callback) { |
||||
fs.readdirSync(start).forEach(name => { |
||||
if (name === 'node_modules') { |
||||
return // hack
|
||||
} |
||||
var abspath = path.join(start, name) |
||||
if (fs.statSync(abspath).isDirectory()) { |
||||
fs.walkSync(abspath, callback) |
||||
} else { |
||||
callback(abspath) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
module.exports = fs |
@ -1,10 +0,0 @@ |
||||
const runTestFiles = require('./runTestFiles.js') |
||||
const runTestSources = require('./runTestSources.js') |
||||
const TestRunner = require('./testRunner.js') |
||||
|
||||
module.exports = { |
||||
runTestFiles: runTestFiles, |
||||
runTestSources: runTestSources, |
||||
runTest: TestRunner.runTest, |
||||
assertLibCode: require('../sol/tests.sol.js') |
||||
} |
@ -0,0 +1,5 @@ |
||||
export { runTestFiles } from './runTestFiles' |
||||
export { runTestSources } from './runTestSources' |
||||
export { runTest } from './testRunner' |
||||
export * from './types' |
||||
export { assertLibCode } from '../sol/tests.sol.js' |
@ -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 @@ |
||||
import colors from 'colors' |
||||
import winston, { Logger, LoggerOptions } from 'winston' |
||||
import timestamp from 'time-stamp'; |
||||
import supportsColor from 'color-support' |
||||
|
||||
function hasFlag (flag: string) { |
||||
return ((typeof (process) !== 'undefined') && (process.argv.indexOf('--' + flag) !== -1)) |
||||
} |
||||
|
||||
function addColor (str: string) { |
||||
if (hasFlag('no-color')) { |
||||
return str |
||||
} |
||||
|
||||
if (hasFlag('color')) { |
||||
return colors.gray(str) |
||||
} |
||||
|
||||
if (supportsColor()) { |
||||
return colors.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: Logger; |
||||
constructor () { |
||||
this.logger = winston.createLogger({ |
||||
level: 'error', |
||||
transports: [new winston.transports.Console()], |
||||
format: winston.format.combine( |
||||
winston.format.colorize({ all: true }), |
||||
logFmt |
||||
) |
||||
}) |
||||
} |
||||
setVerbosity (v: LoggerOptions["level"]) { |
||||
this.logger.configure({ |
||||
level: v, |
||||
transports: [new winston.transports.Console()], |
||||
format: winston.format.combine( |
||||
winston.format.colorize({ all: true }), |
||||
logFmt |
||||
) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
export = Log |
@ -1,65 +0,0 @@ |
||||
const commander = require('commander') |
||||
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 logger = new Log() |
||||
const log = logger.logger |
||||
require('colors') |
||||
|
||||
// parse verbosity
|
||||
function mapVerbosity (v) { |
||||
const levels = { |
||||
0: 'error', |
||||
1: 'warn', |
||||
2: 'info', |
||||
3: 'verbose', |
||||
4: 'debug', |
||||
5: 'silly' |
||||
} |
||||
return levels[v] |
||||
} |
||||
const version = require('../package.json').version |
||||
|
||||
commander.version(version) |
||||
|
||||
commander.command('version').description('output the version number').action(function () { |
||||
console.log(version) |
||||
}) |
||||
|
||||
commander.command('help').description('output usage information').action(function () { |
||||
commander.help() |
||||
}) |
||||
|
||||
// get current version
|
||||
commander |
||||
.option('-v, --verbose <level>', 'run with verbosity', mapVerbosity) |
||||
.action(function (filename) { |
||||
// Console message
|
||||
console.log(('\n\t👁 :: Running remix-tests - Unit testing for solidity :: 👁\t\n').white) |
||||
// set logger verbosity
|
||||
if (commander.verbose) { |
||||
logger.setVerbosity(commander.verbose) |
||||
log.info('verbosity level set to ' + commander.verbose.blue) |
||||
} |
||||
let web3 = new Web3() |
||||
// web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'))
|
||||
web3.setProvider(new Provider()) |
||||
// web3.setProvider(new web3.providers.WebsocketProvider('ws://localhost:8546'))
|
||||
|
||||
if (!fs.existsSync(filename)) { |
||||
console.error(filename + ' not found') |
||||
process.exit(1) |
||||
} |
||||
|
||||
let isDirectory = fs.lstatSync(filename).isDirectory() |
||||
RemixTests.runTestFiles(filename, isDirectory, web3) |
||||
}) |
||||
|
||||
if (!process.argv.slice(2).length) { |
||||
log.error('Please specify a filename') |
||||
process.exit() |
||||
} |
||||
|
||||
commander.parse(process.argv) |
@ -0,0 +1,65 @@ |
||||
import commander from 'commander' |
||||
import Web3 from 'web3' |
||||
import { runTestFiles } from './runTestFiles' |
||||
import fs from './fileSystem' |
||||
import { Provider } from 'remix-simulator' |
||||
import Log from './logger' |
||||
const logger = new Log() |
||||
const log = logger.logger |
||||
import colors from 'colors' |
||||
|
||||
// parse verbosity
|
||||
function mapVerbosity (v: number) { |
||||
const levels = { |
||||
0: 'error', |
||||
1: 'warn', |
||||
2: 'info', |
||||
3: 'verbose', |
||||
4: 'debug', |
||||
5: 'silly' |
||||
} |
||||
return levels[v] |
||||
} |
||||
const version = require('../package.json').version |
||||
|
||||
commander.version(version) |
||||
|
||||
commander.command('version').description('output the version number').action(function () { |
||||
console.log(version) |
||||
}) |
||||
|
||||
commander.command('help').description('output usage information').action(function () { |
||||
commander.help() |
||||
}) |
||||
|
||||
// get current version
|
||||
commander |
||||
.option('-v, --verbose <level>', 'run with verbosity', mapVerbosity) |
||||
.action((filename) => { |
||||
// Console message
|
||||
console.log(colors.white('\n\t👁\t:: Running remix-tests - Unit testing for solidity ::\t👁\n')) |
||||
// set logger verbosity
|
||||
if (commander.verbose) { |
||||
logger.setVerbosity(commander.verbose) |
||||
log.info('verbosity level set to ' + commander.verbose.blue) |
||||
} |
||||
let web3 = new Web3() |
||||
// web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'))
|
||||
web3.setProvider(new Provider()) |
||||
// web3.setProvider(new web3.providers.WebsocketProvider('ws://localhost:8546'))
|
||||
|
||||
if (!fs.existsSync(filename)) { |
||||
console.error(filename + ' not found') |
||||
process.exit(1) |
||||
} |
||||
|
||||
let isDirectory = fs.lstatSync(filename).isDirectory() |
||||
runTestFiles(filename, isDirectory, web3) |
||||
}) |
||||
|
||||
if (!process.argv.slice(2).length) { |
||||
log.error('Please specify a filename') |
||||
process.exit() |
||||
} |
||||
|
||||
commander.parse(process.argv) |
@ -1,133 +0,0 @@ |
||||
const async = require('async') |
||||
const path = require('path') |
||||
const fs = require('./fs') |
||||
const TestRunner = require('./testRunner.js') |
||||
require('colors') |
||||
|
||||
let Compiler = require('./compiler.js') |
||||
let Deployer = require('./deployer.js') |
||||
|
||||
const runTestFiles = function (filepath, isDirectory, web3, opts) { |
||||
opts = opts || {} |
||||
const { Signale } = require('signale') |
||||
// signale configuration
|
||||
const options = { |
||||
types: { |
||||
result: { |
||||
badge: '\t✓', |
||||
label: '', |
||||
color: 'greenBright' |
||||
}, |
||||
name: { |
||||
badge: '\n\t◼', |
||||
label: '', |
||||
color: 'white' |
||||
}, |
||||
error: { |
||||
badge: '\t✘', |
||||
label: '', |
||||
color: 'redBright' |
||||
} |
||||
} |
||||
} |
||||
const signale = new Signale(options) |
||||
let accounts = opts.accounts || null |
||||
async.waterfall([ |
||||
function getAccountList (next) { |
||||
if (accounts) return next(null) |
||||
web3.eth.getAccounts((_err, _accounts) => { |
||||
accounts = _accounts |
||||
next(null) |
||||
}) |
||||
}, |
||||
function compile (next) { |
||||
Compiler.compileFileOrFiles(filepath, isDirectory, { accounts }, next) |
||||
}, |
||||
function deployAllContracts (compilationResult, next) { |
||||
Deployer.deployAll(compilationResult, web3, function (err, contracts) { |
||||
if (err) { |
||||
next(err) |
||||
} |
||||
next(null, compilationResult, contracts) |
||||
}) |
||||
}, |
||||
function determineTestContractsToRun (compilationResult, contracts, next) { |
||||
let contractsToTest = [] |
||||
let contractsToTestDetails = [] |
||||
const gatherContractsFrom = (filename) => { |
||||
if (filename.indexOf('_test.sol') < 0) { |
||||
return |
||||
} |
||||
Object.keys(compilationResult[path.basename(filename)]).forEach(contractName => { |
||||
contractsToTest.push(contractName) |
||||
contractsToTestDetails.push(compilationResult[path.basename(filename)][contractName]) |
||||
}) |
||||
} |
||||
if (isDirectory) { |
||||
fs.walkSync(filepath, foundpath => { |
||||
gatherContractsFrom(foundpath) |
||||
}) |
||||
} else { |
||||
gatherContractsFrom(filepath) |
||||
} |
||||
next(null, contractsToTest, contractsToTestDetails, contracts) |
||||
}, |
||||
function runTests (contractsToTest, contractsToTestDetails, contracts, next) { |
||||
let totalPassing = 0 |
||||
let totalFailing = 0 |
||||
let totalTime = 0 |
||||
let errors = [] |
||||
|
||||
var testCallback = function (result) { |
||||
if (result.type === 'contract') { |
||||
signale.name(result.value.white) |
||||
} else if (result.type === 'testPass') { |
||||
signale.result(result.value) |
||||
} else if (result.type === 'testFailure') { |
||||
signale.result(result.value.red) |
||||
errors.push(result) |
||||
} |
||||
} |
||||
var resultsCallback = function (_err, result, cb) { |
||||
totalPassing += result.passingNum |
||||
totalFailing += result.failureNum |
||||
totalTime += result.timePassed |
||||
cb() |
||||
} |
||||
|
||||
async.eachOfLimit(contractsToTest, 1, (contractName, index, cb) => { |
||||
TestRunner.runTest(contractName, contracts[contractName], contractsToTestDetails[index], { accounts }, testCallback, (err, result) => { |
||||
if (err) { |
||||
return cb(err) |
||||
} |
||||
resultsCallback(null, result, cb) |
||||
}) |
||||
}, function (err, _results) { |
||||
if (err) { |
||||
return next(err) |
||||
} |
||||
|
||||
console.log('\n') |
||||
if (totalPassing > 0) { |
||||
console.log((' ' + totalPassing + ' passing ').green + ('(' + totalTime + 's)').grey) |
||||
} |
||||
if (totalFailing > 0) { |
||||
console.log((' ' + totalFailing + ' failing').red) |
||||
} |
||||
console.log('') |
||||
|
||||
errors.forEach((error, index) => { |
||||
console.log(' ' + (index + 1) + ') ' + error.context + ' ' + error.value) |
||||
console.log('') |
||||
console.log(('\t error: ' + error.errMsg).red) |
||||
}) |
||||
console.log('') |
||||
|
||||
next() |
||||
}) |
||||
} |
||||
], function () { |
||||
}) |
||||
} |
||||
|
||||
module.exports = runTestFiles |
@ -0,0 +1,142 @@ |
||||
import async from 'async' |
||||
import fs from './fileSystem' |
||||
import { runTest } from './testRunner' |
||||
import { TestResultInterface, ResultsInterface } from './types' |
||||
import colors from 'colors' |
||||
import Web3 from 'web3' |
||||
|
||||
import { compileFileOrFiles } from './compiler' |
||||
import { deployAll } from './deployer' |
||||
|
||||
export function runTestFiles(filepath: string, isDirectory: boolean, web3: Web3, opts?: object) { |
||||
opts = opts || {} |
||||
const { Signale } = require('signale') |
||||
// signale configuration
|
||||
const options = { |
||||
types: { |
||||
result: { |
||||
badge: '\t✓', |
||||
label: '', |
||||
color: 'greenBright' |
||||
}, |
||||
name: { |
||||
badge: '\n\t◼', |
||||
label: '', |
||||
color: 'white' |
||||
}, |
||||
error: { |
||||
badge: '\t✘', |
||||
label: '', |
||||
color: 'redBright' |
||||
} |
||||
} |
||||
} |
||||
const signale = new Signale(options) |
||||
let accounts = opts['accounts'] || null |
||||
async.waterfall([ |
||||
function getAccountList (next: Function) { |
||||
if (accounts) return next(null) |
||||
web3.eth.getAccounts((_err: Error | null | undefined, _accounts) => { |
||||
accounts = _accounts |
||||
next(null) |
||||
}) |
||||
}, |
||||
function compile(next: Function) { |
||||
compileFileOrFiles(filepath, isDirectory, { accounts }, next) |
||||
}, |
||||
function deployAllContracts (compilationResult, next: Function) { |
||||
deployAll(compilationResult, web3, (err, contracts) => { |
||||
if (err) { |
||||
next(err) |
||||
} |
||||
next(null, compilationResult, contracts) |
||||
}) |
||||
}, |
||||
function determineTestContractsToRun (compilationResult, contracts, next: Function) { |
||||
let contractsToTest: any[] = [] |
||||
let contractsToTestDetails: any[] = [] |
||||
const gatherContractsFrom = function(filename: string) { |
||||
if (filename.indexOf('_test.sol') < 0) { |
||||
return |
||||
} |
||||
try { |
||||
Object.keys(compilationResult[filename]).forEach(contractName => { |
||||
contractsToTest.push(contractName) |
||||
contractsToTestDetails.push(compilationResult[filename][contractName]) |
||||
}) |
||||
} catch (e) { |
||||
console.error(e) |
||||
} |
||||
} |
||||
if (isDirectory) { |
||||
fs.walkSync(filepath, (foundpath: string) => { |
||||
gatherContractsFrom(foundpath) |
||||
}) |
||||
} else { |
||||
gatherContractsFrom(filepath) |
||||
} |
||||
next(null, contractsToTest, contractsToTestDetails, contracts) |
||||
}, |
||||
function runTests(contractsToTest, contractsToTestDetails, contracts, next: Function) { |
||||
let totalPassing: number = 0 |
||||
let totalFailing: number = 0 |
||||
let totalTime: number = 0 |
||||
let errors: any[] = [] |
||||
|
||||
const _testCallback = function (err: Error | null | undefined, result: TestResultInterface) { |
||||
if(err) throw err; |
||||
if (result.type === 'contract') { |
||||
signale.name(result.value.white) |
||||
} else if (result.type === 'testPass') { |
||||
signale.result(result.value) |
||||
} else if (result.type === 'testFailure') { |
||||
signale.result(result.value.red) |
||||
errors.push(result) |
||||
} |
||||
} |
||||
const _resultsCallback = (_err: Error | null | undefined, result: ResultsInterface, cb) => { |
||||
totalPassing += result.passingNum |
||||
totalFailing += result.failureNum |
||||
totalTime += result.timePassed |
||||
cb() |
||||
} |
||||
|
||||
async.eachOfLimit(contractsToTest, 1, (contractName: string, index, cb) => { |
||||
try { |
||||
runTest(contractName, contracts[contractName], contractsToTestDetails[index], { accounts }, _testCallback, (err, result) => { |
||||
if (err) { |
||||
console.log(err) |
||||
return cb(err) |
||||
} |
||||
_resultsCallback(null, result, cb) |
||||
}) |
||||
} catch(e) { |
||||
console.error(e) |
||||
} |
||||
}, function (err) { |
||||
if (err) { |
||||
return next(err) |
||||
} |
||||
|
||||
console.log('\n') |
||||
if (totalPassing > 0) { |
||||
console.log(colors.green(totalPassing + ' passing ') + colors.grey('(' + totalTime + 's)')) |
||||
} |
||||
if (totalFailing > 0) { |
||||
console.log(colors.red(totalFailing + ' failing')) |
||||
} |
||||
console.log('') |
||||
|
||||
errors.forEach((error, index) => { |
||||
console.log(' ' + (index + 1) + ') ' + error.context + ' ' + error.value) |
||||
console.log('') |
||||
console.log(colors.red('\t error: ' + error.errMsg)) |
||||
}) |
||||
console.log('') |
||||
|
||||
next() |
||||
}) |
||||
} |
||||
], () => { |
||||
}) |
||||
} |
@ -1,107 +0,0 @@ |
||||
const async = require('async') |
||||
require('colors') |
||||
|
||||
let Compiler = require('./compiler.js') |
||||
let Deployer = require('./deployer.js') |
||||
let TestRunner = require('./testRunner.js') |
||||
|
||||
const Web3 = require('web3') |
||||
const Provider = require('remix-simulator').Provider |
||||
|
||||
var createWeb3Provider = function () { |
||||
let web3 = new Web3() |
||||
web3.setProvider(new Provider()) |
||||
return web3 |
||||
} |
||||
|
||||
const runTestSources = function (contractSources, testCallback, resultCallback, finalCallback, importFileCb, opts) { |
||||
opts = opts || {} |
||||
let web3 = opts.web3 || createWeb3Provider() |
||||
let accounts = opts.accounts || null |
||||
async.waterfall([ |
||||
function getAccountList (next) { |
||||
if (accounts) return next() |
||||
web3.eth.getAccounts((_err, _accounts) => { |
||||
accounts = _accounts |
||||
next() |
||||
}) |
||||
}, |
||||
function compile (next) { |
||||
Compiler.compileContractSources(contractSources, importFileCb, next) |
||||
}, |
||||
function deployAllContracts (compilationResult, next) { |
||||
Deployer.deployAll(compilationResult, web3, function (err, contracts) { |
||||
if (err) { |
||||
next(err) |
||||
} |
||||
|
||||
next(null, compilationResult, contracts) |
||||
}) |
||||
}, |
||||
function determineTestContractsToRun (compilationResult, contracts, next) { |
||||
let contractsToTest = [] |
||||
let contractsToTestDetails = [] |
||||
|
||||
for (let filename in compilationResult) { |
||||
if (filename.indexOf('_test.sol') < 0) { |
||||
continue |
||||
} |
||||
Object.keys(compilationResult[filename]).forEach(contractName => { |
||||
contractsToTestDetails.push(compilationResult[filename][contractName]) |
||||
contractsToTest.push(contractName) |
||||
}) |
||||
} |
||||
|
||||
next(null, contractsToTest, contractsToTestDetails, contracts) |
||||
}, |
||||
function runTests (contractsToTest, contractsToTestDetails, contracts, next) { |
||||
let totalPassing = 0 |
||||
let totalFailing = 0 |
||||
let totalTime = 0 |
||||
let errors = [] |
||||
|
||||
var _testCallback = function (result) { |
||||
if (result.type === 'testFailure') { |
||||
errors.push(result) |
||||
} |
||||
testCallback(result) |
||||
} |
||||
|
||||
var _resultsCallback = function (_err, result, cb) { |
||||
resultCallback(_err, result, () => {}) |
||||
totalPassing += result.passingNum |
||||
totalFailing += result.failureNum |
||||
totalTime += result.timePassed |
||||
cb() |
||||
} |
||||
|
||||
async.eachOfLimit(contractsToTest, 1, (contractName, index, cb) => { |
||||
TestRunner.runTest(contractName, contracts[contractName], contractsToTestDetails[index], { accounts }, _testCallback, (err, result) => { |
||||
if (err) { |
||||
return cb(err) |
||||
} |
||||
_resultsCallback(null, result, cb) |
||||
}) |
||||
}, function (err, _results) { |
||||
if (err) { |
||||
return next(err) |
||||
} |
||||
|
||||
let finalResults = {} |
||||
|
||||
finalResults.totalPassing = totalPassing || 0 |
||||
finalResults.totalFailing = totalFailing || 0 |
||||
finalResults.totalTime = totalTime || 0 |
||||
finalResults.errors = [] |
||||
|
||||
errors.forEach((error, _index) => { |
||||
finalResults.errors.push({context: error.context, value: error.value, message: error.errMsg}) |
||||
}) |
||||
|
||||
next(null, finalResults) |
||||
}) |
||||
} |
||||
], finalCallback) |
||||
} |
||||
|
||||
module.exports = runTestSources |
@ -0,0 +1,110 @@ |
||||
import async from 'async' |
||||
require('colors') |
||||
|
||||
import { compileContractSources } from './compiler' |
||||
import { deployAll } from './deployer' |
||||
import { runTest } from './testRunner' |
||||
|
||||
import Web3 = require('web3') |
||||
import Provider from 'remix-simulator' |
||||
import { FinalResult } from './types' |
||||
|
||||
const createWeb3Provider = function () { |
||||
let web3 = new Web3() |
||||
web3.setProvider(new Provider()) |
||||
return web3 |
||||
} |
||||
|
||||
export function runTestSources(contractSources, testCallback, resultCallback, finalCallback, importFileCb, opts) { |
||||
opts = opts || {} |
||||
let web3 = opts.web3 || createWeb3Provider() |
||||
let accounts = opts.accounts || null |
||||
async.waterfall([ |
||||
function getAccountList (next) { |
||||
if (accounts) return next() |
||||
web3.eth.getAccounts((_err, _accounts) => { |
||||
accounts = _accounts |
||||
next() |
||||
}) |
||||
}, |
||||
function compile (next) { |
||||
compileContractSources(contractSources, importFileCb, opts, next) |
||||
}, |
||||
function deployAllContracts (compilationResult, next) { |
||||
deployAll(compilationResult, web3, (err, contracts) => { |
||||
if (err) { |
||||
next(err) |
||||
} |
||||
|
||||
next(null, compilationResult, contracts) |
||||
}) |
||||
}, |
||||
function determineTestContractsToRun (compilationResult, contracts, next) { |
||||
let contractsToTest: any[] = [] |
||||
let contractsToTestDetails: any[] = [] |
||||
|
||||
for (let filename in compilationResult) { |
||||
if (filename.indexOf('_test.sol') < 0) { |
||||
continue |
||||
} |
||||
Object.keys(compilationResult[filename]).forEach(contractName => { |
||||
contractsToTestDetails.push(compilationResult[filename][contractName]) |
||||
contractsToTest.push(contractName) |
||||
}) |
||||
} |
||||
next(null, contractsToTest, contractsToTestDetails, contracts) |
||||
}, |
||||
function runTests(contractsToTest, contractsToTestDetails, contracts, next) { |
||||
let totalPassing = 0 |
||||
let totalFailing = 0 |
||||
let totalTime = 0 |
||||
let errors: any[] = [] |
||||
|
||||
const _testCallback = function (result) { |
||||
if (result.type === 'testFailure') { |
||||
errors.push(result) |
||||
} |
||||
testCallback(result) |
||||
} |
||||
|
||||
const _resultsCallback = function (_err, result, cb) { |
||||
resultCallback(_err, result, () => {}) |
||||
totalPassing += result.passingNum |
||||
totalFailing += result.failureNum |
||||
totalTime += result.timePassed |
||||
cb() |
||||
} |
||||
|
||||
async.eachOfLimit(contractsToTest, 1, (contractName, index, cb) => { |
||||
runTest(contractName, contracts(contractName), contractsToTestDetails[index], { accounts }, _testCallback, (err, result) => { |
||||
if (err) { |
||||
return cb(err) |
||||
} |
||||
_resultsCallback(null, result, cb) |
||||
}) |
||||
}, function (err) { |
||||
if (err) { |
||||
return next(err) |
||||
} |
||||
|
||||
let finalResults: FinalResult = { |
||||
totalPassing: 0, |
||||
totalFailing: 0, |
||||
totalTime: 0, |
||||
errors: [], |
||||
} |
||||
|
||||
finalResults.totalPassing = totalPassing || 0 |
||||
finalResults.totalFailing = totalFailing || 0 |
||||
finalResults.totalTime = totalTime || 0 |
||||
finalResults.errors = [] |
||||
|
||||
errors.forEach((error, _index) => { |
||||
finalResults.errors.push({context: error.context, value: error.value, message: error.errMsg}) |
||||
}) |
||||
|
||||
next(null, finalResults) |
||||
}) |
||||
} |
||||
], finalCallback) |
||||
} |
@ -1,149 +0,0 @@ |
||||
var async = require('async') |
||||
var changeCase = require('change-case') |
||||
var Web3 = require('web3') |
||||
|
||||
function getFunctionFullName (signature, methodIdentifiers) { |
||||
for (var method in methodIdentifiers) { |
||||
if (signature.replace('0x', '') === methodIdentifiers[method].replace('0x', '')) { |
||||
return method |
||||
} |
||||
} |
||||
return null |
||||
} |
||||
|
||||
function getOverridedSender (userdoc, signature, methodIdentifiers) { |
||||
let fullName = getFunctionFullName(signature, methodIdentifiers) |
||||
let match = /sender: account-+(\d)/g |
||||
let accountIndex = userdoc.methods[fullName] ? match.exec(userdoc.methods[fullName].notice) : null |
||||
return fullName && accountIndex ? accountIndex[1] : null |
||||
} |
||||
|
||||
function getAvailableFunctions (jsonInterface) { |
||||
return jsonInterface.reverse().filter((x) => x.type === 'function').map((x) => x.name) |
||||
} |
||||
|
||||
function getTestFunctions (jsonInterface) { |
||||
let specialFunctions = ['beforeAll', 'beforeEach', 'afterAll', 'afterEach'] |
||||
return jsonInterface.filter((x) => specialFunctions.indexOf(x.name) < 0 && x.type === 'function') |
||||
} |
||||
|
||||
function createRunList (jsonInterface) { |
||||
let availableFunctions = getAvailableFunctions(jsonInterface) |
||||
let testFunctions = getTestFunctions(jsonInterface) |
||||
let runList = [] |
||||
|
||||
if (availableFunctions.indexOf('beforeAll') >= 0) { |
||||
runList.push({name: 'beforeAll', type: 'internal', constant: false}) |
||||
} |
||||
|
||||
for (let func of testFunctions) { |
||||
if (availableFunctions.indexOf('beforeEach') >= 0) { |
||||
runList.push({name: 'beforeEach', type: 'internal', constant: false}) |
||||
} |
||||
runList.push({name: func.name, signature: func.signature, type: 'test', constant: func.constant}) |
||||
if (availableFunctions.indexOf('afterEach') >= 0) { |
||||
runList.push({name: 'afterEach', type: 'internal', constant: false}) |
||||
} |
||||
} |
||||
|
||||
if (availableFunctions.indexOf('afterAll') >= 0) { |
||||
runList.push({name: 'afterAll', type: 'internal', constant: false}) |
||||
} |
||||
|
||||
return runList |
||||
} |
||||
|
||||
function runTest (testName, testObject, contractDetails, opts, testCallback, resultsCallback) { |
||||
let runList = createRunList(testObject._jsonInterface) |
||||
|
||||
let passingNum = 0 |
||||
let failureNum = 0 |
||||
let timePassed = 0 |
||||
let web3 = new Web3() |
||||
|
||||
var userAgent = (typeof (navigator) !== 'undefined') && navigator.userAgent ? navigator.userAgent.toLowerCase() : '-' |
||||
var isBrowser = !(typeof (window) === 'undefined' || userAgent.indexOf(' electron/') > -1) |
||||
if (!isBrowser) { |
||||
let signale = require('signale') |
||||
signale.warn('DO NOT TRY TO ACCESS (IN YOUR SOLIDITY TEST) AN ACCOUNT GREATER THAN THE LENGTH OF THE FOLLOWING ARRAY (' + opts.accounts.length + ') :') |
||||
signale.warn(opts.accounts) |
||||
signale.warn('e.g: the following code won\'t work in the current context:') |
||||
signale.warn('TestsAccounts.getAccount(' + opts.accounts.length + ')') |
||||
} |
||||
|
||||
testCallback({type: 'contract', value: testName, filename: testObject.filename}) |
||||
async.eachOfLimit(runList, 1, function (func, index, next) { |
||||
let sender |
||||
if (func.signature) { |
||||
sender = getOverridedSender(contractDetails.userdoc, func.signature, contractDetails.evm.methodIdentifiers) |
||||
if (opts.accounts) { |
||||
sender = opts.accounts[sender] |
||||
} |
||||
} |
||||
let sendParams |
||||
if (sender) sendParams = { from: sender } |
||||
|
||||
let method = testObject.methods[func.name].apply(testObject.methods[func.name], []) |
||||
let startTime = Date.now() |
||||
if (func.constant) { |
||||
method.call(sendParams).then((result) => { |
||||
let time = Math.ceil((Date.now() - startTime) / 1000.0) |
||||
if (result) { |
||||
testCallback({type: 'testPass', value: changeCase.sentenceCase(func.name), time: time, context: testName}) |
||||
passingNum += 1 |
||||
timePassed += time |
||||
} else { |
||||
testCallback({type: 'testFailure', value: changeCase.sentenceCase(func.name), time: time, errMsg: 'function returned false', context: testName}) |
||||
failureNum += 1 |
||||
} |
||||
next() |
||||
}) |
||||
} else { |
||||
method.send(sendParams).on('receipt', function (receipt) { |
||||
try { |
||||
let time = Math.ceil((Date.now() - startTime) / 1000.0) |
||||
let topic = Web3.utils.sha3('AssertionEvent(bool,string)') |
||||
|
||||
let testPassed = false |
||||
|
||||
for (let i in receipt.events) { |
||||
let event = receipt.events[i] |
||||
if (event.raw.topics.indexOf(topic) >= 0) { |
||||
var testEvent = web3.eth.abi.decodeParameters(['bool', 'string'], event.raw.data) |
||||
if (!testEvent[0]) { |
||||
testCallback({type: 'testFailure', value: changeCase.sentenceCase(func.name), time: time, errMsg: testEvent[1], context: testName}) |
||||
failureNum += 1 |
||||
return next() |
||||
} |
||||
testPassed = true |
||||
} |
||||
} |
||||
|
||||
if (testPassed) { |
||||
testCallback({type: 'testPass', value: changeCase.sentenceCase(func.name), time: time, context: testName}) |
||||
passingNum += 1 |
||||
} |
||||
|
||||
return next() |
||||
} catch (err) { |
||||
console.log('error!') |
||||
console.dir(err) |
||||
return next(err) |
||||
} |
||||
}).on('error', function (err) { |
||||
console.error(err) |
||||
next(err) |
||||
}) |
||||
} |
||||
}, function (error) { |
||||
resultsCallback(error, { |
||||
passingNum: passingNum, |
||||
failureNum: failureNum, |
||||
timePassed: timePassed |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
module.exports = { |
||||
runTest: runTest |
||||
} |
@ -0,0 +1,174 @@ |
||||
import async from 'async' |
||||
import * as changeCase from 'change-case' |
||||
import Web3 from 'web3' |
||||
import { RunListInterface, TestCbInterface, TestResultInterface, ResultCbInterface } from './types' |
||||
|
||||
function getFunctionFullName (signature: string, methodIdentifiers) { |
||||
for (const method in methodIdentifiers) { |
||||
if (signature.replace('0x', '') === methodIdentifiers[method].replace('0x', '')) { |
||||
return method |
||||
} |
||||
} |
||||
return null |
||||
} |
||||
|
||||
function getOverridedSender (userdoc, signature: string, methodIdentifiers) { |
||||
let fullName: any = getFunctionFullName(signature, methodIdentifiers) |
||||
let match = /sender: account-+(\d)/g |
||||
let accountIndex = userdoc.methods[fullName] ? match.exec(userdoc.methods[fullName].notice) : null |
||||
return fullName && accountIndex ? accountIndex[1] : null |
||||
} |
||||
|
||||
function getAvailableFunctions (jsonInterface) { |
||||
return jsonInterface.reverse().filter((x) => x.type === 'function').map((x) => x.name) |
||||
} |
||||
|
||||
function getTestFunctions (jsonInterface) { |
||||
let specialFunctions = ['beforeAll', 'beforeEach', 'afterAll', 'afterEach'] |
||||
return jsonInterface.filter((x) => specialFunctions.indexOf(x.name) < 0 && x.type === 'function') |
||||
} |
||||
|
||||
function createRunList (jsonInterface): RunListInterface[] { |
||||
let availableFunctions = getAvailableFunctions(jsonInterface) |
||||
let testFunctions = getTestFunctions(jsonInterface) |
||||
let runList: RunListInterface[] = [] |
||||
|
||||
if (availableFunctions.indexOf('beforeAll') >= 0) { |
||||
runList.push({ name: 'beforeAll', type: 'internal', constant: false }) |
||||
} |
||||
|
||||
for (let func of testFunctions) { |
||||
if (availableFunctions.indexOf('beforeEach') >= 0) { |
||||
runList.push({ name: 'beforeEach', type: 'internal', constant: false }) |
||||
} |
||||
runList.push({ name: func.name, signature: func.signature, type: 'test', constant: func.constant }) |
||||
if (availableFunctions.indexOf('afterEach') >= 0) { |
||||
runList.push({ name: 'afterEach', type: 'internal', constant: false }) |
||||
} |
||||
} |
||||
|
||||
if (availableFunctions.indexOf('afterAll') >= 0) { |
||||
runList.push({ name: 'afterAll', type: 'internal', constant: false }) |
||||
} |
||||
|
||||
return runList |
||||
} |
||||
|
||||
export function runTest (testName, testObject: any, contractDetails: any, opts: any, testCallback: TestCbInterface, resultsCallback: ResultCbInterface) { |
||||
let runList = createRunList(testObject._jsonInterface) |
||||
|
||||
let passingNum: number = 0 |
||||
let failureNum: number = 0 |
||||
let timePassed: number = 0 |
||||
let web3 = new Web3() |
||||
|
||||
const userAgent = (typeof (navigator) !== 'undefined') && navigator.userAgent ? navigator.userAgent.toLowerCase() : '-' |
||||
const isBrowser = !(typeof (window) === 'undefined' || userAgent.indexOf(' electron/') > -1) |
||||
if (!isBrowser) { |
||||
let signale = require('signale') |
||||
signale.warn('DO NOT TRY TO ACCESS (IN YOUR SOLIDITY TEST) AN ACCOUNT GREATER THAN THE LENGTH OF THE FOLLOWING ARRAY (' + opts.accounts.length + ') :') |
||||
signale.warn(opts.accounts) |
||||
signale.warn('e.g: the following code won\'t work in the current context:') |
||||
signale.warn('TestsAccounts.getAccount(' + opts.accounts.length + ')') |
||||
} |
||||
const resp: TestResultInterface = { |
||||
type: 'contract', |
||||
value: testName, |
||||
filename: testObject.filename |
||||
} |
||||
testCallback(undefined, resp) |
||||
async.eachOfLimit(runList, 1, function (func, index, next) { |
||||
let sender |
||||
if (func.signature) { |
||||
sender = getOverridedSender(contractDetails.userdoc, func.signature, contractDetails.evm.methodIdentifiers) |
||||
if (opts.accounts) { |
||||
sender = opts.accounts[sender] |
||||
} |
||||
} |
||||
let sendParams |
||||
if (sender) sendParams = { from: sender } |
||||
|
||||
let method = testObject.methods[func.name].apply(testObject.methods[func.name], []) |
||||
let startTime = Date.now() |
||||
if (func.constant) { |
||||
method.call(sendParams).then((result) => { |
||||
let time = Math.ceil((Date.now() - startTime) / 1000.0) |
||||
if (result) { |
||||
const resp: TestResultInterface = { |
||||
type: 'testPass', |
||||
value: changeCase.sentenceCase(func.name), |
||||
time: time, |
||||
context: testName |
||||
} |
||||
testCallback(undefined, resp) |
||||
passingNum += 1 |
||||
timePassed += time |
||||
} else { |
||||
const resp: TestResultInterface = { |
||||
type: 'testFailure', |
||||
value: changeCase.sentenceCase(func.name), |
||||
time: time, |
||||
errMsg: 'function returned false', |
||||
context: testName |
||||
} |
||||
testCallback(undefined, resp) |
||||
failureNum += 1 |
||||
} |
||||
next() |
||||
}) |
||||
} else { |
||||
method.send(sendParams).on('receipt', (receipt) => { |
||||
try { |
||||
let time: number = Math.ceil((Date.now() - startTime) / 1000.0) |
||||
let topic = Web3.utils.sha3('AssertionEvent(bool,string)') |
||||
let testPassed: boolean = false |
||||
|
||||
for (let i in receipt.events) { |
||||
let event = receipt.events[i] |
||||
if (event.raw.topics.indexOf(topic) >= 0) { |
||||
const testEvent = web3.eth.abi.decodeParameters(['bool', 'string'], event.raw.data) |
||||
if (!testEvent[0]) { |
||||
const resp: TestResultInterface = { |
||||
type: 'testFailure', |
||||
value: changeCase.sentenceCase(func.name), |
||||
time: time, |
||||
errMsg: testEvent[1], |
||||
context: testName |
||||
}; |
||||
testCallback(undefined, resp) |
||||
failureNum += 1 |
||||
return next() |
||||
} |
||||
testPassed = true |
||||
} |
||||
} |
||||
|
||||
if (testPassed) { |
||||
const resp: TestResultInterface = { |
||||
type: 'testPass', |
||||
value: changeCase.sentenceCase(func.name), |
||||
time: time, |
||||
context: testName |
||||
} |
||||
testCallback(undefined, resp) |
||||
passingNum += 1 |
||||
} |
||||
|
||||
return next() |
||||
} catch (err) { |
||||
console.error(err) |
||||
return next(err) |
||||
} |
||||
}).on('error', function (err: Error | null | undefined) { |
||||
console.error(err) |
||||
next(err) |
||||
}) |
||||
} |
||||
}, function(error) { |
||||
resultsCallback(error, { |
||||
passingNum: passingNum, |
||||
failureNum: failureNum, |
||||
timePassed: timePassed |
||||
}) |
||||
}) |
||||
} |
@ -0,0 +1,39 @@ |
||||
/** sources object with name of the file and content **/ |
||||
export interface SrcIfc { |
||||
[key: string]: { |
||||
content: string |
||||
} |
||||
} |
||||
/** An object with final results of test **/ |
||||
export interface FinalResult { |
||||
totalPassing: number, |
||||
totalFailing: number, |
||||
totalTime: number, |
||||
errors: any[], |
||||
} |
||||
/** List of tests to run **/ |
||||
export interface RunListInterface { |
||||
name: string, |
||||
type: string, |
||||
constant: boolean, |
||||
signature?: any |
||||
} |
||||
export interface ResultsInterface { |
||||
passingNum: number, |
||||
failureNum: number, |
||||
timePassed: number |
||||
} |
||||
export interface TestResultInterface { |
||||
type: string, |
||||
value: any, |
||||
time?: number, |
||||
context?: string, |
||||
errMsg?: string |
||||
filename?: string |
||||
} |
||||
export interface TestCbInterface { |
||||
(error: Error | null | undefined, result: TestResultInterface) : void; |
||||
} |
||||
export interface ResultCbInterface { |
||||
(error: Error | null | undefined, result: ResultsInterface) : void; |
||||
} |
@ -1,198 +0,0 @@ |
||||
const async = require('async') |
||||
const Web3 = require('web3') |
||||
const assert = require('assert') |
||||
|
||||
let Compiler = require('../src/compiler.js') |
||||
let Deployer = require('../src/deployer.js') |
||||
let TestRunner = require('../src/testRunner.js') |
||||
const Provider = require('remix-simulator').Provider |
||||
|
||||
function compileAndDeploy (filename, callback) { |
||||
let web3 = new Web3() |
||||
web3.setProvider(new Provider()) |
||||
let compilationData |
||||
let accounts |
||||
async.waterfall([ |
||||
function getAccountList (next) { |
||||
web3.eth.getAccounts((_err, _accounts) => { |
||||
accounts = _accounts |
||||
next(_err) |
||||
}) |
||||
}, |
||||
function compile (next) { |
||||
Compiler.compileFileOrFiles(filename, false, {accounts}, next) |
||||
}, |
||||
function deployAllContracts (compilationResult, next) { |
||||
compilationData = compilationResult |
||||
Deployer.deployAll(compilationResult, web3, next) |
||||
} |
||||
], function (_err, contracts) { |
||||
callback(null, compilationData, contracts, accounts) |
||||
}) |
||||
} |
||||
|
||||
|
||||
describe('testRunner', function () { |
||||
describe('#runTest', function() { |
||||
describe('test with beforeAll', function () { |
||||
let filename = 'tests/examples_1/simple_storage_test.sol' |
||||
let tests = [], results = {} |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { |
||||
var testCallback = function (test) { |
||||
tests.push(test) |
||||
} |
||||
var resultsCallback = function (_err, _results) { |
||||
results = _results |
||||
done() |
||||
} |
||||
TestRunner.runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], { accounts }, testCallback, resultsCallback) |
||||
}) |
||||
}) |
||||
|
||||
it('should 1 passing test', function () { |
||||
assert.equal(results.passingNum, 2) |
||||
}) |
||||
|
||||
it('should 1 failing test', function () { |
||||
assert.equal(results.failureNum, 2) |
||||
}) |
||||
|
||||
it('should returns 5 messages', function () { |
||||
assert.deepEqual(tests, [ |
||||
{ type: 'contract', value: 'MyTest', filename: 'tests/examples_1/simple_storage_test.sol' }, |
||||
{ type: 'testFailure', value: 'Should trigger one fail', time: 1, context: 'MyTest', errMsg: 'the test 1 fails' }, |
||||
{ type: 'testPass', value: 'Should trigger one pass', time: 1, context: 'MyTest'}, |
||||
{ type: 'testPass', value: 'Initial value should be100', time: 1, context: 'MyTest' }, |
||||
{ type: 'testFailure', value: 'Initial value should be200', time: 1, context: 'MyTest', errMsg: 'function returned false' } |
||||
]) |
||||
}) |
||||
}) |
||||
|
||||
describe('test with beforeEach', function () { |
||||
let filename = 'tests/examples_2/simple_storage_test.sol' |
||||
let tests = [], results = {} |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { |
||||
var testCallback = function (test) { |
||||
tests.push(test) |
||||
} |
||||
var resultsCallback = function (_err, _results) { |
||||
results = _results |
||||
done() |
||||
} |
||||
TestRunner.runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], { accounts }, testCallback, resultsCallback) |
||||
}) |
||||
}) |
||||
|
||||
it('should 2 passing tests', function () { |
||||
assert.equal(results.passingNum, 2) |
||||
}) |
||||
|
||||
it('should 0 failing tests', function () { |
||||
assert.equal(results.failureNum, 0) |
||||
}) |
||||
|
||||
it('should returns 3 messages', function () { |
||||
assert.deepEqual(tests, [ |
||||
{ type: 'contract', value: 'MyTest', filename: 'tests/examples_2/simple_storage_test.sol' }, |
||||
{ type: 'testPass', value: 'Initial value should be100', time: 1, context: 'MyTest' }, |
||||
{ type: 'testPass', value: 'Initial value should be200', time: 1, context: 'MyTest' } |
||||
]) |
||||
}) |
||||
}) |
||||
|
||||
// Test string equality
|
||||
describe('test string equality', function () { |
||||
let filename = 'tests/examples_3/simple_string_test.sol' |
||||
let tests = [], results = {} |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { |
||||
var testCallback = function (test) { |
||||
tests.push(test) |
||||
} |
||||
var resultsCallback = function (_err, _results) { |
||||
results = _results |
||||
done() |
||||
} |
||||
TestRunner.runTest('StringTest', contracts.StringTest, compilationData[filename]['StringTest'], { accounts }, testCallback, resultsCallback) |
||||
TestRunner.runTest('StringTest2', contracts.StringTest2, compilationData[filename]['StringTest2'], { accounts }, testCallback, resultsCallback) |
||||
}) |
||||
}) |
||||
|
||||
it('should 2 passing tests', function () { |
||||
assert.equal(results.passingNum, 2) |
||||
}) |
||||
|
||||
it('should 1 failing tests', function () { |
||||
assert.equal(results.failureNum, 1) |
||||
}) |
||||
|
||||
it('should returns 3 messages', function () { |
||||
assert.deepEqual(tests, [ |
||||
{ type: 'contract', value: 'StringTest', filename: 'tests/examples_3/simple_string_test.sol' }, |
||||
{ type: 'testFailure', value: 'Value should be hello world', time: 1, context: 'StringTest', "errMsg": "initial value is not correct" }, |
||||
{ type: 'testPass', value: 'Value should not be hello wordl', time: 1, context: 'StringTest' }, |
||||
{ type: 'testPass', value: 'Initial value should be hello', time: 1, context: 'StringTest' }, |
||||
]) |
||||
}) |
||||
}) |
||||
|
||||
// Test signed/unsigned integer weight
|
||||
describe('test number weight', function () { |
||||
let filename = 'tests/number/number_test.sol' |
||||
let tests = [], results = {} |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { |
||||
var testCallback = function (test) { |
||||
tests.push(test) |
||||
} |
||||
var resultsCallback = function (_err, _results) { |
||||
results = _results |
||||
done() |
||||
} |
||||
TestRunner.runTest('IntegerTest', contracts.IntegerTest, compilationData[filename]['IntegerTest'], { accounts }, testCallback, resultsCallback) |
||||
}) |
||||
}) |
||||
|
||||
it('should have 6 passing tests', function () { |
||||
assert.equal(results.passingNum, 6) |
||||
}) |
||||
it('should have 2 failing tests', function () { |
||||
assert.equal(results.failureNum, 2) |
||||
}) |
||||
}) |
||||
|
||||
// Test Transaction with different sender
|
||||
describe('various sender', function () { |
||||
let filename = 'tests/various_sender/sender_test.sol' |
||||
let tests = [], results = {} |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { |
||||
var testCallback = function (test) { |
||||
tests.push(test) |
||||
} |
||||
var resultsCallback = function (_err, _results) { |
||||
results = _results |
||||
done() |
||||
} |
||||
|
||||
TestRunner.runTest('SenderTest', contracts.SenderTest, compilationData[filename]['SenderTest'], { accounts }, testCallback, resultsCallback) |
||||
|
||||
}) |
||||
}) |
||||
|
||||
it('should have 4 passing tests', function () { |
||||
assert.equal(results.passingNum, 4) |
||||
}) |
||||
it('should have 1 failing tests', function () { |
||||
assert.equal(results.failureNum, 0) |
||||
}) |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,214 @@ |
||||
import 'mocha' |
||||
import * as async from 'async' |
||||
import Web3 from 'web3' |
||||
import * as assert from 'assert' |
||||
import { Provider } from 'remix-simulator' |
||||
|
||||
import { compileFileOrFiles } from '../dist/compiler' |
||||
import { deployAll } from '../dist/deployer' |
||||
import { runTest } from '../dist/index' |
||||
import { ResultsInterface, TestCbInterface, ResultCbInterface } from '../dist/index' |
||||
|
||||
function compileAndDeploy(filename: string, callback: Function) { |
||||
let web3: Web3 = new Web3() |
||||
web3.setProvider(new Provider()) |
||||
let compilationData: object |
||||
let accounts: string[] |
||||
async.waterfall([ |
||||
function getAccountList(next: Function): void { |
||||
web3.eth.getAccounts((_err: Error | null | undefined, _accounts: string[]) => { |
||||
accounts = _accounts |
||||
next(_err) |
||||
}) |
||||
}, |
||||
function compile(next: Function): void { |
||||
compileFileOrFiles(filename, false, { accounts }, next) |
||||
}, |
||||
function deployAllContracts(compilationResult: object, next: Function): void { |
||||
try { |
||||
compilationData = compilationResult |
||||
deployAll(compilationResult, web3, next) |
||||
} catch (e) { |
||||
throw e |
||||
} |
||||
} |
||||
], function (_err: Error | null | undefined, contracts: any): void { |
||||
callback(null, compilationData, contracts, accounts) |
||||
}) |
||||
} |
||||
|
||||
|
||||
describe('testRunner', () => { |
||||
describe('#runTest', () => { |
||||
describe('test with beforeAll', () => { |
||||
let filename: string = 'tests/examples_1/simple_storage_test.sol' |
||||
let tests: any[] = [], results: ResultsInterface; |
||||
|
||||
before((done) => { |
||||
compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: object, contracts: any, accounts: object) => { |
||||
const testCallback: TestCbInterface = (err, test) => { |
||||
if (err) { throw err } |
||||
tests.push(test) |
||||
} |
||||
const resultsCallback: ResultCbInterface = (err, _results) => { |
||||
if (err) { throw err } |
||||
results = _results |
||||
done() |
||||
} |
||||
runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], { accounts }, testCallback, resultsCallback) |
||||
}) |
||||
}) |
||||
|
||||
it('should 1 passing test', function () { |
||||
assert.equal(results.passingNum, 2) |
||||
}) |
||||
|
||||
it('should 1 failing test', function () { |
||||
assert.equal(results.failureNum, 2) |
||||
}) |
||||
|
||||
it('should returns 5 messages', function () { |
||||
assert.deepEqual(tests, [ |
||||
{ type: 'contract', value: 'MyTest', filename: 'tests/examples_1/simple_storage_test.sol' }, |
||||
{ type: 'testFailure', value: 'Should trigger one fail', time: 1, context: 'MyTest', errMsg: 'the test 1 fails' }, |
||||
{ type: 'testPass', value: 'Should trigger one pass', time: 1, context: 'MyTest' }, |
||||
{ type: 'testPass', value: 'Initial value should be100', time: 1, context: 'MyTest' }, |
||||
{ type: 'testFailure', value: 'Initial value should be200', time: 1, context: 'MyTest', errMsg: 'function returned false' } |
||||
]) |
||||
}) |
||||
}) |
||||
|
||||
describe('test with beforeEach', function () { |
||||
let filename = 'tests/examples_2/simple_storage_test.sol' |
||||
let tests: any[] = [], results: ResultsInterface; |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, accounts: object) { |
||||
const testCallback: TestCbInterface = (err, test) => { |
||||
if (err) { throw err } |
||||
tests.push(test) |
||||
} |
||||
const resultsCallback: ResultCbInterface = (err, _results) => { |
||||
if (err) { throw err } |
||||
results = _results |
||||
done() |
||||
} |
||||
runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], { accounts }, testCallback, resultsCallback) |
||||
}) |
||||
}) |
||||
|
||||
it('should 2 passing tests', function () { |
||||
assert.equal(results.passingNum, 2) |
||||
}) |
||||
|
||||
it('should 0 failing tests', function () { |
||||
assert.equal(results.failureNum, 0) |
||||
}) |
||||
|
||||
it('should returns 3 messages', function () { |
||||
assert.deepEqual(tests, [ |
||||
{ type: 'contract', value: 'MyTest', filename: 'tests/examples_2/simple_storage_test.sol' }, |
||||
{ type: 'testPass', value: 'Initial value should be100', time: 1, context: 'MyTest' }, |
||||
{ type: 'testPass', value: 'Initial value should be200', time: 1, context: 'MyTest' } |
||||
]) |
||||
}) |
||||
}) |
||||
|
||||
// Test string equality
|
||||
describe('test string equality', function () { |
||||
let filename = 'tests/examples_3/simple_string_test.sol' |
||||
let tests: any[] = [], results: ResultsInterface; |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, (_err, compilationData, contracts, accounts) => { |
||||
const testCallback: TestCbInterface = (err, test) => { |
||||
if (err) { throw err } |
||||
tests.push(test) |
||||
} |
||||
const resultsCallback: ResultCbInterface = (err, _results) => { |
||||
if (err) { throw err } |
||||
results = _results |
||||
done() |
||||
} |
||||
runTest('StringTest', contracts.StringTest, compilationData[filename]['StringTest'], { accounts }, testCallback, resultsCallback) |
||||
runTest('StringTest2', contracts.StringTest2, compilationData[filename]['StringTest2'], { accounts }, testCallback, resultsCallback) |
||||
}) |
||||
}) |
||||
|
||||
it('should 2 passing tests', function () { |
||||
assert.equal(results.passingNum, 2) |
||||
}) |
||||
|
||||
it('should 1 failing tests', function () { |
||||
assert.equal(results.failureNum, 1) |
||||
}) |
||||
|
||||
it('should returns 3 messages', function () { |
||||
assert.deepEqual(tests, [ |
||||
{ type: 'contract', value: 'StringTest', filename: 'tests/examples_3/simple_string_test.sol' }, |
||||
{ type: 'testFailure', value: 'Value should be hello world', time: 1, context: 'StringTest', "errMsg": "initial value is not correct" }, |
||||
{ type: 'testPass', value: 'Value should not be hello wordl', time: 1, context: 'StringTest' }, |
||||
{ type: 'testPass', value: 'Initial value should be hello', time: 1, context: 'StringTest' }, |
||||
]) |
||||
}) |
||||
}) |
||||
|
||||
//Test signed/unsigned integer weight
|
||||
describe('test number weight', function () { |
||||
let filename = 'tests/number/number_test.sol' |
||||
let tests: any[] = [], results: ResultsInterface; |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, (_err, compilationData, contracts, accounts) => { |
||||
const testCallback: TestCbInterface = (err, test) => { |
||||
if (err) { throw err } |
||||
tests.push(test) |
||||
} |
||||
const resultsCallback: ResultCbInterface = (err, _results) => { |
||||
if (err) { throw err } |
||||
results = _results |
||||
done() |
||||
} |
||||
runTest('IntegerTest', contracts.IntegerTest, compilationData[filename]['IntegerTest'], { accounts }, testCallback, resultsCallback) |
||||
}) |
||||
}) |
||||
|
||||
it('should have 6 passing tests', function () { |
||||
assert.equal(results.passingNum, 6) |
||||
}) |
||||
it('should have 2 failing tests', function () { |
||||
assert.equal(results.failureNum, 2) |
||||
}) |
||||
}) |
||||
|
||||
// Test Transaction with different sender
|
||||
describe('various sender', function () { |
||||
let filename = 'tests/various_sender/sender_test.sol' |
||||
let tests: any[] = [], results: ResultsInterface; |
||||
|
||||
before(function (done) { |
||||
compileAndDeploy(filename, (_err, compilationData, contracts, accounts) => { |
||||
const testCallback: TestCbInterface = (err, test) => { |
||||
if (err) { throw err } |
||||
tests.push(test) |
||||
} |
||||
const resultsCallback: ResultCbInterface = (err, _results) => { |
||||
if (err) { throw err } |
||||
results = _results |
||||
done() |
||||
} |
||||
|
||||
runTest('SenderTest', contracts.SenderTest, compilationData[filename]['SenderTest'], { accounts }, testCallback, resultsCallback) |
||||
|
||||
}) |
||||
}) |
||||
|
||||
it('should have 4 passing tests', function () { |
||||
assert.equal(results.passingNum, 4) |
||||
}) |
||||
it('should have 1 failing tests', function () { |
||||
assert.equal(results.failureNum, 0) |
||||
}) |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,24 @@ |
||||
{ |
||||
"include": ["src"], |
||||
"compilerOptions": { |
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ |
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ |
||||
"lib": ["dom", "es2018"], /* Specify library files to be included in the compilation. */ |
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */ |
||||
"sourceMap": true, /* Generates corresponding '.map' file. */ |
||||
"outDir": "./dist", /* Redirect output structure to the directory. */ |
||||
/* Strict Type-Checking Options */ |
||||
"strict": true, /* Enable all strict type-checking options. */ |
||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ |
||||
/* Module Resolution Options */ |
||||
"baseUrl": "./src", /* Base directory to resolve non-absolute module names. */ |
||||
"paths": { "remix-tests": ["./"] }, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ |
||||
"typeRoots": [ |
||||
"./@types", |
||||
"./node_modules/@types" |
||||
], |
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ |
||||
/* Experimental Options */ |
||||
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ |
||||
} |
||||
} |
Loading…
Reference in new issue