Merge branch 'master' of github.com:ethereum/remix into remix-resolve

pull/7/head
0mkar 6 years ago
commit 88a8988a71
  1. 4
      remix-analyzer/package.json
  2. 6415
      remix-debug/compilation.json
  3. 4
      remix-debug/index.js
  4. 8
      remix-debug/package.json
  5. 108
      remix-debug/rdb.js
  6. 1
      remix-debug/src/Ethdebugger.js
  7. 60
      remix-debug/src/cmdline/contextManager.js
  8. 215
      remix-debug/src/cmdline/index.js
  9. 10
      remix-debug/src/debugger/VmDebugger.js
  10. 8
      remix-debug/src/debugger/debugger.js
  11. 2
      remix-debug/src/debugger/solidityLocals.js
  12. 6
      remix-debug/src/debugger/solidityState.js
  13. 73
      remix-debug/src/debugger/stepManager.js
  14. 5
      remix-debug/src/solidity-decoder/internalCallTree.js
  15. 2
      remix-debug/src/solidity-decoder/solidityProxy.js
  16. 65
      remix-debug/test/sol/ballot.sol
  17. 22
      remix-debug/test/sol/simple_storage.sol
  18. 2
      remix-lib/index.js
  19. 2
      remix-lib/package.json
  20. 1
      remix-lib/src/code/codeResolver.js
  21. 32
      remix-lib/src/offsetToLineColumnConverter.js
  22. 2
      remix-lib/src/trace/traceManager.js
  23. 5
      remix-lib/test/txFormat.js
  24. 4
      remix-simulator/package.json
  25. 4
      remix-solidity/package.json
  26. 8
      remix-tests/package.json
  27. 26
      remix-tests/src/compiler.js
  28. 20
      remix-tests/src/fs.js
  29. 234
      remix-tests/src/index.js
  30. 133
      remix-tests/src/runTestFiles.js
  31. 107
      remix-tests/src/runTestSources.js
  32. 4
      remix-tests/tests/examples_3/simple_string_test.sol
  33. 20
      remix-tests/tests/testRunner.js

