diff --git a/.gitignore b/.gitignore index eddf24d1ff..2f9b6cc3d7 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ package-lock.json .tern-port TODO soljson.js +lerna-debug.log diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..dd7bf5c3ad --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "remixd"] + path = remixd + url = https://github.com/ethereum/remixd diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8db3013e25..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: node_js -node_js: - - stable -env: - - TEST_DIR=remix-lib - - TEST_DIR=remix-solidity - - TEST_DIR=remix-debug - - TEST_DIR=remix-tests - - TEST_DIR=remix-simulator -script: - - cd $TEST_DIR && npm install && npm test -deploy: - provider: script - script: remix-debugger/ci/deploy_from_travis.sh - skip_cleanup: true - on: - branch: master - condition: $TEST_DIR = remix-debugger -cache: false diff --git a/README.md b/README.md index a8fcbdcc05..30012a3add 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Remix [![Join the chat at https://gitter.im/ethereum/remix](https://badges.gitter.im/ethereum/remix.svg)](https://gitter.im/ethereum/remix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![CircleCI](https://circleci.com/gh/ethereum/remix.svg?style=svg)](https://circleci.com/gh/ethereum/remix) +[![CircleCI](https://circleci.com/gh/ethereum/remix/tree/master.svg?style=svg)](https://circleci.com/gh/ethereum/remix/tree/master) [![Documentation Status](https://readthedocs.org/projects/docs/badge/?version=latest)](https://remix.readthedocs.io/en/latest/) Ethereum tools for the web. @@ -50,6 +50,7 @@ Remix is built out of several different modules: + [`remix-lib`](remix-lib/README.md) + [`remix-debug`](remix-debugger/README.md) is now *deprecated*. It contains the debugger. + [`remix-tests`](remix-tests/README.md) contains our tests. ++ [`remixd`](https://github.com/ethereum/remixd/tree/master) CLI which allow accessing local element from Remix IDE (see https://remix.readthedocs.io/en/latest/tutorial_remixd_filesystem.html) Each generally has their own npm package and test suite, as well as basic documentation. diff --git a/docs/unittesting_tab.md b/docs/unittesting_tab.md index e128529dcd..df12a1a320 100644 --- a/docs/unittesting_tab.md +++ b/docs/unittesting_tab.md @@ -24,8 +24,12 @@ This execute tests. The execution is run in a separate environment and the resul | `Assert.greaterThan()` | `uint`, `int` | | `Assert.lesserThan()` | `uint`, `int` | +see [https://github.com/ethereum/remix/blob/master/remix-tests/tests/examples_4/SafeMath_test.sol](https://github.com/ethereum/remix/blob/master/remix-tests/tests/examples_4/SafeMath_test.sol) for some code sample + Continuous integration ---------------------- remix-tests is also a CLI, it can be used in a continuous integration environement which support node.js. Please find more information in the [remix-test repository](https://github.com/ethereum/remix/tree/master/remix-tests) + +See also: example [Su Squares contract](https://github.com/su-squares/ethereum-contract/tree/e542f37d4f8f6c7b07d90a6554424268384a4186) and [https://travis-ci.org/su-squares/ethereum-contract/builds/446186067](Travis build) that uses remix-tests for continuous integration testing. diff --git a/docs/workshop_Building_smart_contracts_with_Remix.md b/docs/workshop_Building_smart_contracts_with_Remix.md index 654668ba0c..204065b64f 100644 --- a/docs/workshop_Building_smart_contracts_with_Remix.md +++ b/docs/workshop_Building_smart_contracts_with_Remix.md @@ -10,5 +10,5 @@ This tutorial was used in workshops at ethCC, Edcon, and DappCon. You can [watch the Edcon presentation talk](https://www.youtube.com/watch?v=nAI_Cr5Y8JY) and here are the [workshop slides](https://slides.com/ninabreznik/deck-11-13#/). (May 3, 2018) -Here are the [DappCon slides (hosted on swarm)](https://30400.swarm-gateways.net/bzz:/2271229d214f8aef9b1176bc22dbc09e384cd8c577a87c60ebece68aebc59d3a/) and here are the [DappCon slides (not on swarm)](https://www.updig.is/pdf/remix-at-dappcon.pdf). -(July 19, 2018) \ No newline at end of file +Here are the [latest slides (hosted on swarm)](http://30400.swarm-gateways.net/bzz:/49277e2a16baf5576c9f54204c70dc403a425c3df85424864fe04ad6dfc609bc/) and here are the [latest slides (not on swarm)](https://www.updig.is/pdf/remix-chez-coinhouse.pdf). +(Oct 16, 2018) \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000000..c8234e39c0 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,11 @@ +#!/usr/bin/env node + +'use strict'; +var gulp = require('gulp'); +var exec = require('child_process').exec; + +var packageJSON = require('./package.json'); + +gulp.task('publishTag', function () { + exec("git tag v"+ packageJSON.version +"; git push --tags"); +}); diff --git a/lerna.json b/lerna.json index c28bf231ed..648f59d921 100644 --- a/lerna.json +++ b/lerna.json @@ -8,5 +8,14 @@ "remix-tests", "remix-simulator" ], + "command": { + "init": { + "exact": true + }, + "publish": { + "exact": true, + "skipGit": true + } + }, "version": "independent" } diff --git a/package.json b/package.json index 6caf32cecb..b5e4ef1d69 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,15 @@ { - "devDependencies": { - "lerna": "^2.10.2" - }, - "scripts": { - "bootstrap": "lerna bootstrap", - "publish": "lerna publish" - } + "version": "0.1.2", + "devDependencies": { + "gulp": "^3.9.1", + "lerna": "^2.10.2" + }, + "scripts": { + "diff": "lerna diff", + "updated": "lerna updated", + "bootstrap": "lerna bootstrap", + "publish": "lerna publish", + "release": "lerna bootstrap; lerna publish;", + "tag": "gulp; gulp publishTag;" + } } diff --git a/release-process.md b/release-process.md new file mode 100644 index 0000000000..405ce367e7 --- /dev/null +++ b/release-process.md @@ -0,0 +1,15 @@ +# Release process +This document details steps for publishing packages and tag the code base accordingly: + +- checkout a new branch +- npm run publish +- commit +- increment root package.json version +- commit +- merge the branch +- fetch origin/master +- checkout origin/master +- npm run tag +- github-changes -o ethereum -r remix -a --only-pulls --use-commit-body --only-merges --between-tags ... +- create a new release out of the changelog.md +- in changelog put list of published packages with version diff --git a/remix-analyzer/package.json b/remix-analyzer/package.json index 2a24abc649..a4bf9c2aff 100644 --- a/remix-analyzer/package.json +++ b/remix-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "remix-analyzer", - "version": "0.2.8", + "version": "0.2.11", "description": "Remix Analyzer", "main": "./index.js", "contributors": [ @@ -21,7 +21,7 @@ "babel-eslint": "^7.1.1", "babel-plugin-transform-object-assign": "^6.22.0", "babel-preset-es2015": "^6.24.0", - "remix-lib": "^0.3.8", + "remix-lib": "0.3.11", "solc": "^0.4.24", "standard": "^7.0.1", "tape": "^4.6.0" diff --git a/remix-debug/package.json b/remix-debug/package.json index 97774d32fb..35cac15450 100644 --- a/remix-debug/package.json +++ b/remix-debug/package.json @@ -1,6 +1,6 @@ { "name": "remix-debug", - "version": "0.2.9", + "version": "0.2.12", "description": "Ethereum IDE and tools for the web", "contributors": [ { @@ -23,7 +23,7 @@ "fast-async": "^6.1.2", "notify-error": "^1.2.0", "npm-run-all": "^4.1.2", - "remix-lib": "^0.3.8", + "remix-lib": "0.3.11", "solc": "^0.4.24" }, "devDependencies": { diff --git a/remix-lib/package.json b/remix-lib/package.json index b4aa95f968..947723c668 100644 --- a/remix-lib/package.json +++ b/remix-lib/package.json @@ -1,6 +1,6 @@ { "name": "remix-lib", - "version": "0.3.8", + "version": "0.3.11", "description": "Ethereum IDE and tools for the web", "contributors": [ { diff --git a/remix-lib/src/execution/execution-context.js b/remix-lib/src/execution/execution-context.js index b8c459973a..fef1a1544b 100644 --- a/remix-lib/src/execution/execution-context.js +++ b/remix-lib/src/execution/execution-context.js @@ -85,6 +85,7 @@ function ExecutionContext () { this.blockGasLimitDefault = 4300000 this.blockGasLimit = this.blockGasLimitDefault + this.customNetWorks = {} this.init = function (config) { if (config.get('settings/always-use-vm')) { @@ -134,6 +135,20 @@ function ExecutionContext () { } } + this.removeProvider = function (name) { + if (name && this.customNetWorks[name]) { + delete this.customNetWorks[name] + self.event.trigger('removeProvider', [name]) + } + } + + this.addProvider = function (network) { + if (network && network.name && network.url) { + this.customNetWorks[network.name] = network + self.event.trigger('addProvider', [network]) + } + } + this.internalWeb3 = function () { return web3 } @@ -182,6 +197,11 @@ function ExecutionContext () { if (context === 'web3') { confirmCb(cb) } + + if (this.customNetWorks[context]) { + var provider = this.customNetWorks[context] + setProviderFromEndpoint(provider.url, provider.name, () => { cb() }) + } } this.currentblockGasLimit = function () { diff --git a/remix-lib/src/web3Provider/web3VmProvider.js b/remix-lib/src/web3Provider/web3VmProvider.js index 189a44617e..17f3a644a7 100644 --- a/remix-lib/src/web3Provider/web3VmProvider.js +++ b/remix-lib/src/web3Provider/web3VmProvider.js @@ -122,6 +122,7 @@ web3VmProvider.prototype.txProcessed = function (self, data) { } self.txsReceipt[self.processingHash].logs = logs self.txsReceipt[self.processingHash].transactionHash = self.processingHash + self.txsReceipt[self.processingHash].status = '0x' + data.vm.exception.toString(16) if (data.createdAddress) { var address = util.hexConvert(data.createdAddress) diff --git a/remix-simulator/package.json b/remix-simulator/package.json index f024401e6f..0efe18ee2c 100644 --- a/remix-simulator/package.json +++ b/remix-simulator/package.json @@ -1,6 +1,6 @@ { "name": "remix-simulator", - "version": "0.0.4", + "version": "0.0.6", "description": "Ethereum IDE and tools for the web", "contributors": [ { @@ -15,6 +15,7 @@ "main": "./index.js", "dependencies": { "ansi-gray": "^0.1.1", + "babel-eslint": "^7.1.1", "babel-plugin-transform-object-assign": "^6.22.0", "babel-preset-es2017": "^6.24.1", "babelify": "^7.3.0", @@ -23,7 +24,7 @@ "express": "^4.16.3", "fast-async": "^6.3.7", "merge": "^1.2.0", - "remix-lib": "^0.2.5", + "remix-lib": "0.3.11", "standard": "^10.0.3", "time-stamp": "^2.0.0", "web3": "1.0.0-beta.27" diff --git a/remix-simulator/src/methods/accounts.js b/remix-simulator/src/methods/accounts.js index c85493aade..d23f572229 100644 --- a/remix-simulator/src/methods/accounts.js +++ b/remix-simulator/src/methods/accounts.js @@ -3,10 +3,15 @@ var Web3 = require('web3') var Accounts = function () { this.web3 = new Web3() // TODO: make it random and/or use remix-libs - this.accounts = [this.web3.eth.accounts.create(['abcd'])] + this.accounts = [this.web3.eth.accounts.create(['abcd']), this.web3.eth.accounts.create(['ef12']), this.web3.eth.accounts.create(['ef34'])] this.accounts[this.accounts[0].address.toLowerCase()] = this.accounts[0] + this.accounts[this.accounts[1].address.toLowerCase()] = this.accounts[1] + this.accounts[this.accounts[2].address.toLowerCase()] = this.accounts[2] + this.accounts[this.accounts[0].address.toLowerCase()].privateKey = Buffer.from(this.accounts[this.accounts[0].address.toLowerCase()].privateKey.slice(2), 'hex') + this.accounts[this.accounts[1].address.toLowerCase()].privateKey = Buffer.from(this.accounts[this.accounts[1].address.toLowerCase()].privateKey.slice(2), 'hex') + this.accounts[this.accounts[2].address.toLowerCase()].privateKey = Buffer.from(this.accounts[this.accounts[2].address.toLowerCase()].privateKey.slice(2), 'hex') } Accounts.prototype.methods = function () { diff --git a/remix-simulator/src/methods/transactions.js b/remix-simulator/src/methods/transactions.js index 53834ea7dd..1e0f315d2c 100644 --- a/remix-simulator/src/methods/transactions.js +++ b/remix-simulator/src/methods/transactions.js @@ -39,7 +39,7 @@ Transactions.prototype.eth_getTransactionReceipt = function (payload, cb) { 'cumulativeGasUsed': '0x06345f', 'contractAddress': receipt.contractAddress, 'logs': receipt.logs, - 'status': 1 + 'status': receipt.status } cb(null, r) diff --git a/remix-solidity/package.json b/remix-solidity/package.json index 6199d3cc85..c5a3328820 100644 --- a/remix-solidity/package.json +++ b/remix-solidity/package.json @@ -1,6 +1,6 @@ { "name": "remix-solidity", - "version": "0.2.8", + "version": "0.2.12", "description": "Ethereum IDE and tools for the web", "contributors": [ { @@ -22,7 +22,7 @@ "ethereumjs-vm": "^2.3.3", "fast-async": "^6.1.2", "npm-run-all": "^4.0.2", - "remix-lib": "^0.3.8", + "remix-lib": "0.3.11", "solc": "^0.5.0", "standard": "^7.0.1", "tape": "^4.6.0", diff --git a/remix-solidity/src/compiler/compiler.js b/remix-solidity/src/compiler/compiler.js index f7d954c1e6..0109223932 100644 --- a/remix-solidity/src/compiler/compiler.js +++ b/remix-solidity/src/compiler/compiler.js @@ -313,7 +313,7 @@ function Compiler (handleImportCall) { while ((match = importRegex.exec(files[fileName].content))) { var importFilePath = match[1] if (importFilePath.startsWith('./')) { - var path = /(.*\/).*/.exec(target) + var path = /(.*\/).*/.exec(fileName) if (path !== null) { importFilePath = importFilePath.replace('./', path[1]) } else { diff --git a/remix-tests/README.md b/remix-tests/README.md index f18a3f48e4..a149105963 100644 --- a/remix-tests/README.md +++ b/remix-tests/README.md @@ -1,5 +1,3 @@ -[![Build Status](https://travis-ci.org/ethereum/remix-tests.svg?branch=master)](https://travis-ci.org/ethereum/remix-tests) - Remix-Tests --- @@ -43,6 +41,8 @@ contract MyTest { } ``` +See also: example [Su Squares contract](https://github.com/su-squares/ethereum-contract/tree/e542f37d4f8f6c7b07d90a6554424268384a4186) and [https://travis-ci.org/su-squares/ethereum-contract/builds/446186067](Travis build) that uses remix-tests for continuous integration testing. + Available special functions: * `beforeEach()` - runs before each test * `beforeAll()` - runs before all tests diff --git a/remix-tests/package.json b/remix-tests/package.json index f8fca503ed..07fb8a00c4 100644 --- a/remix-tests/package.json +++ b/remix-tests/package.json @@ -1,6 +1,6 @@ { "name": "remix-tests", - "version": "0.0.13", + "version": "0.0.18", "description": "Tests for the Ethereum tool suite Remix", "main": "./src/index.js", "contributors": [ @@ -41,13 +41,13 @@ "change-case": "^3.0.1", "colors": "^1.1.2", "commander": "^2.13.0", - "remix-lib": "^0.3.8", - "remix-simulator": "^0.0.4", - "remix-solidity": "^0.2.8", + "remix-lib": "0.3.11", + "remix-simulator": "0.0.6", + "remix-solidity": "0.2.12", "signale": "^1.2.1", "solc": "^0.4.24", "standard": "^10.0.3", - "web3": "1.0.0-beta.34", + "web3": "1.0.0-beta.36", "winston": "^3.0.0" }, "peerDependencies": { diff --git a/remix-tests/sol/tests_accounts.sol.js b/remix-tests/sol/tests_accounts.sol.js new file mode 100644 index 0000000000..2a3cb04024 --- /dev/null +++ b/remix-tests/sol/tests_accounts.sol.js @@ -0,0 +1,9 @@ +module.exports = `pragma solidity ^0.4.7; + +library TestsAccounts { + function getAccount(uint index) returns (address) { + >accounts< + return accounts[index]; + } +} +` diff --git a/remix-tests/src/compiler.js b/remix-tests/src/compiler.js index f43a9cab65..476c8ea881 100644 --- a/remix-tests/src/compiler.js +++ b/remix-tests/src/compiler.js @@ -9,18 +9,28 @@ String.prototype.regexIndexOf = function (regex, startpos) { 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 { + body += '= [' + accounts.map((value) => { return `address(${value})` }).join(',') + '];' + } + 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, cb) { +function compileFileOrFiles (filename, isDirectory, opts, cb) { let compiler, filepath - + let accounts = opts.accounts || [] const sources = { '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) } } - // TODO: for now assumes filepath dir contains all tests, later all this // should be replaced with remix's & browser solidity compiler code filepath = (isDirectory ? filename : path.dirname(filename)) @@ -31,7 +41,7 @@ function compileFileOrFiles (filename, isDirectory, cb) { let c = fs.readFileSync(path.join(filepath, file)).toString() const s = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm if (file.indexOf('_test.sol') > 0 && c.regexIndexOf(s) < 0) { - c = c.replace(/(pragma solidity \^\d+\.\d+\.\d+;)/, '$1\nimport \'remix_tests.sol\';') + c = c.replace(/(pragma solidity \^?\d+\.\d+\.\d+;)/, '$1\nimport \'remix_tests.sol\';') } sources[file] = { content: c } } @@ -61,12 +71,13 @@ function compileFileOrFiles (filename, isDirectory, cb) { }) } -function compileContractSources (sources, importFileCb, cb) { +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 for (let file in sources) { diff --git a/remix-tests/src/index.js b/remix-tests/src/index.js index 3dfd689ff4..91aa7e3a01 100644 --- a/remix-tests/src/index.js +++ b/remix-tests/src/index.js @@ -16,13 +16,22 @@ var createWeb3Provider = function () { return web3 } -var runTestSources = function (contractSources, testCallback, resultCallback, finalCallback, importFileCb) { +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, next) + Compiler.compileContractSources(contractSources, importFileCb, { accounts }, next) }, function deployAllContracts (compilationResult, next) { - let web3 = createWeb3Provider() Deployer.deployAll(compilationResult, web3, function (err, contracts) { if (err) { next(err) @@ -33,19 +42,21 @@ var runTestSources = function (contractSources, testCallback, resultCallback, fi }, 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, contracts) + next(null, contractsToTest, contractsToTestDetails, contracts) }, - function runTests (contractsToTest, contracts, next) { + function runTests (contractsToTest, contractsToTestDetails, contracts, next) { let totalPassing = 0 let totalFailing = 0 let totalTime = 0 @@ -67,7 +78,7 @@ var runTestSources = function (contractSources, testCallback, resultCallback, fi } async.eachOfLimit(contractsToTest, 1, (contractName, index, cb) => { - TestRunner.runTest(contractName, contracts[contractName], _testCallback, (err, result) => { + TestRunner.runTest(contractName, contracts[contractName], contractsToTestDetails[index], { accounts }, _testCallback, (err, result) => { if (err) { return cb(err) } @@ -95,7 +106,8 @@ var runTestSources = function (contractSources, testCallback, resultCallback, fi ], finalCallback) } -var runTestFiles = function (filepath, isDirectory, web3) { +var runTestFiles = function (filepath, isDirectory, web3, opts) { + opts = opts || {} const { Signale } = require('signale') // signale configuration const options = { @@ -118,37 +130,49 @@ var runTestFiles = function (filepath, isDirectory, web3) { } } 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, 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 => { - if (filename.indexOf('_test.sol') < 0) { - return - } - Object.keys(compilationResult[path.basename(filename)]).forEach(contractName => { - contractsToTest.push(contractName) - }) + gatherContractsFrom(filename) }) } else { - contractsToTest = Object.keys(compilationResult[path.basename(filepath)]) + gatherContractsFrom(filepath) } - - next(null, contractsToTest, contracts) + next(null, contractsToTest, contractsToTestDetails, contracts) }, - function runTests (contractsToTest, contracts, next) { + function runTests (contractsToTest, contractsToTestDetails, contracts, next) { let totalPassing = 0 let totalFailing = 0 let totalTime = 0 @@ -172,7 +196,7 @@ var runTestFiles = function (filepath, isDirectory, web3) { } async.eachOfLimit(contractsToTest, 1, (contractName, index, cb) => { - TestRunner.runTest(contractName, contracts[contractName], testCallback, (err, result) => { + TestRunner.runTest(contractName, contracts[contractName], contractsToTestDetails[index], { accounts }, testCallback, (err, result) => { if (err) { return cb(err) } diff --git a/remix-tests/src/testRunner.js b/remix-tests/src/testRunner.js index 89493e944b..7c804b91c9 100644 --- a/remix-tests/src/testRunner.js +++ b/remix-tests/src/testRunner.js @@ -2,6 +2,20 @@ 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) + return fullName && userdoc.methods[fullName] ? userdoc.methods[fullName].notice : null +} + function getAvailableFunctions (jsonInterface) { return jsonInterface.reverse().filter((x) => x.type === 'function').map((x) => x.name) } @@ -24,7 +38,7 @@ function createRunList (jsonInterface) { if (availableFunctions.indexOf('beforeEach') >= 0) { runList.push({name: 'beforeEach', type: 'internal', constant: false}) } - runList.push({name: func.name, type: 'test', constant: func.constant}) + 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}) } @@ -37,7 +51,7 @@ function createRunList (jsonInterface) { return runList } -function runTest (testName, testObject, testCallback, resultsCallback) { +function runTest (testName, testObject, contractDetails, opts, testCallback, resultsCallback) { let runList = createRunList(testObject._jsonInterface) let passingNum = 0 @@ -45,12 +59,32 @@ function runTest (testName, testObject, testCallback, resultsCallback) { 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().then((result) => { + 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}) @@ -63,7 +97,7 @@ function runTest (testName, testObject, testCallback, resultsCallback) { next() }) } else { - method.send().on('receipt', function (receipt) { + 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)') @@ -95,11 +129,12 @@ function runTest (testName, testObject, testCallback, resultsCallback) { return next(err) } }).on('error', function (err) { + console.error(err) next(err) }) } - }, function () { - resultsCallback(null, { + }, function (error) { + resultsCallback(error, { passingNum: passingNum, failureNum: failureNum, timePassed: timePassed diff --git a/remix-tests/tests/testRunner.js b/remix-tests/tests/testRunner.js index 4f23dfd243..1871d19e13 100644 --- a/remix-tests/tests/testRunner.js +++ b/remix-tests/tests/testRunner.js @@ -10,18 +10,27 @@ 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, next) + Compiler.compileFileOrFiles(filename, false, {accounts}, next) }, function deployAllContracts (compilationResult, next) { + compilationData = compilationResult Deployer.deployAll(compilationResult, web3, next) } ], function (_err, contracts) { - callback(null, contracts) + callback(null, compilationData, contracts, accounts) }) -} +} + describe('testRunner', function () { describe('#runTest', function() { @@ -30,7 +39,7 @@ describe('testRunner', function () { let tests = [], results = {} before(function (done) { - compileAndDeploy(filename, function (_err, contracts) { + compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { var testCallback = function (test) { tests.push(test) } @@ -38,7 +47,7 @@ describe('testRunner', function () { results = _results done() } - TestRunner.runTest('MyTest', contracts.MyTest, testCallback, resultsCallback) + TestRunner.runTest('MyTest', contracts.MyTest, compilationData['simple_storage_test.sol']['MyTest'], { accounts }, testCallback, resultsCallback) }) }) @@ -66,7 +75,7 @@ describe('testRunner', function () { let tests = [], results = {} before(function (done) { - compileAndDeploy(filename, function (_err, contracts) { + compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { var testCallback = function (test) { tests.push(test) } @@ -74,7 +83,7 @@ describe('testRunner', function () { results = _results done() } - TestRunner.runTest('MyTest', contracts.MyTest, testCallback, resultsCallback) + TestRunner.runTest('MyTest', contracts.MyTest, compilationData['simple_storage_test.sol']['MyTest'], { accounts }, testCallback, resultsCallback) }) }) @@ -101,7 +110,7 @@ describe('testRunner', function () { let tests = [], results = {} before(function (done) { - compileAndDeploy(filename, function (_err, contracts) { + compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { var testCallback = function (test) { tests.push(test) } @@ -109,8 +118,8 @@ describe('testRunner', function () { results = _results done() } - TestRunner.runTest('StringTest', contracts.StringTest, testCallback, resultsCallback) - TestRunner.runTest('StringTest2', contracts.StringTest2, testCallback, resultsCallback) + TestRunner.runTest('StringTest', contracts.StringTest, compilationData['simple_string_test.sol']['StringTest'], { accounts }, testCallback, resultsCallback) + TestRunner.runTest('StringTest2', contracts.StringTest2, compilationData['simple_string_test.sol']['StringTest2'], { accounts }, testCallback, resultsCallback) }) }) @@ -138,7 +147,7 @@ describe('testRunner', function () { let tests = [], results = {} before(function (done) { - compileAndDeploy(filename, function (_err, contracts) { + compileAndDeploy(filename, function (_err, compilationData, contracts, accounts) { var testCallback = function (test) { tests.push(test) } @@ -146,7 +155,7 @@ describe('testRunner', function () { results = _results done() } - TestRunner.runTest('IntegerTest', contracts.IntegerTest, testCallback, resultsCallback) + TestRunner.runTest('IntegerTest', contracts.IntegerTest, compilationData['number_test.sol']['IntegerTest'], { accounts }, testCallback, resultsCallback) }) }) @@ -157,5 +166,33 @@ describe('testRunner', 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['sender_test.sol']['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) + }) + }) }) }) diff --git a/remix-tests/tests/various_sender/sender_test.sol b/remix-tests/tests/various_sender/sender_test.sol new file mode 100644 index 0000000000..896c145447 --- /dev/null +++ b/remix-tests/tests/various_sender/sender_test.sol @@ -0,0 +1,28 @@ +pragma solidity ^0.4.7; +import "remix_tests.sol"; // this import is automatically injected by Remix. +import "remix_accounts.sol"; + +contract SenderTest { + + function beforeAll () {} + + /// 1 + function checkSenderIs1 () public { + Assert.equal(msg.sender, TestsAccounts.getAccount(1), "wrong sender in checkSenderIs1"); + } + + /// 0 + function checkSenderIs0 () public { + Assert.equal(msg.sender, TestsAccounts.getAccount(0), "wrong sender in checkSenderIs0"); + } + + /// 1 + function checkSenderIsNt0 () public { + Assert.notEqual(msg.sender, TestsAccounts.getAccount(0), "wrong sender in checkSenderIsNot0"); + } + + /// 2 + function checkSenderIsnt2 () public { + Assert.notEqual(msg.sender, TestsAccounts.getAccount(1), "wrong sender in checkSenderIsnt2"); + } +} diff --git a/remixd b/remixd new file mode 160000 index 0000000000..1a9ec3230e --- /dev/null +++ b/remixd @@ -0,0 +1 @@ +Subproject commit 1a9ec3230e7a3c278ddc6344e5c89d488a316910