From df8f3768e2c38dcc191d115b6873cab9029c2c88 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 13 Oct 2017 15:29:40 +0200 Subject: [PATCH] more tests : inputs, outputs, events, import test debugging locals/state --- ci/browser_tests.sh | 2 +- ci/makeMockCompiler.js | 31 +++- package.json | 1 + src/app/execution/txLogger.js | 2 +- src/app/panels/file-panel.js | 14 +- test-browser/helpers/contracts.js | 150 +++++++++++++-- test-browser/helpers/init.js | 2 +- test-browser/mockcompiler/compiler.js | 9 +- test-browser/tests/ballot.js | 100 +++++++++- test-browser/tests/compiling.js | 180 +++++++++++++++--- test-browser/tests/fileExplorer.js | 7 +- test-browser/tests/new-file-test.js | 18 -- test-browser/tests/sharedFolderExplorer.js | 8 +- test-browser/tests/simpleContract.js | 203 ++++++++++++++++++++- test-browser/tests/staticanalysis.js | 11 +- 15 files changed, 628 insertions(+), 110 deletions(-) delete mode 100644 test-browser/tests/new-file-test.js diff --git a/ci/browser_tests.sh b/ci/browser_tests.sh index 51a5cbbcb5..3b5d139214 100755 --- a/ci/browser_tests.sh +++ b/ci/browser_tests.sh @@ -41,7 +41,7 @@ done npm run nightwatch_remote_chrome || TEST_EXITCODE=1 npm run nightwatch_remote_firefox || TEST_EXITCODE=1 npm run nightwatch_remote_safari || TEST_EXITCODE=1 -npm run nightwatch_remote_ie || TEST_EXITCODE=1 +# npm run nightwatch_remote_ie || TEST_EXITCODE=1 # npm run nightwatch_remote_parallel || TEST_EXITCODE=1 => cannot run in parallel because of remixd node ci/sauceDisconnect.js "$SAUCECONNECT_USERNAME" "$SAUCECONNECT_ACCESSKEY" "$SAUCECONNECT_JOBIDENTIFIER" diff --git a/ci/makeMockCompiler.js b/ci/makeMockCompiler.js index df472c4060..8875862693 100644 --- a/ci/makeMockCompiler.js +++ b/ci/makeMockCompiler.js @@ -24,11 +24,15 @@ function gatherCompilationResults (callback) { filenames.map(function (item, i) { var testDef = require('../test-browser/tests/' + item) if ('@sources' in testDef) { - var source = testDef['@sources']() - var result = compile(source, 1) - compilationResult[result.key] = result - result = compile(source, 0) - compilationResult[result.key] = result + var sources = testDef['@sources']() + for (var files in sources) { + compile({sources: sources[files]}, 1, function (result) { + compilationResult[result.key] = result + }) + compile({sources: sources[files]}, 0, function (result) { + compilationResult[result.key] = result + }) + } } }) @@ -37,23 +41,29 @@ function gatherCompilationResults (callback) { }) } -function compile (source, optimization) { +function compile (source, optimization, addCompilationResult) { var missingInputs = [] - var result = compiler.compile(source, optimization, function (path) { - missingInputs.push(path) - }) + try { + var result = compiler.compile(source, optimization, function (path) { + missingInputs.push(path) + return { error: 'Deferred import' } + }) + } catch (e) { + console.log(e) + } var key = optimization.toString() for (var k in source.sources) { key += k + source.sources[k] } key = key.replace(/(\t)|(\n)|( )/g, '') - return { + var ret = { key: key, source: source, optimization: optimization, missingInputs: missingInputs, result: result } + addCompilationResult(ret) } function replaceSolCompiler (results) { @@ -63,6 +73,7 @@ function replaceSolCompiler (results) { process.exit(1) return } + console.log(compiler.version()) data = data + '\n\nvar mockCompilerVersion = \'' + compiler.version() + '\'' data = data + '\n\nvar mockData = ' + JSON.stringify(results) + ';\n' fs.writeFile('./soljson.js', data, 'utf8', function (error) { diff --git a/package.json b/package.json index fa71d7094e..7e859dc47c 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "component-type": "^1.2.1", "csjs-inject": "^1.0.1", "csslint": "^1.0.2", + "deep-equal": "^1.0.1", "ethereum-remix": "https://github.com/ethereum/remix", "ethereumjs-abi": "https://github.com/ethereumjs/ethereumjs-abi", "ethereumjs-block": "^1.6.0", diff --git a/src/app/execution/txLogger.js b/src/app/execution/txLogger.js index 828bfea654..47fc97f0d3 100644 --- a/src/app/execution/txLogger.js +++ b/src/app/execution/txLogger.js @@ -385,7 +385,7 @@ function createTable (opts) { var logs = yo` logs - + ${JSON.stringify(stringified, null, '\t')} diff --git a/src/app/panels/file-panel.js b/src/app/panels/file-panel.js index 83f2061b0c..f4a93fe095 100644 --- a/src/app/panels/file-panel.js +++ b/src/app/panels/file-panel.js @@ -266,12 +266,14 @@ function filepanel (appAPI, filesProvider) { } function createNewFile () { - var newName = filesProvider['browser'].type + '/' + helper.createNonClashingName('Untitled.sol', filesProvider['browser']) - if (!filesProvider['browser'].set(newName, '')) { - modalDialogCustom.alert('Failed to create file ' + newName) - } else { - appAPI.switchFile(newName) - } + modalDialogCustom.prompt(null, 'File Name', 'Untitled.sol', (input) => { + var newName = filesProvider['browser'].type + '/' + helper.createNonClashingName(input, filesProvider['browser']) + if (!filesProvider['browser'].set(newName, '')) { + modalDialogCustom.alert('Failed to create file ' + newName) + } else { + appAPI.switchFile(newName) + } + }) } /** diff --git a/test-browser/helpers/contracts.js b/test-browser/helpers/contracts.js index 5cc4264b98..739d280821 100644 --- a/test-browser/helpers/contracts.js +++ b/test-browser/helpers/contracts.js @@ -1,11 +1,18 @@ 'use strict' +var deepequal = require('deep-equal') module.exports = { - checkCompiledContracts: checkCompiledContracts, - testContracts: testContracts + getCompiledContracts: getCompiledContracts, + testContracts: testContracts, + addFile: addFile, + switchFile: switchFile, + verifyContract: verifyContract, + testFunction, + checkDebug, + goToVMtraceStep } -function checkCompiledContracts (browser, compiled, callback) { +function getCompiledContracts (browser, compiled, callback) { browser.execute(function () { var contracts = document.querySelectorAll('#compileTabView select option') if (!contracts) { @@ -18,23 +25,138 @@ function checkCompiledContracts (browser, compiled, callback) { return ret } }, [], function (result) { - if (!result.value) { - browser.end('no compiled contracts') + callback(result) + }) +} + +function verifyContract (browser, compiledContractNames, callback) { + getCompiledContracts(browser, compiledContractNames, (result) => { + if (result.value) { + for (var contract in compiledContractNames) { + console.log(' - ' + result.value) + console.log(' - ' + compiledContractNames[contract]) + if (result.value.indexOf(compiledContractNames[contract]) === -1) { + browser.assert.fail('compiled contract ' + compiledContractNames + ' not found', 'info about error', '') + browser.end() + return + } + } } else { - result.value.map(function (item, i) { - browser.assert.equal(item, compiled[i]) - }) + browser.assert.fail('compiled contract ' + compiledContractNames + ' not found - none found', 'info about error', '') + browser.end() } + console.log('contracts all found ' + result.value) callback() }) } -function testContracts (browser, contractCode, compiledContractNames, callback) { +function testContracts (browser, fileName, contractCode, compiledContractNames, callback) { browser - .clearValue('#input textarea') - .click('.newFile') - .setValue('#input textarea', contractCode, function () {}) - .waitForElementPresent('#compileTabView select option', 50000, true, function () { - checkCompiledContracts(browser, compiledContractNames, callback) + .click('.compileView') + .clearValue('#input textarea') + .perform((client, done) => { + addFile(browser, fileName, contractCode, done) + }) + .pause(1000) + .perform(function () { + verifyContract(browser, compiledContractNames, callback) + }) +} + +function testFunction (fnFullName, txHash, log, expectedInput, expectedReturn, expectedEvent) { + // this => browser + this.waitForElementPresent('.instance button[title="' + fnFullName + '"]') + .perform(function (client, done) { + if (expectedInput) { + client.setValue('#runTabView input[title="' + expectedInput.types + '"]', expectedInput.values, function () {}) + } + done() + }) + .click('.instance button[title="' + fnFullName + '"]') + .pause(500) + .waitForElementPresent('#editor-container div[class^="terminal"] span[id="tx' + txHash + '"]') + .assert.containsText('#editor-container div[class^="terminal"] span[id="tx' + txHash + '"] span', log) + .click('#editor-container div[class^="terminal"] span[id="tx' + txHash + '"] button[class^="details"]') + .perform(function (client, done) { + if (expectedReturn) { + client.assert.containsText('#editor-container div[class^="terminal"] span[id="tx' + txHash + '"] table[class^="txTable"] #decodedoutput', expectedReturn) + } + done() + }) + .perform(function (client, done) { + if (expectedEvent) { + client.assert.containsText('#editor-container div[class^="terminal"] span[id="tx' + txHash + '"] table[class^="txTable"] #logs', expectedEvent) + } + done() + }) + return this +} + +function addFile (browser, name, content, done) { + browser.click('.newFile') + .perform((client, done) => { + browser.execute(function (fileName) { + if (fileName !== 'Untitled.sol') { + document.querySelector('#modal-dialog #prompt_text').setAttribute('value', fileName) + } + document.querySelector('#modal-footer-ok').click() + }, [name], function (result) { + console.log(result) + done() }) + }) + .setValue('#input textarea', content, function () {}) + .pause(1000) + .perform(function () { + done() + }) +} + +function switchFile (browser, name, done) { + browser + .useXpath() + .click('//ul[@id="files"]//span[text()="' + name + '"]') + .useCss() + .pause(2000) + .perform(function () { + done() + }) +} + +function checkDebug (browser, id, debugValue, done) { + // id is soliditylocals or soliditystate + browser.execute(function (id) { + return document.querySelector('#' + id + ' .dropdownrawcontent').innerText + }, [id], function (result) { + console.log(id + ' ' + result.value) + var value = JSON.parse(result.value) + var equal = deepequal(debugValue, value) + if (!equal) { + browser.assert.fail('checkDebug on ' + id, 'info about error', '') + } + done() + }) +} + +function goToVMtraceStep (browser, step, done, incr) { + if (!incr) incr = 0 + browser.execute(function (step) { + return document.querySelector('#stepdetail').innerHTML + }, [step], function (result) { + if (result.value.indexOf('vm trace step: ' + step) !== -1) { + done() + } else if (incr > 1000) { + console.log(result) + browser.assert.fail('goToVMtraceStep fails', 'info about error', '') + done() + } else { + incr++ + browser.click('#intoforward') + .perform(() => { + setTimeout(() => { + goToVMtraceStep(browser, step, done, incr) + }, 200) + }) + } + }) } diff --git a/test-browser/helpers/init.js b/test-browser/helpers/init.js index 314daa61e8..1d3a9a6652 100644 --- a/test-browser/helpers/init.js +++ b/test-browser/helpers/init.js @@ -2,6 +2,6 @@ module.exports = function (browser, callback) { browser .url('http://127.0.0.1:8080/#version=builtin') .injectScript('test-browser/helpers/applytestmode.js', function () { - callback() + browser.resizeWindow(2560, 1440, callback) }) } diff --git a/test-browser/mockcompiler/compiler.js b/test-browser/mockcompiler/compiler.js index 87f20faf58..ddc50ad97d 100644 --- a/test-browser/mockcompiler/compiler.js +++ b/test-browser/mockcompiler/compiler.js @@ -4,14 +4,15 @@ var Module = { // eslint-disable-line cwrap: function () { return arguments[0] === 'version' ? version : compile }, writeStringToMemory: function () {}, setValue: function () {}, - Pointer_stringify: function () {}, + Pointer_stringify: function (value) { return value }, Runtime: { - addFunction: function () {}, + addFunction: function () { return arguments[0] }, removeFunction: function () {} }, _compileJSONMulti: {}, _compileJSONCallback: {}, - _compileJSON: {} + _compileJSON: {}, + _malloc: function () {} } function compile (source, optimization, missingInputs) { @@ -31,7 +32,7 @@ function compile (source, optimization, missingInputs) { } else { data.missingInputs.map(function (item, i) { if (missingInputs) { - missingInputs(item) + missingInputs(item, '', '') } }) } diff --git a/test-browser/tests/ballot.js b/test-browser/tests/ballot.js index 910466b3bc..623ee1e46f 100644 --- a/test-browser/tests/ballot.js +++ b/test-browser/tests/ballot.js @@ -4,11 +4,9 @@ var examples = require('../../src/app/editor/example-contracts') var init = require('../helpers/init') var sauce = require('./sauce') -var sources = { - 'sources': { - 'browser/Untitled.sol': examples.ballot.content - } -} +var sources = [ + {'browser/Untitled.sol': examples.ballot.content} +] module.exports = { before: function (browser, done) { @@ -24,10 +22,98 @@ module.exports = { } function runTests (browser, testData) { + browser.testFunction = contractHelper.testFunction browser .waitForElementVisible('.newFile', 10000) .click('.compileView') - contractHelper.testContracts(browser, sources.sources['browser/Untitled.sol'], ['browser/Untitled.sol:Ballot'], function () { - browser.end() + contractHelper.testContracts(browser, 'Untitled.sol', sources[0]['browser/Untitled.sol'], ['browser/Untitled.sol:Ballot'], function () { + browser + .click('.runView') + .setValue('input[placeholder="uint8 _numProposals"]', '1', () => {}) + .click('#runTabView div[class^="create"]') + .testFunction('delegate - transact (not payable)', '0xd3cd54e2f76f3993078ecf9e1b54a148def4520afc141a182293b3610bddf10f', + '[vm] from:0xca3...a733c, to:browser/Untitled.sol:Ballot.delegate(address) 0x692...77b3a, value:0 wei, data:0x5c1...4d2db, 0 logs, hash:0xd3c...df10f', + {types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"'}, null, null) + .click('span#tx0xd3cd54e2f76f3993078ecf9e1b54a148def4520afc141a182293b3610bddf10f button[class^="debug"]') + .pause(1000) + .click('#jumppreviousbreakpoint') + .click('#stepdetail .title') + .click('#asmcodes .title') + .pause(500) + .perform(function (client, done) { + contractHelper.goToVMtraceStep(browser, 39, () => { + done() + }) + }) + .pause(2000) + .perform(function (client, done) { + contractHelper.checkDebug(browser, 'soliditystate', stateCheck, () => { + done() + }) + }) + .perform(function (client, done) { + contractHelper.checkDebug(browser, 'soliditylocals', localsCheck, () => { + done() + browser.end() + }) + }) }) } + +var localsCheck = { + 'to': { + 'value': '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB', + 'type': 'address' + } +} + +var stateCheck = { + 'chairperson': { + 'value': '0xCA35B7D915458EF540ADE6068DFE2F44E8FA733C', + 'type': 'address', + 'constant': false + }, + 'voters': { + 'value': { + '000000000000000000000000ca35b7d915458ef540ade6068dfe2f44e8fa733c': { + 'value': { + 'weight': { + 'value': '1', + 'type': 'uint256' + }, + 'voted': { + 'value': false, + 'type': 'bool' + }, + 'vote': { + 'value': '0', + 'type': 'uint8' + }, + 'delegate': { + 'value': '0x0000000000000000000000000000000000000000', + 'type': 'address' + } + }, + 'type': 'struct Ballot.Voter' + } + }, + 'type': 'mapping(address => struct Ballot.Voter)', + 'constant': false + }, + 'proposals': { + 'value': [ + { + 'value': { + 'voteCount': { + 'value': '0', + 'type': 'uint256' + } + }, + 'type': 'struct Ballot.Proposal' + } + ], + 'length': '0x1', + 'type': 'struct Ballot.Proposal[]', + 'constant': false + } +} diff --git a/test-browser/tests/compiling.js b/test-browser/tests/compiling.js index 1606b1d0fc..4406700179 100644 --- a/test-browser/tests/compiling.js +++ b/test-browser/tests/compiling.js @@ -2,19 +2,7 @@ var contractHelper = require('../helpers/contracts') var init = require('../helpers/init') var sauce = require('./sauce') - -var sources = { - 'sources': { - 'browser/Untitled.sol': `pragma solidity ^0.4.0; - contract TestContract { function f() returns (uint) { return 8; } - function g() returns (uint, string, bool, uint) { - uint payment = 345; - bool payed = true; - string memory comment = "comment_comment_"; - uint month = 4; - return (payment, comment, payed, month); } }` - } -} +var async = require('async') module.exports = { before: function (browser, done) { @@ -30,29 +18,169 @@ module.exports = { } function runTests (browser) { + browser.testFunction = contractHelper.testFunction browser .waitForElementVisible('.newFile', 10000) .click('.compileView') - contractHelper.testContracts(browser, sources.sources['browser/Untitled.sol'], ['browser/Untitled.sol:TestContract'], function () { + .perform(() => { + // the first fn is used to pass browser to the other ones. + async.waterfall([function (callback) { callback(null, browser) }, testSimpleContract, testReturnValues, testInputValues], function () { + browser.end() + }) + }) +} + +function testSimpleContract (browser, callback) { + contractHelper.testContracts(browser, 'Untitled.sol', sources[0]['browser/Untitled.sol'], ['browser/Untitled.sol:TestContract'], function () { browser.click('.runView') - .click('#runTabView div[class^="create"]') - .waitForElementPresent('.instance button[title="f - transact (not payable)"]') - .click('.instance button[title="f - transact (not payable)"]') - .waitForElementPresent('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]') - .assert.containsText('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]', '[vm] from:0xca3...a733c, to:browser/Untitled.sol:TestContract.f() 0x692...77b3a, value:0 wei, data:0x261...21ff0, 0 logs, hash:0xa17...523bc') - .click('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"] button[class^="details"]') - .assert.containsText('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"] table[class^="txTable"] #decodedoutput', `{ + .click('#runTabView div[class^="create"]') + .pause(500) + .testFunction('f - transact (not payable)', + '0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc', + '[vm] from:0xca3...a733c, to:browser/Untitled.sol:TestContract.f() 0x692...77b3a, value:0 wei, data:0x261...21ff0, 0 logs, hash:0xa17...523bc', null, + `{ "0": "uint256: 8" }`) - .click('.instance button[title="g - transact (not payable)"]') - .waitForElementPresent('#editor-container div[class^="terminal"] span[id="tx0xb1532162e2e31397dc1e07ed0a1cf08f728e9b4487c6f9ed79d2f39410c92781"]') - .click('#editor-container div[class^="terminal"] span[id="tx0xb1532162e2e31397dc1e07ed0a1cf08f728e9b4487c6f9ed79d2f39410c92781"] button[class^="details"]') - .assert.containsText('#editor-container div[class^="terminal"] span[id="tx0xb1532162e2e31397dc1e07ed0a1cf08f728e9b4487c6f9ed79d2f39410c92781"] table[class^="txTable"] #decodedoutput', `{ + .pause(500) + .testFunction('g - transact (not payable)', + '0xb1532162e2e31397dc1e07ed0a1cf08f728e9b4487c6f9ed79d2f39410c92781', + '[vm] from:0xca3...a733c, to:browser/Untitled.sol:TestContract.g() 0x692...77b3a, value:0 wei, data:0xe21...79b8e, 0 logs, hash:0xb15...92781', null, `{ "0": "uint256: 345", "1": "string: comment_comment_", "2": "bool: true", "3": "uint256: 4" +}`).perform(() => { callback(null, browser) }) + }) +} + +function testReturnValues (browser, callback) { + contractHelper.testContracts(browser, 'returnValues.sol', sources[1]['browser/returnValues.sol'], ['browser/returnValues.sol:testReturnValues'], function () { + browser.click('.runView') + .click('#runTabView div[class^="create"]') + .pause(500) + .testFunction('retunValues1 - transact (not payable)', + '0x79dc928d149d2ade02ab610a8ae290636222d034d4adce0bb08a68401e3d1f7f', + '[vm] from:0xca3...a733c, to:browser/returnValues.sol:testReturnValues.retunValues1() 0x5e7...26e9f, value:0 wei, data:0x9ed...59eb7, 0 logs, hash:0x79d...d1f7f', + null, + `{ + "0": "bool: _b true", + "1": "uint256: _u 345", + "2": "int256: _i -345", + "3": "address: _a 0xca35b7d915458ef540ade6068dfe2f44e8fa733c" }`) - .end() + .pause(500) + .testFunction('retunValues2 - transact (not payable)', + '0x09175dcb30227b3af422d75786dbba3b0549985e5c7f59f86d12c7e1043ccb8c', + '[vm] from:0xca3...a733c, to:browser/returnValues.sol:testReturnValues.retunValues2() 0x5e7...26e9f, value:0 wei, data:0xf57...4036c, 0 logs, hash:0x091...ccb8c', null, `{ + "0": "bytes1: _b 0x12", + "1": "bytes2: _b2 0x1223", + "2": "bytes3: _b3 0x000000", + "3": "bytes: _blit 0x123498", + "4": "bytes5: _b5 0x0000043245", + "5": "bytes6: _b6 0x002345532532", + "6": "string: _str this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string", + "7": "bytes7: _b7 0x03252353253253", + "8": "bytes22: _b22 0x00000000000000000000325235235325325325235325", + "9": "bytes32: _b32 0x0000000000000000000000000000000000032523532532523532523532523532" +}`).pause(500).testFunction('retunValues3 - transact (not payable)', + '0x7faab07aeaafc8afe6bf283bb83be70c000dff381dec04e779354e354da14aff', + '[vm] from:0xca3...a733c, to:browser/returnValues.sol:testReturnValues.retunValues3() 0x5e7...26e9f, value:0 wei, data:0x033...e0a7d, 0 logs, hash:0x7fa...14aff', null, `{ + "0": "uint8: _en 2", + "1": "int256[5][]: _a1 1,-45,-78,56,60, -1,42,334,-45455,-446, 1,10,-5435,45,-7" +}`).perform(() => { callback(null, browser) }) }) } + +function testInputValues (browser, callback) { + contractHelper.testContracts(browser, 'inputValues.sol', sources[2]['browser/inputValues.sol'], ['browser/inputValues.sol:test'], function () { + browser.click('.runView') + .click('#runTabView div[class^="create"]') + .pause(500) + .testFunction('inputValue1 - transact (not payable)', + '0x917a873d27d105213eaf5461e14780387ccceb66fed574f8432d1963917832ae', + '[vm] from:0xca3...a733c, to:browser/inputValues.sol:test.inputValue1(uint256,int256,string) 0x8c1...401f5, value:0 wei, data:0xd69...00000, 0 logs, hash:0x917...832ae', + {types: 'uint256 _u, int256 _i, string _str', values: '"2343242", "-4324324", "string _ string _ string _ string _ string _ string _ string _ string _ string _ string _"'}, + `{ + "0": "uint256: _uret 2343242", + "1": "int256: _iret -4324324", + "2": "string: _strret string _ string _ string _ string _ string _ string _ string _ string _ string _ string _" +}`).pause(500).testFunction('inputValue2 - transact (not payable)', + '0x487d09e244853bcb108b3a22cd6ee57b6431e50869619c9b918e9764fc16ef7f', + '[vm] from:0xca3...a733c, to:browser/inputValues.sol:test.inputValue2(uint256[3],bytes8[4]) 0x8c1...401f5, value:0 wei, data:0x1b7...00000, 1 logs, hash:0x487...6ef7f', + {types: 'uint256[3] _n, bytes8[4] _b8', values: '[1,2,3], ["0x1234", "0x1234","0x1234","0x1234"]'}, + `{ + "0": "uint256[3]: _nret 1, 2, 3", + "1": "bytes8[4]: _b8ret 0x1234000000000000, 0x1234000000000000, 0x1234000000000000, 0x1234000000000000" +}`, `[ + { + "event": "event1", + "args": [ + "-123", + "000000000000000000000000000000000000000000000000000000000000007b", + "9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658", + "0x00001234", + "test _ test _ test _ test test _ test test _ test test _ test test _ test test _ test test _ test " + ] + } +]`) + .perform(() => { callback(null, browser) }) + }) +} + +// @TODO test: bytes8[3][] type as input + +var sources = [ + {'browser/Untitled.sol': `pragma solidity ^0.4.0; + contract TestContract { function f() returns (uint) { return 8; } + function g() returns (uint, string, bool, uint) { + uint payment = 345; + bool payed = true; + string memory comment = "comment_comment_"; + uint month = 4; + return (payment, comment, payed, month); } }`}, + {'browser/returnValues.sol': `pragma solidity ^0.4.0; + contract testReturnValues { + enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill } + function retunValues1 () returns (bool _b, uint _u, int _i, address _a) { + _b = true; + _u = 345; + _i = -345; + _a = msg.sender; + } + + function retunValues2 () returns (byte _b, bytes2 _b2, bytes3 _b3, bytes _blit, bytes5 _b5, bytes6 _b6, string _str, bytes7 _b7, bytes22 _b22, bytes32 _b32) { + _b = 0x12; + _b2 = 0x1223; + _b5 = 0x43245; + _b6 = 0x2345532532; + _b7 = 0x3252353253253; + _b22 = 0x325235235325325325235325; + _b32 = 0x32523532532523532523532523532; + _blit = hex"123498"; + _str = "this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string _ this is a long string"; + } + + function retunValues3 () returns (ActionChoices _en, int[5][] _a1) { + _en = ActionChoices.GoStraight; + int[5][] memory a = new int[5][](3); + a[0] = [int(1),-45,-78,56,60]; + a[1] = [int(-1),42,334,-45455,-446]; + a[2] = [int(1),10,-5435,45,-7]; + _a1 = a; + } + }`}, + {'browser/inputValues.sol': `pragma solidity ^0.4.0; + contract test { + event event1(int _i, uint indexed _u, string indexed _str, bytes4 _b, string _notIndexed); + function inputValue1 (uint _u, int _i, string _str) returns (uint _uret, int _iret, string _strret) { + _uret = _u; + _iret = _i; + _strret = _str; + } + function inputValue2 (uint[3] _n, bytes8[4] _b8) returns (uint[3] _nret, bytes8[4] _b8ret){ + _nret = _n; + _b8ret = _b8; + event1(-123, 123, "test", 0x1234, "test _ test _ test _ test test _ test test _ test test _ test test _ test test _ test test _ test "); + } + }`} +] diff --git a/test-browser/tests/fileExplorer.js b/test-browser/tests/fileExplorer.js index 581d6f2e62..26b43f816b 100644 --- a/test-browser/tests/fileExplorer.js +++ b/test-browser/tests/fileExplorer.js @@ -4,9 +4,8 @@ var examples = require('../../src/app/editor/example-contracts') var init = require('../helpers/init') var sauce = require('./sauce') -var sources = { - 'sources': { - 'browser/ballot.sol': examples.ballot.content, +var sources = [ + {'browser/ballot.sol': examples.ballot.content, 'browser/test/client/credit.sol': '', 'browser/src/voting.sol': '', 'browser/src/leasing.sol': '', @@ -18,7 +17,7 @@ var sources = { 'browser/app/solidity/mode.sol': true, 'browser/app/ethereum/constitution.sol': true } -} +] module.exports = { before: function (browser, done) { diff --git a/test-browser/tests/new-file-test.js b/test-browser/tests/new-file-test.js deleted file mode 100644 index 35e34a07aa..0000000000 --- a/test-browser/tests/new-file-test.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict' -var init = require('../helpers/init') -var sauce = require('./sauce') - -module.exports = { - before: function (browser, done) { - init(browser, done) - }, - 'New file test': function (browser) { - browser - .waitForElementVisible('.newFile', 10000) - .click('.newFile') - .pause(500) - .assert.containsText('.active', 'Untitled') - .end() - }, - tearDown: sauce -} diff --git a/test-browser/tests/sharedFolderExplorer.js b/test-browser/tests/sharedFolderExplorer.js index 9ec29539d6..cc3bf1f2a3 100644 --- a/test-browser/tests/sharedFolderExplorer.js +++ b/test-browser/tests/sharedFolderExplorer.js @@ -3,11 +3,11 @@ var contractHelper = require('../helpers/contracts') var init = require('../helpers/init') var sauce = require('./sauce') -var sources = { - 'sources': { +var sources = [ + { 'localhost/folder1/contract2.sol': 'contract test2 { function get () returns (uint) { return 11; }}' } -} +] module.exports = { before: function (browser, done) { @@ -43,7 +43,7 @@ function runTests (browser, testData) { .assert.containsText('[data-path="localhost/folder1/contract2.sol"]', 'contract2.sol') .click('[data-path="localhost/folder1/contract2.sol"]') .waitForElementPresent('#compileTabView select option', 50000, true, function () { - contractHelper.checkCompiledContracts(browser, ['localhost/folder1/contract2.sol:test2'], function () { + contractHelper.verifyContract(browser, ['localhost/folder1/contract2.sol:test2'], function () { browser.click('.websocketconn').end() }) }) diff --git a/test-browser/tests/simpleContract.js b/test-browser/tests/simpleContract.js index 0e0aad0dd8..c3778dc6d2 100644 --- a/test-browser/tests/simpleContract.js +++ b/test-browser/tests/simpleContract.js @@ -2,12 +2,7 @@ var contractHelper = require('../helpers/contracts') var init = require('../helpers/init') var sauce = require('./sauce') - -var sources = { - 'sources': { - 'browser/Untitled.sol': 'contract test1 {} contract test2 {}' - } -} +var async = require('async') module.exports = { before: function (browser, done) { @@ -26,7 +21,199 @@ function runTests (browser) { browser .waitForElementVisible('.newFile', 10000) .click('.compileView') - contractHelper.testContracts(browser, sources.sources['browser/Untitled.sol'], ['browser/Untitled.sol:test1', 'browser/Untitled.sol:test2'], function () { - browser.end() + .click('#filepanel label[data-path="browser"]') + .perform(() => { + // the first fn is used to pass browser to the other ones. + async.waterfall([function (callback) { callback(null, browser) }, + testSimpleContract, + testSuccessImport, + testFailedImport, + testGitHubImport], + function () { + browser.end() + }) + }) +} + +function testSimpleContract (browser, callback) { + contractHelper.testContracts(browser, 'Untitled.sol', sources[0]['browser/Untitled.sol'], ['browser/Untitled.sol:test1', 'browser/Untitled.sol:test2'], function () { + callback(null, browser) }) } + +function testSuccessImport (browser, callback) { + contractHelper.addFile(browser, 'Untitled1.sol', sources[1]['browser/Untitled1.sol'], () => { + contractHelper.addFile(browser, 'Untitled2.sol', sources[1]['browser/Untitled2.sol'], () => { + contractHelper.switchFile(browser, 'browser/Untitled1.sol', function () { + contractHelper.verifyContract(browser, ['browser/Untitled1.sol:test6', 'browser/Untitled2.sol:test4', 'browser/Untitled2.sol:test5'], function () { + callback(null, browser) + }) + }) + }) + }) +} + +function testFailedImport (browser, callback) { + contractHelper.addFile(browser, 'Untitled3.sol', sources[2]['browser/Untitled3.sol'], () => { + browser.assert.containsText('#compileTabView .error pre', 'Unable to import "browser/Untitled11.sol": File not found') + .perform(function () { + callback(null, browser) + }) + }) +} + +function testGitHubImport (browser, callback) { + // cant' import from github from Travis ... (got "Forbidden"") + /* + contractHelper.addFile(browser, 'Untitled4.sol', sources[3]['browser/Untitled4.sol'], () => { + browser.pause(10000) + .perform(function () { + contractHelper.verifyContract(browser, ['browser/Untitled4.sol:test7', 'github.com/ethereum/ens/contracts/AbstractENS.sol:AbstractENS', 'github.com/ethereum/ens/contracts/ENS.sol:ENS'], function () { + callback(null, browser) + }) + }) + }) + */ + callback(null, browser) +} + +var abstractENS = `pragma solidity ^0.4.0; + +contract AbstractENS { + function owner(bytes32 node) constant returns(address); + function resolver(bytes32 node) constant returns(address); + function ttl(bytes32 node) constant returns(uint64); + function setOwner(bytes32 node, address owner); + function setSubnodeOwner(bytes32 node, bytes32 label, address owner); + function setResolver(bytes32 node, address resolver); + function setTTL(bytes32 node, uint64 ttl); + + // Logged when the owner of a node assigns a new owner to a subnode. + event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); + + // Logged when the owner of a node transfers ownership to a new account. + event Transfer(bytes32 indexed node, address owner); + + // Logged when the resolver for a node changes. + event NewResolver(bytes32 indexed node, address resolver); + + // Logged when the TTL of a node changes + event NewTTL(bytes32 indexed node, uint64 ttl); +}` + +var ENS = `pragma solidity ^0.4.0; + +import './AbstractENS.sol'; + +/** + * The ENS registry contract. + */ +contract ENS is AbstractENS { + struct Record { + address owner; + address resolver; + uint64 ttl; + } + + mapping(bytes32=>Record) records; + + // Permits modifications only by the owner of the specified node. + modifier only_owner(bytes32 node) { + if (records[node].owner != msg.sender) throw; + _; + } + + /** + * Constructs a new ENS registrar. + */ + function ENS() { + records[0].owner = msg.sender; + } + + /** + * Returns the address that owns the specified node. + */ + function owner(bytes32 node) constant returns (address) { + return records[node].owner; + } + + /** + * Returns the address of the resolver for the specified node. + */ + function resolver(bytes32 node) constant returns (address) { + return records[node].resolver; + } + + /** + * Returns the TTL of a node, and any records associated with it. + */ + function ttl(bytes32 node) constant returns (uint64) { + return records[node].ttl; + } + + /** + * Transfers ownership of a node to a new address. May only be called by the current + * owner of the node. + * @param node The node to transfer ownership of. + * @param owner The address of the new owner. + */ + function setOwner(bytes32 node, address owner) only_owner(node) { + Transfer(node, owner); + records[node].owner = owner; + } + + /** + * Transfers ownership of a subnode sha3(node, label) to a new address. May only be + * called by the owner of the parent node. + * @param node The parent node. + * @param label The hash of the label specifying the subnode. + * @param owner The address of the new owner. + */ + function setSubnodeOwner(bytes32 node, bytes32 label, address owner) only_owner(node) { + var subnode = sha3(node, label); + NewOwner(node, label, owner); + records[subnode].owner = owner; + } + + /** + * Sets the resolver address for the specified node. + * @param node The node to update. + * @param resolver The address of the resolver. + */ + function setResolver(bytes32 node, address resolver) only_owner(node) { + NewResolver(node, resolver); + records[node].resolver = resolver; + } + + /** + * Sets the TTL for the specified node. + * @param node The node to update. + * @param ttl The TTL in seconds. + */ + function setTTL(bytes32 node, uint64 ttl) only_owner(node) { + NewTTL(node, ttl); + records[node].ttl = ttl; + } +}` + +var sources = [ + { + 'browser/Untitled.sol': 'contract test1 {} contract test2 {}' + }, + { + 'browser/Untitled1.sol': 'import "./Untitled2.sol"; contract test6 {}', + 'browser/Untitled2.sol': 'contract test4 {} contract test5 {}' + }, + { + 'browser/Untitled3.sol': 'import "./Untitled11.sol"; contract test6 {}' + }, + { + 'browser/Untitled4.sol': 'import "github.com/ethereum/ens/contracts/ENS.sol"; contract test7 {}', + 'github.com/ethereum/ens/contracts/ENS.sol': ENS + }, + { + 'browser/Untitled4.sol': 'import "github.com/ethereum/ens/contracts/ENS.sol"; contract test7 {}', + 'github.com/ethereum/ens/contracts/ENS.sol': ENS, + 'github.com/ethereum/ens/contracts/AbstractENS.sol': abstractENS + } +] diff --git a/test-browser/tests/staticanalysis.js b/test-browser/tests/staticanalysis.js index fb7cf9861e..62f7b1aea7 100644 --- a/test-browser/tests/staticanalysis.js +++ b/test-browser/tests/staticanalysis.js @@ -4,17 +4,16 @@ var init = require('../helpers/init') var sauce = require('./sauce') var dom = require('../helpers/dom') -var sources = { - 'sources': { +var sources = [ + { 'browser/Untitled.sol': ` contract test1 { address test = tx.origin; } contract test2 {} contract TooMuchGas { uint x; function() { x++; } -}` - } -} +}`} +] module.exports = { before: function (browser, done) { @@ -33,7 +32,7 @@ function runTests (browser) { browser .waitForElementVisible('.newFile', 10000) .click('.compileView') - contractHelper.testContracts(browser, sources.sources['browser/Untitled.sol'], ['browser/Untitled.sol:TooMuchGas', 'browser/Untitled.sol:test1', 'browser/Untitled.sol:test2'], function () { + contractHelper.testContracts(browser, 'Untitled.sol', sources[0]['browser/Untitled.sol'], ['browser/Untitled.sol:TooMuchGas', 'browser/Untitled.sol:test1', 'browser/Untitled.sol:test2'], function () { browser .click('.staticanalysisView') .click('#staticanalysisView button')