@ -1,6 +1,6 @@
{ {
"name": "remix-analyzer", "name": "remix-analyzer",
"version": "0.2.13", "version": "0.3.1",
"description": "Remix Analyzer", "description": "Remix Analyzer",
"main": "./index.js", "main": "./index.js",
"contributors": [ "contributors": [
@ -18,7 +18,7 @@
} }
], ],
"dependencies": { "dependencies": {
"remix-lib": "0.3.13" "remix-lib": "0.4.1"
}, },
"scripts": { "scripts": {
"lint": "standard", "lint": "standard",

File diff suppressed because one or more lines are too long

@ -1,6 +1,7 @@
'use strict' 'use strict'
var EthDebugger = require('./src/Ethdebugger') var EthDebugger = require('./src/Ethdebugger')
var TransactionDebugger = require('./src/debugger/debugger') var TransactionDebugger = require('./src/debugger/debugger')
var CmdLine = require('./src/cmdline')
var StorageViewer = require('./src/storage/storageViewer') var StorageViewer = require('./src/storage/storageViewer')
var StorageResolver = require('./src/storage/storageResolver') var StorageResolver = require('./src/storage/storageResolver')
@ -32,6 +33,7 @@ module.exports = {
storage: { storage: {
StorageViewer: StorageViewer, StorageViewer: StorageViewer,
StorageResolver: StorageResolver StorageResolver: StorageResolver
} },
CmdLine: CmdLine
} }

@ -1,6 +1,6 @@
{ {
"name": "remix-debug", "name": "remix-debug",
"version": "0.2.14", "version": "0.3.1",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
@ -10,6 +10,10 @@
{ {
"name": "Liana Husikyan", "name": "Liana Husikyan",
"email": "liana@ethdev.com" "email": "liana@ethdev.com"
},
{
"name": "Iuri Matias",
"email": "iuri.matias@gmail.com"
} }
], ],
"main": "./index.js", "main": "./index.js",
@ -17,7 +21,7 @@
"ethereumjs-util": "^4.5.0", "ethereumjs-util": "^4.5.0",
"ethereumjs-vm": "2.4.0", "ethereumjs-vm": "2.4.0",
"fast-async": "^6.1.2", "fast-async": "^6.1.2",
"remix-lib": "0.3.13" "remix-lib": "0.4.1"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^7.1.1", "babel-eslint": "^7.1.1",

@ -0,0 +1,108 @@
var CmdLine = require('./src/cmdline/index.js')
// var compilation = require('./compilation.json')
var solc = require('solc')
var fs = require('fs')
var filename = 'test/sol/simple_storage.sol'
var shortFilename = 'simple_storage.sol'
var inputJson = {
language: 'Solidity',
sources: {
},
settings: {
optimizer: {
enabled: true,
runs: 200
},
outputSelection: {
'*': {
'': [ 'legacyAST' ],
'*': [ 'abi', 'metadata', 'devdoc', 'userdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates' ]
}
}
}
}
inputJson.sources[shortFilename] = {content: fs.readFileSync(filename).toString()}
console.dir(inputJson)
console.log('compiling...')
let compilationData = JSON.parse(solc.compileStandardWrapper(JSON.stringify(inputJson)))
console.dir(Object.keys(compilationData))
var compilation = {}
compilation.data = compilationData
compilation.source = { sources: inputJson.sources }
console.dir(compilation)
console.dir(compilation.data.errors)
var cmdLine = new CmdLine()
cmdLine.connect('http', 'http://localhost:8545')
cmdLine.loadCompilationResult(compilation)
cmdLine.initDebugger()
// var deployContract = function (cb) {
// let _web3 = cmdLine.debugger.debugger.web3
//
// let blockNumber = null
// let txNumber = null
// let tx = null
//
// let code = compilation.data.contracts[shortFilename].SimpleStorage.evm.bytecode.object
// console.dir('deploying...')
// console.dir(code)
// _web3.eth.sendTransaction({data: '0x' + code, from: _web3.eth.accounts[0], gas: 800000}, cb)
// }
// let _web3 = cmdLine.debugger.debugger.web3
var tx = '0xf510c4f0b1d9ee262d7b9e9e87b4262f275fe029c2c733feef7dfa1e2b1e32aa'
// deployContract((err, tx) => {
cmdLine.startDebug(tx, shortFilename)
cmdLine.events.on('source', () => {
cmdLine.getSource().forEach(console.dir)
})
// })
// })
const repl = require('repl')
repl.start({
prompt: '> ',
eval: (cmd, context, filename, cb) => {
let command = cmd.trim()
if (command === 'next' || command === 'n') {
cmdLine.stepOverForward(true)
}
if (command === 'previous' || command === 'p' || command === 'prev') {
cmdLine.stepOverBack(true)
}
if (command === 'step' || command === 's') {
cmdLine.stepIntoForward(true)
}
if (command === 'stepback' || command === 'sb') {
cmdLine.stepIntoBack(true)
}
if (command === 'exit' || command === 'quit') {
process.exit(0)
}
if (command === 'var local' || command === 'v l' || command === 'vl') {
cmdLine.displayLocals()
}
if (command === 'var global' || command === 'v g' || command === 'vg') {
cmdLine.displayGlobals()
}
if (command.split(' ')[0] === 'jump') {
let stepIndex = parseInt(command.split(' ')[1], 10)
cmdLine.jumpTo(stepIndex)
}
cb(null, '')
}
})
module.exports = cmdLine

@ -183,7 +183,6 @@ Ethdebugger.prototype.debug = function (tx) {
tx.to = traceHelper.contractCreationToken('0') tx.to = traceHelper.contractCreationToken('0')
} }
this.setCompilationResult(this.opts.compilationResult()) this.setCompilationResult(this.opts.compilationResult())
console.log('loading trace...')
this.tx = tx this.tx = tx
var self = this var self = this
this.traceManager.resolveTrace(tx, function (error, result) { this.traceManager.resolveTrace(tx, function (error, result) {

@ -0,0 +1,60 @@
var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager
var executionContext = remixLib.execution.executionContext
var Web3Providers = remixLib.vm.Web3Providers
var DummyProvider = remixLib.vm.DummyProvider
var init = remixLib.init
class ContextManager {
constructor () {
this.executionContext = executionContext
this.web3 = this.executionContext.web3()
this.event = new EventManager()
}
initProviders () {
this.web3Providers = new Web3Providers()
this.addProvider('DUMMYWEB3', new DummyProvider())
this.switchProvider('DUMMYWEB3')
this.addProvider('vm', this.executionContext.vm())
this.addProvider('injected', this.executionContext.internalWeb3())
this.addProvider('web3', this.executionContext.internalWeb3())
this.switchProvider(this.executionContext.getProvider())
}
getWeb3 () {
return this.web3
}
addProvider (type, obj) {
this.web3Providers.addProvider(type, obj)
this.event.trigger('providerAdded', [type])
}
switchProvider (type, cb) {
var self = this
this.web3Providers.get(type, function (error, obj) {
if (error) {
// console.log('provider ' + type + ' not defined')
} else {
self.web3 = obj
self.executionContext.detectNetwork((error, network) => {
if (error || !network) {
self.web3 = obj
} else {
var webDebugNode = init.web3DebugNode(network.name)
self.web3 = (!webDebugNode ? obj : webDebugNode)
}
self.event.trigger('providerChanged', [type, self.web3])
if (cb) return cb()
})
self.event.trigger('providerChanged', [type, self.web3])
}
})
}
}
module.exports = ContextManager

@ -0,0 +1,215 @@
var Web3 = require('web3')
var Debugger = require('../debugger/debugger.js')
var ContextManager = require('./contextManager.js')
var EventManager = require('events')
class CmdLine {
constructor () {
this.events = new EventManager()
this.lineColumnPos = null
this.rawLocation = null
}
connect (providerType, url) {
if (providerType !== 'http') throw new Error('unsupported provider type')
this.web3 = new Web3(new Web3.providers.HttpProvider(url))
}
loadCompilationData (inputJson, outputJson) {
let data = {}
data.data = outputJson
data.source = { sources: inputJson.sources }
this.loadCompilationResult(data)
}
loadCompilationResult (compilationResult) {
this.compilation = {}
this.compilation.lastCompilationResult = compilationResult
}
initDebugger (cb) {
const self = this
this.contextManager = new ContextManager()
this.debugger = new Debugger({
web3: this.contextManager.getWeb3(),
compiler: this.compilation
})
this.contextManager.event.register('providerChanged', () => {
self.debugger.updateWeb3(self.contextManager.getWeb3())
})
this.contextManager.initProviders()
this.contextManager.addProvider('debugger_web3', this.web3)
this.contextManager.switchProvider('debugger_web3', cb)
}
getSource () {
const self = this
let lineColumnPos = this.lineColumnPos
if (!lineColumnPos || !lineColumnPos.start) return []
let content = self.compilation.lastCompilationResult.source.sources[this.filename].content.split('\n')
let source = []
let line
line = content[lineColumnPos.start.line - 2]
if (line !== undefined) {
source.push(' ' + (lineColumnPos.start.line - 1) + ': ' + line)
}
line = content[lineColumnPos.start.line - 1]
if (line !== undefined) {
source.push(' ' + lineColumnPos.start.line + ': ' + line)
}
let currentLineNumber = lineColumnPos.start.line
let currentLine = content[currentLineNumber]
source.push('=> ' + (currentLineNumber + 1) + ': ' + currentLine)
let startLine = lineColumnPos.start.line
for (var i = 1; i < 4; i++) {
let line = content[startLine + i]
source.push(' ' + (startLine + i + 1) + ': ' + line)
}
return source
}
getCurrentLine () {
let lineColumnPos = this.lineColumnPos
if (!lineColumnPos) return ''
let currentLineNumber = lineColumnPos.start.line
let content = this.compilation.lastCompilationResult.source.sources[this.filename].content.split('\n')
return content[currentLineNumber]
}
startDebug (txNumber, filename, cb) {
const self = this
this.filename = filename
this.txHash = txNumber
this.debugger.debug(null, txNumber, null, () => {
self.debugger.event.register('newSourceLocation', function (lineColumnPos, rawLocation) {
self.lineColumnPos = lineColumnPos
self.rawLocation = rawLocation
self.events.emit('source', [lineColumnPos, rawLocation])
})
self.debugger.vmDebuggerLogic.event.register('solidityState', (data) => {
self.solidityState = data
self.events.emit('globals', data)
})
// TODO: this doesnt work too well, it should request the data instead...
self.debugger.vmDebuggerLogic.event.register('solidityLocals', (data) => {
if (JSON.stringify(data) === '{}') return
self.solidityLocals = data
self.events.emit('locals', data)
})
if (cb) {
// TODO: this should be an onReady event
setTimeout(cb, 1000)
}
})
}
getVars () {
return {
locals: this.solidityLocals,
contract: this.solidityState
}
}
triggerSourceUpdate () {
this.events.emit('source', [this.lineColumnPos, this.rawLocation])
}
stepJumpNextBreakpoint () {
this.debugger.step_manager.jumpNextBreakpoint()
}
stepJumpPreviousBreakpoint () {
this.debugger.step_manager.jumpPreviousBreakpoint()
}
stepOverForward (solidityMode) {
this.debugger.step_manager.stepOverForward(solidityMode)
}
stepOverBack (solidityMode) {
this.debugger.step_manager.stepOverBack(solidityMode)
}
stepIntoForward (solidityMode) {
this.debugger.step_manager.stepIntoForward(solidityMode)
}
stepIntoBack (solidityMode) {
this.debugger.step_manager.stepIntoBack(solidityMode)
}
jumpTo (step) {
this.debugger.step_manager.jumpTo(step)
}
getTraceLength () {
if (!this.debugger.step_manager) return 0
return this.debugger.step_manager.traceLength
}
getCodeFirstStep () {
if (!this.debugger.step_manager) return 0
return this.debugger.step_manager.calculateFirstStep()
}
getCodeTraceLength () {
if (!this.debugger.step_manager) return 0
return this.debugger.step_manager.calculateCodeLength()
}
nextStep () {
if (!this.debugger.step_manager) return 0
return this.debugger.step_manager.nextStep()
}
previousStep () {
if (!this.debugger.step_manager) return 0
return this.debugger.step_manager.previousStep()
}
currentStep () {
if (!this.debugger.step_manager) return 0
return this.debugger.step_manager.currentStepIndex
}
canGoNext () {
return this.currentStep() < this.getCodeTraceLength()
}
canGoPrevious () {
return this.currentStep() > this.getCodeFirstStep()
}
unload () {
return this.debugger.unload()
}
displayLocals () {
console.dir('= displayLocals')
console.dir(this.solidityLocals)
}
displayGlobals () {
console.dir('= displayGlobals')
console.dir(this.solidityState)
}
}
module.exports = CmdLine

@ -64,7 +64,7 @@ class VmDebuggerLogic {
self._traceManager.getCallDataAt(index, function (error, calldata) { self._traceManager.getCallDataAt(index, function (error, calldata) {
if (error) { if (error) {
console.log(error) // console.log(error)
self.event.trigger('traceManagerCallDataUpdate', [{}]) self.event.trigger('traceManagerCallDataUpdate', [{}])
} else if (self.stepManager.currentStepIndex === index) { } else if (self.stepManager.currentStepIndex === index) {
self.event.trigger('traceManagerCallDataUpdate', [calldata]) self.event.trigger('traceManagerCallDataUpdate', [calldata])
@ -73,7 +73,7 @@ class VmDebuggerLogic {
self._traceManager.getMemoryAt(index, function (error, memory) { self._traceManager.getMemoryAt(index, function (error, memory) {
if (error) { if (error) {
console.log(error) // console.log(error)
self.event.trigger('traceManagerMemoryUpdate', [{}]) self.event.trigger('traceManagerMemoryUpdate', [{}])
} else if (self.stepManager.currentStepIndex === index) { } else if (self.stepManager.currentStepIndex === index) {
self.event.trigger('traceManagerMemoryUpdate', [ui.formatMemory(memory, 16)]) self.event.trigger('traceManagerMemoryUpdate', [ui.formatMemory(memory, 16)])
@ -82,7 +82,7 @@ class VmDebuggerLogic {
self._traceManager.getCallStackAt(index, function (error, callstack) { self._traceManager.getCallStackAt(index, function (error, callstack) {
if (error) { if (error) {
console.log(error) // console.log(error)
self.event.trigger('traceManagerCallStackUpdate', [{}]) self.event.trigger('traceManagerCallStackUpdate', [{}])
} else if (self.stepManager.currentStepIndex === index) { } else if (self.stepManager.currentStepIndex === index) {
self.event.trigger('traceManagerCallStackUpdate', [callstack]) self.event.trigger('traceManagerCallStackUpdate', [callstack])
@ -91,7 +91,7 @@ class VmDebuggerLogic {
self._traceManager.getStackAt(index, function (error, callstack) { self._traceManager.getStackAt(index, function (error, callstack) {
if (error) { if (error) {
console.log(error) // console.log(error)
self.event.trigger('traceManagerStackUpdate', [{}]) self.event.trigger('traceManagerStackUpdate', [{}])
} else if (self.stepManager.currentStepIndex === index) { } else if (self.stepManager.currentStepIndex === index) {
self.event.trigger('traceManagerStackUpdate', [callstack]) self.event.trigger('traceManagerStackUpdate', [callstack])
@ -106,7 +106,7 @@ class VmDebuggerLogic {
storageViewer.storageRange((error, storage) => { storageViewer.storageRange((error, storage) => {
if (error) { if (error) {
console.log(error) // console.log(error)
self.event.trigger('traceManagerStorageUpdate', [{}]) self.event.trigger('traceManagerStorageUpdate', [{}])
} else if (self.stepManager.currentStepIndex === index) { } else if (self.stepManager.currentStepIndex === index) {
var header = storageViewer.isComplete(address) ? 'completely loaded' : 'partially loaded...' var header = storageViewer.isComplete(address) ? 'completely loaded' : 'partially loaded...'

@ -3,6 +3,7 @@ var Ethdebugger = require('../Ethdebugger')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
var OffsetToColumnConverter = remixLib.OffsetToColumnConverter
var StepManager = require('./stepManager') var StepManager = require('./stepManager')
var VmDebuggerLogic = require('./VmDebugger') var VmDebuggerLogic = require('./VmDebugger')
@ -11,7 +12,7 @@ function Debugger (options) {
var self = this var self = this
this.event = new EventManager() this.event = new EventManager()
this.offsetToLineColumnConverter = options.offsetToLineColumnConverter this.offsetToLineColumnConverter = options.offsetToLineColumnConverter || (new OffsetToColumnConverter())
this.compiler = options.compiler this.compiler = options.compiler
this.debugger = new Ethdebugger({ this.debugger = new Ethdebugger({
@ -111,8 +112,13 @@ Debugger.prototype.debugTx = function (tx, loadingCb) {
}) })
this.vmDebuggerLogic = new VmDebuggerLogic(this.debugger, tx, this.step_manager, this.debugger.traceManager, this.debugger.codeManager, this.debugger.solidityProxy, this.debugger.callTree) this.vmDebuggerLogic = new VmDebuggerLogic(this.debugger, tx, this.step_manager, this.debugger.traceManager, this.debugger.codeManager, this.debugger.solidityProxy, this.debugger.callTree)
this.vmDebuggerLogic.start()
this.step_manager.event.register('stepChanged', this, function (stepIndex) { this.step_manager.event.register('stepChanged', this, function (stepIndex) {
if (!stepIndex) {
return self.event.trigger('endDebug')
}
self.debugger.codeManager.resolveStep(stepIndex, tx) self.debugger.codeManager.resolveStep(stepIndex, tx)
self.step_manager.event.trigger('indexChanged', [stepIndex]) self.step_manager.event.trigger('indexChanged', [stepIndex])
self.vmDebuggerLogic.event.trigger('indexChanged', [stepIndex]) self.vmDebuggerLogic.event.trigger('indexChanged', [stepIndex])

@ -40,7 +40,7 @@ class DebuggerSolidityLocals {
self.stepManager.currentStepIndex, self.stepManager.currentStepIndex,
(error, result) => { (error, result) => {
if (error) { if (error) {
return console.log(error) return error
} }
var stack = result[0].value var stack = result[0].value
var memory = result[1].value var memory = result[1].value

@ -36,7 +36,13 @@ class DebuggerSolidityState {
} }
self.event.trigger('solidityStateUpdating') self.event.trigger('solidityStateUpdating')
decodeTimeout = setTimeout(function () { decodeTimeout = setTimeout(function () {
// necessary due to some states that can crash the debugger
try {
self.decode(index) self.decode(index)
} catch (err) {
console.dir('====> error')
console.dir(err)
}
}, 500) }, 500)
} }

@ -1,5 +1,6 @@
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var util = remixLib.util
class DebuggerStepManager { class DebuggerStepManager {
@ -9,6 +10,7 @@ class DebuggerStepManager {
this.traceManager = traceManager this.traceManager = traceManager
this.currentStepIndex = 0 this.currentStepIndex = 0
this.traceLength = 0 this.traceLength = 0
this.codeTraceLength = 0
this.revertionPoint = null this.revertionPoint = null
this.listenToEvents() this.listenToEvents()
@ -25,6 +27,7 @@ class DebuggerStepManager {
if (self.traceLength !== newLength) { if (self.traceLength !== newLength) {
self.event.trigger('traceLengthChanged', [newLength]) self.event.trigger('traceLengthChanged', [newLength])
self.traceLength = newLength self.traceLength = newLength
self.codeTraceLength = self.calculateCodeLength()
} }
self.jumpTo(0) self.jumpTo(0)
}) })
@ -81,43 +84,58 @@ class DebuggerStepManager {
}) })
} }
stepIntoBack () { stepIntoBack (solidityMode) {
if (!this.traceManager.isLoaded()) return if (!this.traceManager.isLoaded()) return
var step = this.currentStepIndex - 1 var step = this.currentStepIndex - 1
this.currentStepIndex = step this.currentStepIndex = step
if (solidityMode) {
step = this.resolveToReducedTrace(step, -1)
}
if (!this.traceManager.inRange(step)) { if (!this.traceManager.inRange(step)) {
return return
} }
this.event.trigger('stepChanged', [step]) this.event.trigger('stepChanged', [step])
} }
stepIntoForward () { stepIntoForward (solidityMode) {
if (!this.traceManager.isLoaded()) return if (!this.traceManager.isLoaded()) return
var step = this.currentStepIndex + 1 var step = this.currentStepIndex + 1
this.currentStepIndex = step this.currentStepIndex = step
if (solidityMode) {
step = this.resolveToReducedTrace(step, 1)
}
if (!this.traceManager.inRange(step)) { if (!this.traceManager.inRange(step)) {
return return
} }
this.event.trigger('stepChanged', [step]) this.event.trigger('stepChanged', [step])
} }
stepOverBack () { stepOverBack (solidityMode) {
if (!this.traceManager.isLoaded()) return if (!this.traceManager.isLoaded()) return
var step = this.traceManager.findStepOverBack(this.currentStepIndex) var step = this.traceManager.findStepOverBack(this.currentStepIndex)
if (solidityMode) {
step = this.resolveToReducedTrace(step, -1)
}
this.currentStepIndex = step this.currentStepIndex = step
this.event.trigger('stepChanged', [step]) this.event.trigger('stepChanged', [step])
} }
stepOverForward () { stepOverForward (solidityMode) {
if (!this.traceManager.isLoaded()) return if (!this.traceManager.isLoaded()) return
var step = this.traceManager.findStepOverForward(this.currentStepIndex) var step = this.traceManager.findStepOverForward(this.currentStepIndex)
if (solidityMode) {
step = this.resolveToReducedTrace(step, 1)
}
this.currentStepIndex = step this.currentStepIndex = step
this.event.trigger('stepChanged', [step]) this.event.trigger('stepChanged', [step])
} }
jumpOut () { jumpOut (solidityMode) {
if (!this.traceManager.isLoaded()) return if (!this.traceManager.isLoaded()) return
var step = this.traceManager.findStepOut(this.currentStepIndex) var step = this.traceManager.findStepOut(this.currentStepIndex)
if (solidityMode) {
step = this.resolveToReducedTrace(step, 0)
}
this.currentStepIndex = step this.currentStepIndex = step
this.event.trigger('stepChanged', [step]) this.event.trigger('stepChanged', [step])
} }
@ -140,6 +158,51 @@ class DebuggerStepManager {
this.debugger.breakpointManager.jumpPreviousBreakpoint(this.currentStepIndex, true) this.debugger.breakpointManager.jumpPreviousBreakpoint(this.currentStepIndex, true)
} }
calculateFirstStep () {
let step = this.resolveToReducedTrace(0, 1)
return this.resolveToReducedTrace(step, 1)
}
calculateCodeStepList () {
let step = 0
let steps = []
while (step < this.traceLength) {
let _step = this.resolveToReducedTrace(step, 1)
if (!_step) break
steps.push(_step)
step += 1
}
steps = steps.filter((item, pos, self) => { return steps.indexOf(item) === pos })
return steps
}
calculateCodeLength () {
this.calculateCodeStepList().reverse()
return this.calculateCodeStepList().reverse()[1] || this.traceLength
}
nextStep () {
return this.resolveToReducedTrace(this.currentStepIndex, 1)
}
previousStep () {
return this.resolveToReducedTrace(this.currentStepIndex, -1)
}
resolveToReducedTrace (value, incr) {
if (this.debugger.callTree.reducedTrace.length) {
var nextSource = util.findClosestIndex(value, this.debugger.callTree.reducedTrace)
nextSource = nextSource + incr
if (nextSource <= 0) {
nextSource = 0
} else if (nextSource > this.debugger.callTree.reducedTrace.length) {
nextSource = this.debugger.callTree.reducedTrace.length - 1
}
return this.debugger.callTree.reducedTrace[nextSource]
}
return value
}
} }
module.exports = DebuggerStepManager module.exports = DebuggerStepManager

@ -38,7 +38,6 @@ class InternalCallTree {
if (result.error) { if (result.error) {
this.event.trigger('callTreeBuildFailed', [result.error]) this.event.trigger('callTreeBuildFailed', [result.error])
} else { } else {
console.log('ready')
createReducedTrace(this, traceManager.trace.length - 1) createReducedTrace(this, traceManager.trace.length - 1)
this.event.trigger('callTreeReady', [this.scopes, this.scopeStarts]) this.event.trigger('callTreeReady', [this.scopes, this.scopeStarts])
} }
@ -230,7 +229,7 @@ function resolveVariableDeclaration (tree, step, sourceLocation) {
if (ast) { if (ast) {
tree.variableDeclarationByFile[sourceLocation.file] = extractVariableDeclarations(ast, tree.astWalker) tree.variableDeclarationByFile[sourceLocation.file] = extractVariableDeclarations(ast, tree.astWalker)
} else { } else {
console.log('Ast not found for step ' + step + '. file ' + sourceLocation.file) // console.log('Ast not found for step ' + step + '. file ' + sourceLocation.file)
return null return null
} }
} }
@ -243,7 +242,7 @@ function resolveFunctionDefinition (tree, step, sourceLocation) {
if (ast) { if (ast) {
tree.functionDefinitionByFile[sourceLocation.file] = extractFunctionDefinitions(ast, tree.astWalker) tree.functionDefinitionByFile[sourceLocation.file] = extractFunctionDefinitions(ast, tree.astWalker)
} else { } else {
console.log('Ast not found for step ' + step + '. file ' + sourceLocation.file) // console.log('Ast not found for step ' + step + '. file ' + sourceLocation.file)
return null return null
} }
} }

@ -117,7 +117,7 @@ class SolidityProxy {
if (this.sources[file]) { if (this.sources[file]) {
return this.sources[file].legacyAST return this.sources[file].legacyAST
} else { } else {
console.log('AST not found for file id ' + sourceLocation.file) // console.log('AST not found for file id ' + sourceLocation.file)
return null return null
} }
} }

@ -0,0 +1,65 @@
pragma solidity ^0.4.0;
contract Ballot {
struct Voter {
uint weight;
bool voted;
uint8 vote;
address delegate;
}
struct Proposal {
uint voteCount;
}
address chairperson;
mapping(address => Voter) voters;
Proposal[] proposals;
/// Create a new ballot with $(_numProposals) different proposals.
function Ballot(uint8 _numProposals) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
proposals.length = _numProposals;
}
/// Give $(toVoter) the right to vote on this ballot.
/// May only be called by $(chairperson).
function giveRightToVote(address toVoter) public {
if (msg.sender != chairperson || voters[toVoter].voted) return;
voters[toVoter].weight = 1;
}
/// Delegate your vote to the voter $(to).
function delegate(address to) public {
Voter storage sender = voters[msg.sender]; // assigns reference
if (sender.voted) return;
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
to = voters[to].delegate;
if (to == msg.sender) return;
sender.voted = true;
sender.delegate = to;
Voter storage delegateTo = voters[to];
if (delegateTo.voted)
proposals[delegateTo.vote].voteCount += sender.weight;
else
delegateTo.weight += sender.weight;
}
/// Give a single vote to proposal $(toProposal).
function vote(uint8 toProposal) public {
Voter storage sender = voters[msg.sender];
if (sender.voted || toProposal >= proposals.length) return;
sender.voted = true;
sender.vote = toProposal;
proposals[toProposal].voteCount += sender.weight;
}
function winningProposal() public constant returns (uint8 _winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 prop = 0; prop < proposals.length; prop++)
if (proposals[prop].voteCount > winningVoteCount) {
winningVoteCount = proposals[prop].voteCount;
_winningProposal = prop;
}
}
}

@ -0,0 +1,22 @@
pragma solidity ^0.4.25;
contract SimpleStorage {
uint public storedData;
address owner;
constructor(uint initialValue) public {
storedData = initialValue;
owner = msg.sender;
}
function set(uint x) public {
storedData = x;
require(msg.sender != owner);
storedData = x + 2;
}
function get() public view returns (uint retVal) {
return storedData;
}
}

@ -5,6 +5,7 @@ var uiHelper = require('./src/helpers/uiHelper')
var compilerHelper = require('./src/helpers/compilerHelper') var compilerHelper = require('./src/helpers/compilerHelper')
var SourceMappingDecoder = require('./src/sourceMappingDecoder') var SourceMappingDecoder = require('./src/sourceMappingDecoder')
var SourceLocationTracker = require('./src/sourceLocationTracker') var SourceLocationTracker = require('./src/sourceLocationTracker')
var OffsetToColumnConverter = require('./src/offsetToLineColumnConverter')
var init = require('./src/init') var init = require('./src/init')
var util = require('./src/util') var util = require('./src/util')
var Web3Providers = require('./src/web3Provider/web3Providers') var Web3Providers = require('./src/web3Provider/web3Providers')
@ -56,6 +57,7 @@ function modules () {
}, },
SourceMappingDecoder: SourceMappingDecoder, SourceMappingDecoder: SourceMappingDecoder,
SourceLocationTracker: SourceLocationTracker, SourceLocationTracker: SourceLocationTracker,
OffsetToColumnConverter: OffsetToColumnConverter,
Storage: Storage, Storage: Storage,
init: init, init: init,
util: util, util: util,

@ -1,6 +1,6 @@
{ {
"name": "remix-lib", "name": "remix-lib",
"version": "0.3.13", "version": "0.4.1",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {

@ -29,7 +29,6 @@ CodeResolver.prototype.resolveCode = function (address, callBack) {
} }
CodeResolver.prototype.loadCode = function (address, callback) { CodeResolver.prototype.loadCode = function (address, callback) {
console.log('loading new code from web3 ' + address)
this.web3.eth.getCode(address, function (error, result) { this.web3.eth.getCode(address, function (error, result) {
if (error) { if (error) {
console.log(error) console.log(error)

@ -0,0 +1,32 @@
'use strict'
var SourceMappingDecoder = require('./sourceMappingDecoder')
function offsetToColumnConverter (compilerEvent) {
this.lineBreakPositionsByContent = {}
this.sourceMappingDecoder = new SourceMappingDecoder()
var self = this
if (compilerEvent) {
compilerEvent.register('compilationFinished', function (success, data, source) {
self.clear()
})
}
}
offsetToColumnConverter.prototype.offsetToLineColumn = function (rawLocation, file, sources, asts) {
if (!this.lineBreakPositionsByContent[file]) {
for (var filename in asts) {
var source = asts[filename]
if (source.id === file) {
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content)
break
}
}
}
return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
}
offsetToColumnConverter.prototype.clear = function () {
this.lineBreakPositionsByContent = {}
}
module.exports = offsetToColumnConverter

@ -120,7 +120,7 @@ TraceManager.prototype.getStackAt = function (stepIndex, callback) {
return callback(check, null) return callback(check, null)
} }
var stack var stack
if (this.trace[stepIndex].stack) { // there's always a stack if (this.trace[stepIndex] && this.trace[stepIndex].stack) { // there's always a stack
stack = this.trace[stepIndex].stack.slice(0) stack = this.trace[stepIndex].stack.slice(0)
stack.reverse() stack.reverse()
callback(null, stack) callback(null, stack)

@ -15,7 +15,8 @@ tape('ContractParameters - (TxFormat.buildData) - format input parameters', func
output = JSON.parse(output) output = JSON.parse(output)
var contract = output.contracts['test.sol']['uintContractTest'] var contract = output.contracts['test.sol']['uintContractTest']
context = { output, contract } context = { output, contract }
var bytecode = '608060405234801561001057600080fd5b5061011e806100206000396000f3fe608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634b521953146044575b600080fd5b348015604f57600080fd5b5060a360048036036060811015606457600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505060a5565b005b8260008190555081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505056fea165627a7a7230582053a6bee96a62b9079722b2a0004a405aa29803abc12ed6dd0322007ebb44a5f60029' var bytecode = '608060405234801561001057600080fd5b50610118806100206000396000f3fe6080604052348015600f57600080fd5b50600436106045576000357c0100000000000000000000000000000000000000000000000000000000900480634b52195314604a575b600080fd5b609d60048036036060811015605e57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050609f565b005b8260008190555081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505056fea165627a7a723058201ef20c1b8cb426610dbcf2fd6ff80b99cee4cbf63c1af4e26c951310ff7233c70029'
t.test('(TxFormat.buildData)', function (st) { t.test('(TxFormat.buildData)', function (st) {
st.plan(3) st.plan(3)
testWithInput(st, '123123, "0xf7a10e525d4b168f45f74db1b61f63d3e7619ea8", "34"', bytecode + '000000000000000000000000000000000000000000000000000000000001e0f3000000000000000000000000f7a10e525d4b168f45f74db1b61f63d3e7619ea80000000000000000000000000000000000000000000000000000000000000022') testWithInput(st, '123123, "0xf7a10e525d4b168f45f74db1b61f63d3e7619ea8", "34"', bytecode + '000000000000000000000000000000000000000000000000000000000001e0f3000000000000000000000000f7a10e525d4b168f45f74db1b61f63d3e7619ea80000000000000000000000000000000000000000000000000000000000000022')
@ -97,7 +98,7 @@ function testLinkLibrary2 (st, callbackDeployLibraries) {
} }
} }
var data = '608060405234801561001057600080fd5b5061026b806100206000396000f3fe608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c14610046575b600080fd5b34801561005257600080fd5b5061005b61005d565b005b73f7a10e525d4b168f45f74db1b61f63d3e7619e116344733ae16040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b1580156100bd57600080fd5b505af41580156100d1573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e336344733ae16040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b15801561013557600080fd5b505af4158015610149573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e336344733ae16040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b1580156101ad57600080fd5b505af41580156101c1573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e116344733ae16040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b15801561022557600080fd5b505af4158015610239573d6000803e3d6000fd5b5050505056fea165627a7a72305820d2fdcf2968ba13c89dd82748af1cac609a670e333fce635bc2212c2a50508be70029' var data = '608060405234801561001057600080fd5b50610265806100206000396000f3fe608060405234801561001057600080fd5b5060043610610048576000357c0100000000000000000000000000000000000000000000000000000000900480636d4ce63c1461004d575b600080fd5b610055610057565b005b73f7a10e525d4b168f45f74db1b61f63d3e7619e116344733ae16040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b1580156100b757600080fd5b505af41580156100cb573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e336344733ae16040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b15801561012f57600080fd5b505af4158015610143573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e336344733ae16040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b1580156101a757600080fd5b505af41580156101bb573d6000803e3d6000fd5b5050505073f7a10e525d4b168f45f74db1b61f63d3e7619e116344733ae16040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038186803b15801561021f57600080fd5b505af4158015610233573d6000803e3d6000fd5b5050505056fea165627a7a723058206775efae13f5e8ef63a78158d4c45f4eaa135657958a136d4e22968970f24aac0029'
var deployMsg = ['creation of library test.sol:lib1 pending...', var deployMsg = ['creation of library test.sol:lib1 pending...',
'creation of library test.sol:lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2 pending...'] 'creation of library test.sol:lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2_lib2 pending...']

@ -1,6 +1,6 @@
{ {
"name": "remix-simulator", "name": "remix-simulator",
"version": "0.0.8", "version": "0.1.1",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
@ -21,7 +21,7 @@
"express-ws": "^4.0.0", "express-ws": "^4.0.0",
"fast-async": "^6.3.7", "fast-async": "^6.3.7",
"merge": "^1.2.0", "merge": "^1.2.0",
"remix-lib": "0.3.13", "remix-lib": "0.4.1",
"time-stamp": "^2.0.0", "time-stamp": "^2.0.0",
"web3": "1.0.0-beta.27" "web3": "1.0.0-beta.27"
}, },

@ -1,6 +1,6 @@
{ {
"name": "remix-solidity", "name": "remix-solidity",
"version": "0.2.14", "version": "0.3.1",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
@ -17,7 +17,7 @@
"ethereumjs-util": "^4.5.0", "ethereumjs-util": "^4.5.0",
"ethereumjs-vm": "2.4.0", "ethereumjs-vm": "2.4.0",
"fast-async": "^6.1.2", "fast-async": "^6.1.2",
"remix-lib": "0.3.13", "remix-lib": "0.4.1",
"solc": "^0.5.0", "solc": "^0.5.0",
"webworkify": "^1.2.1" "webworkify": "^1.2.1"
}, },

@ -1,6 +1,6 @@
{ {
"name": "remix-tests", "name": "remix-tests",
"version": "0.0.21", "version": "0.1.1",
"description": "Tests for the Ethereum tool suite Remix", "description": "Tests for the Ethereum tool suite Remix",
"main": "./src/index.js", "main": "./src/index.js",
"contributors": [ "contributors": [
@ -40,9 +40,9 @@
"change-case": "^3.0.1", "change-case": "^3.0.1",
"colors": "^1.1.2", "colors": "^1.1.2",
"commander": "^2.13.0", "commander": "^2.13.0",
"remix-lib": "0.3.13", "remix-lib": "0.4.1",
"remix-simulator": "0.0.8", "remix-simulator": "0.1.1",
"remix-solidity": "0.2.14", "remix-solidity": "0.3.1",
"signale": "^1.2.1", "signale": "^1.2.1",
"web3": "1.0.0-beta.36", "web3": "1.0.0-beta.36",
"winston": "^3.0.0" "winston": "^3.0.0"

@ -1,5 +1,5 @@
/* eslint no-extend-native: "warn" */ /* eslint no-extend-native: "warn" */
let fs = require('fs') let fs = require('./fs')
var async = require('async') var async = require('async')
var path = require('path') var path = require('path')
let RemixCompiler = require('remix-solidity').Compiler let RemixCompiler = require('remix-solidity').Compiler
@ -26,30 +26,37 @@ var isBrowser = !(typeof (window) === 'undefined' || userAgent.indexOf(' electro
// TODO: replace this with remix's own compiler code // TODO: replace this with remix's own compiler code
function compileFileOrFiles (filename, isDirectory, opts, cb) { function compileFileOrFiles (filename, isDirectory, opts, cb) {
let compiler, filepath let compiler
let accounts = opts.accounts || [] let accounts = opts.accounts || []
const sources = { const sources = {
'tests.sol': { content: require('../sol/tests.sol.js') }, 'tests.sol': { content: require('../sol/tests.sol.js') },
'remix_tests.sol': { content: require('../sol/tests.sol.js') }, 'remix_tests.sol': { content: require('../sol/tests.sol.js') },
'remix_accounts.sol': { content: writeTestAccountsContract(accounts) } '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 // TODO: for now assumes filepath dir contains all tests, later all this
// should be replaced with remix's & browser solidity compiler code // should be replaced with remix's & browser solidity compiler code
filepath = (isDirectory ? filename : path.dirname(filename))
fs.readdirSync(filepath).forEach(file => { // 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 // only process .sol files
if (file.split('.').pop() === 'sol') { if (foundpath.split('.').pop() === 'sol') {
let c = fs.readFileSync(path.join(filepath, file)).toString() let c = fs.readFileSync(foundpath).toString()
const s = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm const s = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm
let includeTestLibs = '\nimport \'remix_tests.sol\';\n' let includeTestLibs = '\nimport \'remix_tests.sol\';\n'
if (file.indexOf('_test.sol') > 0 && c.regexIndexOf(s) < 0) { if (foundpath.indexOf('_test.sol') > 0 && c.regexIndexOf(s) < 0) {
c = includeTestLibs.concat(c) c = includeTestLibs.concat(c)
} }
sources[file] = { content: c } sources[foundpath] = { content: c }
} }
}) })
} catch (e) {
throw e
} finally {
async.waterfall([ async.waterfall([
function loadCompiler (next) { function loadCompiler (next) {
compiler = new RemixCompiler() compiler = new RemixCompiler()
@ -72,6 +79,7 @@ function compileFileOrFiles (filename, isDirectory, opts, cb) {
} }
cb(err, result.contracts) cb(err, result.contracts)
}) })
}
} }
function compileContractSources (sources, importFileCb, opts, cb) { function compileContractSources (sources, importFileCb, opts, cb) {

@ -0,0 +1,20 @@
// 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,234 +1,6 @@
const async = require('async') const runTestFiles = require('./runTestFiles.js')
const path = require('path') const runTestSources = require('./runTestSources.js')
const fs = require('fs') const TestRunner = require('./testRunner.js')
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
}
var 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, { 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 = []
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)
}
var 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 = []
var 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.readdirSync(filepath).forEach(filename => {
gatherContractsFrom(filename)
})
} 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 = { module.exports = {
runTestFiles: runTestFiles, runTestFiles: runTestFiles,

@ -0,0 +1,133 @@
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,107 @@
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

@ -12,8 +12,8 @@ contract StringTest {
return Assert.equal(foo.get(), "Hello world!", "initial value is not correct"); return Assert.equal(foo.get(), "Hello world!", "initial value is not correct");
} }
function valueShouldNotBeHelloWorld() public returns (bool) { function valueShouldNotBeHelloWordl() public returns (bool) {
return Assert.notEqual(foo.get(), "Hello wordl!", "initial value is not correct"); return Assert.notEqual(foo.get(), "Hello wordl!", "value should not be hello world");
} }
function valueShouldBeHelloWorld() public returns (bool) { function valueShouldBeHelloWorld() public returns (bool) {

@ -47,7 +47,7 @@ describe('testRunner', function () {
results = _results results = _results
done() done()
} }
TestRunner.runTest('MyTest', contracts.MyTest, compilationData['simple_storage_test.sol']['MyTest'], { accounts }, testCallback, resultsCallback) TestRunner.runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], { accounts }, testCallback, resultsCallback)
}) })
}) })
@ -61,7 +61,7 @@ describe('testRunner', function () {
it('should returns 5 messages', function () { it('should returns 5 messages', function () {
assert.deepEqual(tests, [ assert.deepEqual(tests, [
{ type: 'contract', value: 'MyTest', filename: 'simple_storage_test.sol' }, { 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: '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: 'Should trigger one pass', time: 1, context: 'MyTest'},
{ type: 'testPass', value: 'Initial value should be100', time: 1, context: 'MyTest' }, { type: 'testPass', value: 'Initial value should be100', time: 1, context: 'MyTest' },
@ -83,7 +83,7 @@ describe('testRunner', function () {
results = _results results = _results
done() done()
} }
TestRunner.runTest('MyTest', contracts.MyTest, compilationData['simple_storage_test.sol']['MyTest'], { accounts }, testCallback, resultsCallback) TestRunner.runTest('MyTest', contracts.MyTest, compilationData[filename]['MyTest'], { accounts }, testCallback, resultsCallback)
}) })
}) })
@ -97,7 +97,7 @@ describe('testRunner', function () {
it('should returns 3 messages', function () { it('should returns 3 messages', function () {
assert.deepEqual(tests, [ assert.deepEqual(tests, [
{ type: 'contract', value: 'MyTest', filename: 'simple_storage_test.sol' }, { 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 be100', time: 1, context: 'MyTest' },
{ type: 'testPass', value: 'Initial value should be200', time: 1, context: 'MyTest' } { type: 'testPass', value: 'Initial value should be200', time: 1, context: 'MyTest' }
]) ])
@ -118,8 +118,8 @@ describe('testRunner', function () {
results = _results results = _results
done() done()
} }
TestRunner.runTest('StringTest', contracts.StringTest, compilationData['simple_string_test.sol']['StringTest'], { accounts }, testCallback, resultsCallback) TestRunner.runTest('StringTest', contracts.StringTest, compilationData[filename]['StringTest'], { accounts }, testCallback, resultsCallback)
TestRunner.runTest('StringTest2', contracts.StringTest2, compilationData['simple_string_test.sol']['StringTest2'], { accounts }, testCallback, resultsCallback) TestRunner.runTest('StringTest2', contracts.StringTest2, compilationData[filename]['StringTest2'], { accounts }, testCallback, resultsCallback)
}) })
}) })
@ -133,9 +133,9 @@ describe('testRunner', function () {
it('should returns 3 messages', function () { it('should returns 3 messages', function () {
assert.deepEqual(tests, [ assert.deepEqual(tests, [
{ type: 'contract', value: 'StringTest', filename: 'simple_string_test.sol' }, { 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: '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 world', time: 1, context: 'StringTest' }, { 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' }, { type: 'testPass', value: 'Initial value should be hello', time: 1, context: 'StringTest' },
]) ])
}) })
@ -155,7 +155,7 @@ describe('testRunner', function () {
results = _results results = _results
done() done()
} }
TestRunner.runTest('IntegerTest', contracts.IntegerTest, compilationData['number_test.sol']['IntegerTest'], { accounts }, testCallback, resultsCallback) TestRunner.runTest('IntegerTest', contracts.IntegerTest, compilationData[filename]['IntegerTest'], { accounts }, testCallback, resultsCallback)
}) })
}) })
@ -182,7 +182,7 @@ describe('testRunner', function () {
done() done()
} }
TestRunner.runTest('SenderTest', contracts.SenderTest, compilationData['sender_test.sol']['SenderTest'], { accounts }, testCallback, resultsCallback) TestRunner.runTest('SenderTest', contracts.SenderTest, compilationData[filename]['SenderTest'], { accounts }, testCallback, resultsCallback)
}) })
}) })

Loading…
Cancel
Save