mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Some tests and bugfixes for the compiler.
This commit is contained in:
parent
6951657c59
commit
dab09c595a
210
solidityEndToEndTest.cpp
Normal file
210
solidityEndToEndTest.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
|
||||
/*
|
||||
This file is part of cpp-ethereum.
|
||||
|
||||
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
cpp-ethereum is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @author Christian <c@ethdev.com>
|
||||
* @date 2014
|
||||
* Unit tests for the solidity expression compiler, testing the behaviour of the code.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <libethereum/State.h>
|
||||
#include <libethereum/Executive.h>
|
||||
#include <libsolidity/CompilerStack.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
|
||||
class ExecutionFramework
|
||||
{
|
||||
public:
|
||||
ExecutionFramework() { g_logVerbosity = 0; }
|
||||
|
||||
bytes compileAndRun(std::string const& _sourceCode)
|
||||
{
|
||||
bytes code = dev::solidity::CompilerStack::compile(_sourceCode);
|
||||
eth::Executive ex(m_state);
|
||||
BOOST_REQUIRE(!ex.create(Address(), 0, m_gasPrice, m_gas, &code, Address()));
|
||||
BOOST_REQUIRE(ex.go());
|
||||
ex.finalize();
|
||||
m_contractAddress = ex.newAddress();
|
||||
return ex.out().toBytes();
|
||||
}
|
||||
|
||||
bytes callFunction(byte _index, bytes const& _data)
|
||||
{
|
||||
bytes data = bytes(1, _index) + _data;
|
||||
eth::Executive ex(m_state);
|
||||
BOOST_REQUIRE(!ex.call(m_contractAddress, Address(), 0, m_gasPrice, &data, m_gas, Address()));
|
||||
BOOST_REQUIRE(ex.go());
|
||||
ex.finalize();
|
||||
return ex.out().toBytes();
|
||||
}
|
||||
|
||||
bytes callFunction(byte _index, u256 const& _argument)
|
||||
{
|
||||
return callFunction(_index, toBigEndian(_argument));
|
||||
}
|
||||
|
||||
private:
|
||||
Address m_contractAddress;
|
||||
eth::State m_state;
|
||||
u256 const m_gasPrice = 100 * eth::szabo;
|
||||
u256 const m_gas = 1000000;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f(uint a) returns(uint d) { return a * 7; }\n"
|
||||
"}\n";
|
||||
ExecutionFramework framework;
|
||||
framework.compileAndRun(sourceCode);
|
||||
u256 a = 0x200030004;
|
||||
bytes result = framework.callFunction(0, a);
|
||||
BOOST_CHECK(result == toBigEndian(a * 7));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_contract)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
"}\n";
|
||||
ExecutionFramework framework;
|
||||
framework.compileAndRun(sourceCode);
|
||||
BOOST_CHECK(framework.callFunction(0, bytes()).empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(recursive_calls)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f(uint n) returns(uint nfac) {\n"
|
||||
" if (n <= 1) return 1;\n"
|
||||
" else return n * f(n - 1);\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ExecutionFramework framework;
|
||||
framework.compileAndRun(sourceCode);
|
||||
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(while_loop)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function f(uint n) returns(uint nfac) {\n"
|
||||
" nfac = 1;\n"
|
||||
" var i = 2;\n"
|
||||
" while (i <= n) nfac *= i++;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ExecutionFramework framework;
|
||||
framework.compileAndRun(sourceCode);
|
||||
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(calling_other_functions)
|
||||
{
|
||||
// note that the index of a function is its index in the sorted sequence of functions
|
||||
char const* sourceCode = "contract collatz {\n"
|
||||
" function run(uint x) returns(uint y) {\n"
|
||||
" while ((y = x) > 1) {\n"
|
||||
" if (x % 2 == 0) x = evenStep(x);\n"
|
||||
" else x = oddStep(x);\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" function evenStep(uint x) returns(uint y) {\n"
|
||||
" return x / 2;\n"
|
||||
" }\n"
|
||||
" function oddStep(uint x) returns(uint y) {\n"
|
||||
" return 3 * x + 1;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ExecutionFramework framework;
|
||||
framework.compileAndRun(sourceCode);
|
||||
BOOST_CHECK(framework.callFunction(2, u256(0)) == toBigEndian(u256(0)));
|
||||
BOOST_CHECK(framework.callFunction(2, u256(1)) == toBigEndian(u256(1)));
|
||||
BOOST_CHECK(framework.callFunction(2, u256(2)) == toBigEndian(u256(1)));
|
||||
BOOST_CHECK(framework.callFunction(2, u256(8)) == toBigEndian(u256(1)));
|
||||
BOOST_CHECK(framework.callFunction(2, u256(127)) == toBigEndian(u256(1)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(many_local_variables)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function run(uint x1, uint x2, uint x3) returns(uint y) {\n"
|
||||
" var a = 0x1; var b = 0x10; var c = 0x100;\n"
|
||||
" y = a + b + c + x1 + x2 + x3;\n"
|
||||
" y += b + x2;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ExecutionFramework framework;
|
||||
framework.compileAndRun(sourceCode);
|
||||
BOOST_CHECK(framework.callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000)))
|
||||
== toBigEndian(u256(0x121121)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_return_values)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function run(bool x1, uint x2) returns(uint y1, bool y2, uint y3) {\n"
|
||||
" y1 = x2; y2 = x1;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ExecutionFramework framework;
|
||||
framework.compileAndRun(sourceCode);
|
||||
BOOST_CHECK(framework.callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
|
||||
== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(short_circuiting)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" function run(uint x) returns(uint y) {\n"
|
||||
" x == 0 || ((x = 8) > 0);\n"
|
||||
" return x;"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ExecutionFramework framework;
|
||||
framework.compileAndRun(sourceCode);
|
||||
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0)));
|
||||
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8)));
|
||||
}
|
||||
|
||||
//@todo test smaller types
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
}
|
||||
} // end namespaces
|
||||
|
@ -177,8 +177,9 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
|
||||
byte(eth::Instruction::GT),
|
||||
byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4
|
||||
byte(eth::Instruction::DUP1),
|
||||
byte(eth::Instruction::PUSH1), 0x14,
|
||||
byte(eth::Instruction::PUSH1), 0x15,
|
||||
byte(eth::Instruction::JUMPI), // short-circuit if it is true
|
||||
byte(eth::Instruction::POP),
|
||||
byte(eth::Instruction::PUSH1), 0x2,
|
||||
byte(eth::Instruction::PUSH1), 0x9,
|
||||
byte(eth::Instruction::EQ),
|
||||
|
Loading…
Reference in New Issue
Block a user