pull/5370/head
aniket-engg 5 years ago
parent b71c8ec3bb
commit af3d01cede
  1. 24
      remix-tests/src/compiler.ts
  2. 9
      remix-tests/src/runTestFiles.ts
  3. 13
      remix-tests/src/runTestSources.ts
  4. 65
      remix-tests/src/testRunner.ts
  5. 12
      remix-tests/tests/testRunner.ts

@ -72,7 +72,16 @@ function processFile(filePath: string, sources: SrcIfc, isRoot: boolean = false)
const userAgent = (typeof (navigator) !== 'undefined') && navigator.userAgent ? navigator.userAgent.toLowerCase() : '-' const userAgent = (typeof (navigator) !== 'undefined') && navigator.userAgent ? navigator.userAgent.toLowerCase() : '-'
const isBrowser = !(typeof (window) === 'undefined' || userAgent.indexOf(' electron/') > -1) const isBrowser = !(typeof (window) === 'undefined' || userAgent.indexOf(' electron/') > -1)
// TODO: replace this with remix's own compiler code /**
* @dev Compile file or files before running tests (used for CLI execution)
* @param filename Name of file
* @param isDirectory True, if path is a directory
* @param opts Options
* @param cb Callback
*
* TODO: replace this with remix's own compiler code
*/
export function compileFileOrFiles(filename: string, isDirectory: boolean, opts: any, cb: Function) { export function compileFileOrFiles(filename: string, isDirectory: boolean, opts: any, cb: Function) {
let compiler: any let compiler: any
const accounts: string[] = opts.accounts || [] const accounts: string[] = opts.accounts || []
@ -125,11 +134,20 @@ export function compileFileOrFiles(filename: string, isDirectory: boolean, opts:
if (!isBrowser) require('signale').fatal(errors) if (!isBrowser) require('signale').fatal(errors)
return cb(errors) return cb(errors)
} }
cb(err, result.contracts, result.sources) cb(err, result.contracts, result.sources) //return callback with contract details & ASTs
}) })
} }
} }
/**
* @dev Compile contract source before running tests (used for IDE tests execution)
* @param sources sources
* @param versionUrl url of selected compiler version to load
* @param usingWorker if true, load compiler using web worker
* @param importFileCb Import file callback
* @param opts Options
* @param cb Callback
*/
export function compileContractSources(sources: SrcIfc, versionUrl: any, usingWorker: boolean, importFileCb: any, opts: any, cb: Function) { export function compileContractSources(sources: SrcIfc, versionUrl: any, usingWorker: boolean, importFileCb: any, opts: any, cb: Function) {
let compiler, filepath: string let compiler, filepath: string
const accounts: string[] = opts.accounts || [] const accounts: string[] = opts.accounts || []
@ -172,6 +190,6 @@ export function compileContractSources(sources: SrcIfc, versionUrl: any, usingWo
if (!isBrowser) require('signale').fatal(errors) if (!isBrowser) require('signale').fatal(errors)
return cb(errors) return cb(errors)
} }
cb(err, result.contracts, result.sources) cb(err, result.contracts, result.sources) // return callback with contract details & ASTs
}) })
} }

