11import async from 'async'
22import * as changeCase from 'change-case'
3- import { keccak256 , AbiCoder , ContractTransactionResponse , toUtf8Bytes , Interface } from 'ethers'
3+ import { keccak256 , AbiCoder , ContractTransactionResponse , toUtf8Bytes , Interface } from 'ethers'
44import assertionEvents from './assertionEvents'
55import {
66 RunListInterface , TestCbInterface , TestResultInterface , ResultCbInterface ,
@@ -232,32 +232,123 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
232232 filename : testObject . filename
233233 }
234234 testCallback ( undefined , resp )
235- async . eachOfLimit ( runList , 1 , function ( func , index , next ) {
235+ async . eachOfLimit ( runList , 1 , async function ( func , index ) {
236236 let sender : string | null = null
237237 let hhLogs
238- if ( func . signature ) {
239- sender = getOverriddenSender ( contractDetails . userdoc , func . signature , contractDetails . evm . methodIdentifiers )
240- if ( opts . accounts && sender ) {
241- sender = opts . accounts [ sender ]
242- }
243- }
244238 let sendParams : Record < string , any > | null = null
245- if ( sender ) sendParams = { from : sender }
246- if ( func . inputs && func . inputs . length > 0 ) { return resultsCallback ( new Error ( `Method '${ func . name } ' can not have parameters inside a test contract` ) , { passingNum, failureNum, timePassed } ) }
247-
248239 const startTime = Date . now ( )
240+ if ( func . inputs && func . inputs . length > 0 ) { return resultsCallback ( new Error ( `Method '${ func . name } ' can not have parameters inside a test contract` ) , { passingNum, failureNum, timePassed } ) }
249241 let debugTxHash :string
250242 if ( func . constant ) {
251243 sendParams = { }
252244 const tagTimestamp = 'remix_tests_tag' + Date . now ( )
253245 if ( provider . remix && provider . remix . registerCallId ) provider . remix . registerCallId ( tagTimestamp )
254- testObject [ func . name ] ( sendParams ) . then ( async ( result ) => {
255- const time = ( Date . now ( ) - startTime ) / 1000.0
256- let tagTxHash
257- if ( provider . remix && provider . remix . getHashFromTagBySimulator ) tagTxHash = await provider . remix . getHashFromTagBySimulator ( tagTimestamp )
258- if ( provider . remix && provider . remix . getHHLogsForTx ) hhLogs = await provider . remix . getHHLogsForTx ( tagTxHash )
259- debugTxHash = tagTxHash
260- if ( result ) {
246+ const result = await testObject [ func . name ] ( sendParams )
247+ const time = ( Date . now ( ) - startTime ) / 1000.0
248+ let tagTxHash
249+ if ( provider . remix && provider . remix . getHashFromTagBySimulator ) tagTxHash = await provider . remix . getHashFromTagBySimulator ( tagTimestamp )
250+ if ( provider . remix && provider . remix . getHHLogsForTx ) hhLogs = await provider . remix . getHHLogsForTx ( tagTxHash )
251+ debugTxHash = tagTxHash
252+ if ( result ) {
253+ const resp : TestResultInterface = {
254+ type : 'testPass' ,
255+ value : changeCase . sentenceCase ( func . name ) ,
256+ filename : testObject . filename ,
257+ time : time ,
258+ context : testName ,
259+ provider,
260+ debugTxHash
261+ }
262+ if ( hhLogs && hhLogs . length ) resp . hhLogs = hhLogs
263+ testCallback ( undefined , resp )
264+ passingNum += 1
265+ timePassed += time
266+ } else {
267+ const resp : TestResultInterface = {
268+ type : 'testFailure' ,
269+ value : changeCase . sentenceCase ( func . name ) ,
270+ filename : testObject . filename ,
271+ time : time ,
272+ errMsg : 'function returned false' ,
273+ context : testName ,
274+ provider,
275+ debugTxHash
276+ }
277+ if ( hhLogs && hhLogs . length ) resp . hhLogs = hhLogs
278+ testCallback ( undefined , resp )
279+ failureNum += 1
280+ timePassed += time
281+ }
282+ } else {
283+ if ( func . signature ) {
284+ sender = getOverriddenSender ( contractDetails . userdoc , func . signature , contractDetails . evm . methodIdentifiers )
285+ if ( opts . accounts && sender ) {
286+ sender = opts . accounts [ sender ]
287+ }
288+ }
289+ if ( sender ) {
290+ sendParams = { from : sender }
291+ const signer = await provider . getSigner ( sender )
292+ testObject = testObject . connect ( signer )
293+ }
294+ if ( func . payable ) {
295+ const value = getProvidedValue ( contractDetails . userdoc , func . signature , contractDetails . evm . methodIdentifiers )
296+ if ( value ) {
297+ if ( sendParams ) sendParams . value = value
298+ else sendParams = { value }
299+ }
300+ }
301+ if ( ! sendParams ) sendParams = { }
302+ sendParams . gasLimit = 10000000 * 8
303+ try {
304+ const txResponse : ContractTransactionResponse = await testObject [ func . name ] ( sendParams )
305+ const receipt = await provider . getTransactionReceipt ( txResponse . hash )
306+ debugTxHash = receipt . hash
307+ if ( provider . remix && provider . remix . getHHLogsForTx ) hhLogs = await provider . remix . getHHLogsForTx ( receipt . hash )
308+ const time : number = ( Date . now ( ) - startTime ) / 1000.0
309+ const assertionEventHashes = assertionEvents . map ( e => keccak256 ( toUtf8Bytes ( e . name + '(' + e . params . join ( ) + ')' ) ) )
310+ let testPassed = false
311+ for ( const i in receipt . logs ) {
312+ let events = receipt . logs [ i ]
313+ if ( ! Array . isArray ( events ) ) events = [ events ]
314+ for ( const event of events ) {
315+ const eIndex = assertionEventHashes . indexOf ( event . topics [ 0 ] ) // event name topic will always be at index 0
316+ if ( eIndex >= 0 ) {
317+ const testEventArray = AbiCoder . defaultAbiCoder ( ) . decode ( assertionEvents [ eIndex ] . params , event . data )
318+ const testEvent = [ ...testEventArray ] // Make it mutable
319+ if ( ! testEvent [ 0 ] ) {
320+ const assertMethod = testEvent [ 2 ]
321+ if ( assertMethod === 'ok' ) { // for 'Assert.ok' method
322+ testEvent [ 3 ] = 'false'
323+ testEvent [ 4 ] = 'true'
324+ }
325+ const location = getAssertMethodLocation ( fileAST , testName , func . name , assertMethod )
326+ const resp : TestResultInterface = {
327+ type : 'testFailure' ,
328+ value : changeCase . sentenceCase ( func . name ) ,
329+ filename : testObject . filename ,
330+ time : time ,
331+ errMsg : testEvent [ 1 ] ,
332+ context : testName ,
333+ assertMethod,
334+ returned : testEvent [ 3 ] ,
335+ expected : testEvent [ 4 ] ,
336+ location,
337+ provider,
338+ debugTxHash
339+ }
340+ if ( hhLogs && hhLogs . length ) resp . hhLogs = hhLogs
341+ testCallback ( undefined , resp )
342+ failureNum += 1
343+ timePassed += time
344+ return
345+ }
346+ testPassed = true
347+ }
348+ }
349+ }
350+
351+ if ( testPassed ) {
261352 const resp : TestResultInterface = {
262353 type : 'testPass' ,
263354 value : changeCase . sentenceCase ( func . name ) ,
@@ -271,117 +362,27 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
271362 testCallback ( undefined , resp )
272363 passingNum += 1
273364 timePassed += time
274- } else {
365+ } else if ( hhLogs && hhLogs . length ) {
275366 const resp : TestResultInterface = {
276- type : 'testFailure ' ,
367+ type : 'logOnly ' ,
277368 value : changeCase . sentenceCase ( func . name ) ,
278369 filename : testObject . filename ,
279370 time : time ,
280- errMsg : 'function returned false' ,
281371 context : testName ,
282- provider,
283- debugTxHash
372+ hhLogs
284373 }
285- if ( hhLogs && hhLogs . length ) resp . hhLogs = hhLogs
286374 testCallback ( undefined , resp )
287- failureNum += 1
288375 timePassed += time
289376 }
290- next ( )
291- } )
292- } else {
293- if ( func . payable ) {
294- const value = getProvidedValue ( contractDetails . userdoc , func . signature , contractDetails . evm . methodIdentifiers )
295- if ( value ) {
296- if ( sendParams ) sendParams . value = value
297- else sendParams = { value }
298- }
299- }
300- if ( ! sendParams ) sendParams = { }
301- sendParams . gas = 10000000 * 8
302- testObject [ func . name ] ( sendParams ) . then ( async ( txResponse : ContractTransactionResponse ) => {
303- try {
304- const receipt = await provider . getTransactionReceipt ( txResponse . hash )
305- debugTxHash = receipt . hash
306- if ( provider . remix && provider . remix . getHHLogsForTx ) hhLogs = await provider . remix . getHHLogsForTx ( receipt . hash )
307- const time : number = ( Date . now ( ) - startTime ) / 1000.0
308- const assertionEventHashes = assertionEvents . map ( e => keccak256 ( toUtf8Bytes ( e . name + '(' + e . params . join ( ) + ')' ) ) )
309- let testPassed = false
310- for ( const i in receipt . logs ) {
311- let events = receipt . logs [ i ]
312- if ( ! Array . isArray ( events ) ) events = [ events ]
313- for ( const event of events ) {
314- const eIndex = assertionEventHashes . indexOf ( event . topics [ 0 ] ) // event name topic will always be at index 0
315- if ( eIndex >= 0 ) {
316- const testEventArray = AbiCoder . defaultAbiCoder ( ) . decode ( assertionEvents [ eIndex ] . params , event . data )
317- const testEvent = [ ...testEventArray ] // Make it mutable
318- if ( ! testEvent [ 0 ] ) {
319- const assertMethod = testEvent [ 2 ]
320- if ( assertMethod === 'ok' ) { // for 'Assert.ok' method
321- testEvent [ 3 ] = 'false'
322- testEvent [ 4 ] = 'true'
323- }
324- const location = getAssertMethodLocation ( fileAST , testName , func . name , assertMethod )
325- const resp : TestResultInterface = {
326- type : 'testFailure' ,
327- value : changeCase . sentenceCase ( func . name ) ,
328- filename : testObject . filename ,
329- time : time ,
330- errMsg : testEvent [ 1 ] ,
331- context : testName ,
332- assertMethod,
333- returned : testEvent [ 3 ] ,
334- expected : testEvent [ 4 ] ,
335- location,
336- provider,
337- debugTxHash
338- }
339- if ( hhLogs && hhLogs . length ) resp . hhLogs = hhLogs
340- testCallback ( undefined , resp )
341- failureNum += 1
342- timePassed += time
343- return next ( )
344- }
345- testPassed = true
346- }
347- }
348- }
349-
350- if ( testPassed ) {
351- const resp : TestResultInterface = {
352- type : 'testPass' ,
353- value : changeCase . sentenceCase ( func . name ) ,
354- filename : testObject . filename ,
355- time : time ,
356- context : testName ,
357- provider,
358- debugTxHash
359- }
360- if ( hhLogs && hhLogs . length ) resp . hhLogs = hhLogs
361- testCallback ( undefined , resp )
362- passingNum += 1
363- timePassed += time
364- } else if ( hhLogs && hhLogs . length ) {
365- const resp : TestResultInterface = {
366- type : 'logOnly' ,
367- value : changeCase . sentenceCase ( func . name ) ,
368- filename : testObject . filename ,
369- time : time ,
370- context : testName ,
371- hhLogs
372- }
373- testCallback ( undefined , resp )
374- timePassed += time
375- }
376377
377- return next ( )
378- } catch ( err ) {
378+ return
379+ } catch ( err ) {
380+ if ( ! err . receipt ) {
379381 console . error ( err )
380- return next ( err )
382+ return
381383 }
382- } ) . catch ( async ( err ) => {
383384 const time : number = ( Date . now ( ) - startTime ) / 1000.0
384- if ( ! err . receipt || failedTransactions [ err . receipt . transactionHash ] ) return // we are already aware of this transaction failing.
385+ if ( failedTransactions [ err . receipt . transactionHash ] ) return // we are already aware of this transaction failing.
385386 failedTransactions [ err . receipt . transactionHash ] = time
386387 let errMsg = err . message
387388 let txHash
@@ -405,8 +406,8 @@ export function runTest (testName: string, testObject: any, contractDetails: Com
405406 testCallback ( undefined , resp )
406407 failureNum += 1
407408 timePassed += time
408- return next ( )
409- } )
409+ return
410+ }
410411 }
411412 } , function ( error ) {
412413 resultsCallback ( error , { passingNum, failureNum, timePassed } )
0 commit comments