@ -8,6 +8,14 @@ import Web3 = require('web3')
import { compileFileOrFiles } from './compiler' import { compileFileOrFiles } from './compiler'
import { deployAll } from './deployer' import { deployAll } from './deployer'
/**
* @dev run test contract files (used for CLI)
* @param filepath Path of file
* @param isDirectory True, if path is a directory
* @param web3 Web3
* @param opts Options
*/
export function runTestFiles(filepath: string, isDirectory: boolean, web3: Web3, opts?: object) { export function runTestFiles(filepath: string, isDirectory: boolean, web3: Web3, opts?: object) {
opts = opts || {} opts = opts || {}
let sourceASTs: any = {} let sourceASTs: any = {}
@ -46,6 +54,7 @@ export function runTestFiles(filepath: string, isDirectory: boolean, web3: Web3,
compileFileOrFiles(filepath, isDirectory, { accounts }, next) compileFileOrFiles(filepath, isDirectory, { accounts }, next)
}, },
function deployAllContracts (compilationResult, asts, next: Function) { function deployAllContracts (compilationResult, asts, next: Function) {
// Extract AST of test contract file source
for(const filename in asts) for(const filename in asts)
{ {
if(filename.includes('_test.sol')) if(filename.includes('_test.sol'))

@ -4,7 +4,7 @@ require('colors')
import { compileContractSources } from './compiler' import { compileContractSources } from './compiler'
import { deployAll } from './deployer' import { deployAll } from './deployer'
import { runTest } from './testRunner' import { runTest } from './testRunner'
import { TestResultInterface, ResultsInterface } from './types' import { TestResultInterface } from './types'
import Web3 = require('web3') import Web3 = require('web3')
import { Provider } from 'remix-simulator' import { Provider } from 'remix-simulator'
@ -18,6 +18,17 @@ const createWeb3Provider = async function () {
return web3 return web3
} }
/**
* @dev Run tests from source of a test contract file (used for IDE)
* @param contractSources Sources of contract
* @param versionUrl url of selected compiler version to load
* @param usingWorker if true, load compiler using web worker
* @param testCallback Test callback
* @param resultCallback Result Callback
* @param finalCallback Final Callback
* @param importFileCb Import file callback
* @param opts Options
*/
export async function runTestSources(contractSources, versionUrl, usingWorker, testCallback, resultCallback, finalCallback, importFileCb, opts) { export async function runTestSources(contractSources, versionUrl, usingWorker, testCallback, resultCallback, finalCallback, importFileCb, opts) {
opts = opts || {} opts = opts || {}
let sourceASTs: any = {} let sourceASTs: any = {}

@ -19,26 +19,45 @@ function getOverridedSender (userdoc, signature: string, methodIdentifiers) {
return fullName && accountIndex ? accountIndex[1] : null return fullName && accountIndex ? accountIndex[1] : null
} }
function getAvailableFunctions (fileAST, testContractName) { /**
let contractAST: any[] = fileAST.nodes.filter(node => node.name === testContractName && node.nodeType === 'ContractDefinition') * @dev returns functions of a test contract file in same sequence they appear in file (using passed AST)
let funcNodes: any[] = contractAST[0].nodes.filter(node => node.kind === 'function' && node.nodeType === "FunctionDefinition") * @param fileAST AST of test contract file source
let funcList: string[] = funcNodes.map(node => node.name) * @param testContractName Name of test contract
*/
function getAvailableFunctions (fileAST: any, testContractName: string) {
const contractAST: any[] = fileAST.nodes.filter(node => node.name === testContractName && node.nodeType === 'ContractDefinition')
const funcNodes: any[] = contractAST[0].nodes.filter(node => node.kind === 'function' && node.nodeType === "FunctionDefinition")
const funcList: string[] = funcNodes.map(node => node.name)
return funcList; return funcList;
} }
function getTestFunctionsInterface (jsonInterface, funcList: string[]) { /**
let resutantInterface: any[] = [] * @dev returns ABI of passed method list from passed interface
let specialFunctions = ['beforeAll', 'beforeEach', 'afterAll', 'afterEach'] * @param jsonInterface Json Interface
* @param funcList Methods to extract the interface of
*/
function getTestFunctionsInterface (jsonInterface: any, funcList: string[]) {
let functionsInterface: any[] = []
const specialFunctions = ['beforeAll', 'beforeEach', 'afterAll', 'afterEach']
for(const func of funcList){ for(const func of funcList){
if(!specialFunctions.includes(func)) if(!specialFunctions.includes(func))
resutantInterface.push(jsonInterface.find(node => node.type === 'function' && node.name === func)) functionsInterface.push(jsonInterface.find(node => node.type === 'function' && node.name === func))
} }
return resutantInterface return functionsInterface
} }
function createRunList (jsonInterface, fileAST, testContractName): RunListInterface[] { /**
let availableFunctions = getAvailableFunctions(fileAST, testContractName) * @dev Prepare a list of tests to run using test contract file ABI, AST & contract name
let testFunctionsInterface = getTestFunctionsInterface(jsonInterface, availableFunctions) * @param jsonInterface File JSON interface
* @param fileAST File AST
* @param testContractName Test contract name
*/
function createRunList (jsonInterface: any, fileAST: any, testContractName: string): RunListInterface[] {
const availableFunctions: string[] = getAvailableFunctions(fileAST, testContractName)
const testFunctionsInterface: any[] = getTestFunctionsInterface(jsonInterface, availableFunctions)
let runList: RunListInterface[] = [] let runList: RunListInterface[] = []
@ -46,7 +65,7 @@ function createRunList (jsonInterface, fileAST, testContractName): RunListInterf
runList.push({ name: 'beforeAll', type: 'internal', constant: false }) runList.push({ name: 'beforeAll', type: 'internal', constant: false })
} }
for (let func of testFunctionsInterface) { for (const func of testFunctionsInterface) {
if (availableFunctions.indexOf('beforeEach') >= 0) { if (availableFunctions.indexOf('beforeEach') >= 0) {
runList.push({ name: 'beforeEach', type: 'internal', constant: false }) runList.push({ name: 'beforeEach', type: 'internal', constant: false })
} }
@ -64,11 +83,11 @@ function createRunList (jsonInterface, fileAST, testContractName): RunListInterf
} }
export function runTest (testName, testObject: any, contractDetails: any, fileAST: any, opts: any, testCallback: TestCbInterface, resultsCallback: ResultCbInterface) { export function runTest (testName, testObject: any, contractDetails: any, fileAST: any, opts: any, testCallback: TestCbInterface, resultsCallback: ResultCbInterface) {
let runList = createRunList(testObject._jsonInterface, fileAST, testName) const runList: RunListInterface[] = createRunList(testObject._jsonInterface, fileAST, testName)
let passingNum: number = 0 let passingNum: number = 0
let failureNum: number = 0 let failureNum: number = 0
let timePassed: number = 0 let timePassed: number = 0
let web3 = new Web3() const web3 = new Web3()
const accts: TestResultInterface = { const accts: TestResultInterface = {
type: 'accountList', type: 'accountList',
@ -95,11 +114,11 @@ export function runTest (testName, testObject: any, contractDetails: any, fileAS
let sendParams let sendParams
if (sender) sendParams = { from: sender } if (sender) sendParams = { from: sender }
let method = testObject.methods[func.name].apply(testObject.methods[func.name], []) const method = testObject.methods[func.name].apply(testObject.methods[func.name], [])
let startTime = Date.now() const startTime = Date.now()
if (func.constant) { if (func.constant) {
method.call(sendParams).then((result) => { method.call(sendParams).then((result) => {
let time = (Date.now() - startTime) / 1000.0 const time = (Date.now() - startTime) / 1000.0
if (result) { if (result) {
const resp: TestResultInterface = { const resp: TestResultInterface = {
type: 'testPass', type: 'testPass',
@ -126,12 +145,12 @@ export function runTest (testName, testObject: any, contractDetails: any, fileAS
} else { } else {
method.send(sendParams).on('receipt', (receipt) => { method.send(sendParams).on('receipt', (receipt) => {
try { try {
let time: number = (Date.now() - startTime) / 1000.0 const time: number = (Date.now() - startTime) / 1000.0
let topic = Web3.utils.sha3('AssertionEvent(bool,string)') const topic = Web3.utils.sha3('AssertionEvent(bool,string)')
let testPassed: boolean = false let testPassed: boolean = false
for (let i in receipt.events) { for (const i in receipt.events) {
let event = receipt.events[i] const event = receipt.events[i]
if (event.raw.topics.indexOf(topic) >= 0) { if (event.raw.topics.indexOf(topic) >= 0) {
const testEvent = web3.eth.abi.decodeParameters(['bool', 'string'], event.raw.data) const testEvent = web3.eth.abi.decodeParameters(['bool', 'string'], event.raw.data)
if (!testEvent[0]) { if (!testEvent[0]) {
@ -168,7 +187,7 @@ export function runTest (testName, testObject: any, contractDetails: any, fileAS
} }
}).on('error', function (err: any) { }).on('error', function (err: any) {
console.error(err) console.error(err)
let time: number = (Date.now() - startTime) / 1000.0 const time: number = (Date.now() - startTime) / 1000.0
const resp: TestResultInterface = { const resp: TestResultInterface = {
type: 'testFailure', type: 'testFailure',
value: changeCase.sentenceCase(func.name), value: changeCase.sentenceCase(func.name),

@ -103,7 +103,7 @@ describe('testRunner', () => {
describe('#runTest', () => { describe('#runTest', () => {
describe('test with beforeAll', () => { describe('test with beforeAll', () => {
let filename: string = 'tests/examples_1/simple_storage_test.sol' const filename: string = 'tests/examples_1/simple_storage_test.sol'
before((done) => { before((done) => {
compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) => { compileAndDeploy(filename, (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) => {
@ -134,7 +134,7 @@ describe('testRunner', () => {
}) })
describe('test with beforeEach', function () { describe('test with beforeEach', function () {
let filename = 'tests/examples_2/simple_storage_test.sol' const filename: string = 'tests/examples_2/simple_storage_test.sol'
before(function (done) { before(function (done) {
compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) {
@ -164,7 +164,7 @@ describe('testRunner', () => {
// Test string equality // Test string equality
describe('test string equality', function () { describe('test string equality', function () {
let filename = 'tests/examples_3/simple_string_test.sol' const filename: string = 'tests/examples_3/simple_string_test.sol'
before(function (done) { before(function (done) {
compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) {
@ -190,7 +190,7 @@ describe('testRunner', () => {
// Test multiple directory import in test contract // Test multiple directory import in test contract
describe('test multiple directory import in test contract', function () { describe('test multiple directory import in test contract', function () {
let filename = 'tests/examples_5/test/simple_storage_test.sol' const filename: string = 'tests/examples_5/test/simple_storage_test.sol'
before(function (done) { before(function (done) {
compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) {
@ -217,7 +217,7 @@ describe('testRunner', () => {
//Test signed/unsigned integer weight //Test signed/unsigned integer weight
describe('test number weight', function () { describe('test number weight', function () {
let filename = 'tests/number/number_test.sol' const filename: string = 'tests/number/number_test.sol'
before(function (done) { before(function (done) {
compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) {
@ -237,7 +237,7 @@ describe('testRunner', () => {
// Test Transaction with different sender // Test Transaction with different sender
describe('various sender', function () { describe('various sender', function () {
let filename = 'tests/various_sender/sender_test.sol' const filename: string = 'tests/various_sender/sender_test.sol'
before(function (done) { before(function (done) {
compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) { compileAndDeploy(filename, function (_err: Error | null | undefined, compilationData: object, contracts: any, asts: any, accounts: string[]) {

Loading…
Cancel
Save