aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt22
-rw-r--r--test/RPCSession.cpp49
-rw-r--r--test/RPCSession.h10
-rwxr-xr-xtest/cmdlineTests.sh23
-rw-r--r--test/fuzzer.cpp91
-rw-r--r--test/libsolidity/InlineAssembly.cpp124
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp36
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp77
8 files changed, 362 insertions, 70 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 609aaab3..4d56ec9d 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -7,23 +7,9 @@ aux_source_directory(libsolidity SRC_LIST)
aux_source_directory(contracts SRC_LIST)
aux_source_directory(liblll SRC_LIST)
-get_filename_component(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
+list(REMOVE_ITEM SRC_LIST "./fuzzer.cpp")
-# search for test names and create ctest tests
-enable_testing()
-foreach(file ${SRC_LIST})
- file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/${file} test_list_raw REGEX "BOOST_.*TEST_(SUITE|CASE)")
- set(TestSuite "DEFAULT")
- foreach(test_raw ${test_list_raw})
- string(REGEX REPLACE ".*TEST_(SUITE|CASE)\\(([^ ,\\)]*).*" "\\1 \\2" test ${test_raw})
- if(test MATCHES "^SUITE .*")
- string(SUBSTRING ${test} 6 -1 TestSuite)
- elseif(test MATCHES "^CASE .*")
- string(SUBSTRING ${test} 5 -1 TestCase)
- add_test(NAME ${TestSuite}/${TestCase} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND test -t ${TestSuite}/${TestCase})
- endif(test MATCHES "^SUITE .*")
- endforeach(test_raw)
-endforeach(file)
+get_filename_component(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
file(GLOB HEADERS "*.h" "*/*.h")
set(EXECUTABLE soltest)
@@ -34,5 +20,5 @@ eth_use(${EXECUTABLE} REQUIRED Solidity::solidity Solidity::lll)
include_directories(BEFORE ..)
target_link_libraries(${EXECUTABLE} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
-enable_testing()
-set(CTEST_OUTPUT_ON_FAILURE TRUE)
+add_executable(solfuzzer fuzzer.cpp)
+target_link_libraries(solfuzzer soljson)
diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp
index ff00d783..be8774bc 100644
--- a/test/RPCSession.cpp
+++ b/test/RPCSession.cpp
@@ -16,19 +16,20 @@
The Implementation originally from https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx
*/
-/** @file RPCSession.cpp
- * @author Dimtiry Khokhlov <dimitry@ethdev.com>
- * @author Alex Beregszaszi
- * @date 2016
- */
+/// @file RPCSession.cpp
+/// Low-level IPC communication between the test framework and the Ethereum node.
+
+#include "RPCSession.h"
-#include <string>
-#include <stdio.h>
-#include <thread>
#include <libdevcore/CommonData.h>
+
#include <json/reader.h>
#include <json/writer.h>
-#include "RPCSession.h"
+
+#include <string>
+#include <stdio.h>
+#include <thread>
+#include <chrono>
using namespace std;
using namespace dev;
@@ -107,13 +108,24 @@ string IPCSocket::sendRequest(string const& _req)
return string(m_readBuf, m_readBuf + cbRead);
#else
if (send(m_socket, _req.c_str(), _req.length(), 0) != (ssize_t)_req.length())
- BOOST_FAIL("Writing on IPC failed");
+ BOOST_FAIL("Writing on IPC failed.");
- ssize_t ret = recv(m_socket, m_readBuf, sizeof(m_readBuf), 0);
+ auto start = chrono::steady_clock::now();
+ ssize_t ret;
+ do
+ {
+ ret = recv(m_socket, m_readBuf, sizeof(m_readBuf), 0);
+ // Also consider closed socket an error.
+ if (ret < 0)
+ BOOST_FAIL("Reading on IPC failed.");
+ }
+ while (
+ ret == 0 &&
+ chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count() < m_readTimeOutMS
+ );
- // Also consider closed socket an error.
- if (ret <= 0)
- BOOST_FAIL("Reading on IPC failed");
+ if (ret == 0)
+ BOOST_FAIL("Timeout reading on IPC.");
return string(m_readBuf, m_readBuf + ret);
#endif
@@ -186,12 +198,17 @@ string RPCSession::eth_getStorageRoot(string const& _address, string const& _blo
void RPCSession::personal_unlockAccount(string const& _address, string const& _password, int _duration)
{
- BOOST_REQUIRE(rpcCall("personal_unlockAccount", { quote(_address), quote(_password), to_string(_duration) }) == true);
+ BOOST_REQUIRE_MESSAGE(
+ rpcCall("personal_unlockAccount", { quote(_address), quote(_password), to_string(_duration) }),
+ "Error unlocking account " + _address
+ );
}
string RPCSession::personal_newAccount(string const& _password)
{
- return rpcCall("personal_newAccount", { quote(_password) }).asString();
+ string addr = rpcCall("personal_newAccount", { quote(_password) }).asString();
+ BOOST_MESSAGE("Created account " + addr);
+ return addr;
}
void RPCSession::test_setChainParams(vector<string> const& _accounts)
diff --git a/test/RPCSession.h b/test/RPCSession.h
index 414db323..843036e1 100644
--- a/test/RPCSession.h
+++ b/test/RPCSession.h
@@ -28,11 +28,13 @@
#include <sys/un.h>
#endif
+#include <json/value.h>
+
+#include <boost/test/unit_test.hpp>
+
#include <string>
#include <stdio.h>
#include <map>
-#include <json/value.h>
-#include <boost/test/unit_test.hpp>
#if defined(_WIN32)
class IPCSocket : public boost::noncopyable
@@ -60,8 +62,12 @@ public:
std::string const& path() const { return m_path; }
private:
+
std::string m_path;
int m_socket;
+ /// Socket read timeout in milliseconds. Needs to be large because the key generation routine
+ /// might take long.
+ unsigned static constexpr m_readTimeOutMS = 15000;
char m_readBuf[512000];
};
#endif
diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh
index fc48654a..cb714efe 100755
--- a/test/cmdlineTests.sh
+++ b/test/cmdlineTests.sh
@@ -31,7 +31,7 @@ set -e
REPO_ROOT="$(dirname "$0")"/..
SOLC="$REPO_ROOT/build/solc/solc"
- # Compile all files in std and examples.
+# Compile all files in std and examples.
for f in "$REPO_ROOT"/std/*.sol
do
@@ -46,6 +46,21 @@ do
test -z "$output" -a "$failed" -eq 0
done
-# Test library checksum
-echo 'contact C {}' | "$SOLC" --link --libraries a:0x90f20564390eAe531E810af625A22f51385Cd222
-! echo 'contract C {}' | "$SOLC" --link --libraries a:0x80f20564390eAe531E810af625A22f51385Cd222 2>/dev/null
+echo "Testing library checksum..."
+echo '' | "$SOLC" --link --libraries a:0x90f20564390eAe531E810af625A22f51385Cd222
+! echo '' | "$SOLC" --link --libraries a:0x80f20564390eAe531E810af625A22f51385Cd222 2>/dev/null
+
+echo "Testing soljson via the fuzzer..."
+TMPDIR=$(mktemp -d)
+(
+ cd "$REPO_ROOT"
+ REPO_ROOT=$(pwd) # make it absolute
+ cd "$TMPDIR"
+ "$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/test/contracts/* "$REPO_ROOT"/test/libsolidity/*EndToEnd*
+ for f in *.sol
+ do
+ "$REPO_ROOT"/build/test/solfuzzer < "$f"
+ done
+)
+rm -rf "$TMPDIR"
+echo "Done."
diff --git a/test/fuzzer.cpp b/test/fuzzer.cpp
new file mode 100644
index 00000000..410313c5
--- /dev/null
+++ b/test/fuzzer.cpp
@@ -0,0 +1,91 @@
+/*
+ This file is part of solidity.
+
+ solidity 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.
+
+ solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Executable for use with AFL <http://lcamtuf.coredump.cx/afl>.
+ * Reads a single source from stdin and signals a failure for internal errors.
+ */
+
+#include <json/json.h>
+
+#include <string>
+#include <iostream>
+
+using namespace std;
+
+extern "C"
+{
+extern char const* compileJSON(char const* _input, bool _optimize);
+}
+
+string contains(string const& _haystack, vector<string> const& _needles)
+{
+ for (string const& needle: _needles)
+ if (_haystack.find(needle) != string::npos)
+ return needle;
+ return "";
+}
+
+int main()
+{
+ string input;
+ while (!cin.eof())
+ {
+ string s;
+ getline(cin, s);
+ input += s + '\n';
+ }
+
+ bool optimize = true;
+ string outputString(compileJSON(input.c_str(), optimize));
+ Json::Value outputJson;
+ if (!Json::Reader().parse(outputString, outputJson))
+ {
+ cout << "Compiler produced invalid JSON output." << endl;
+ abort();
+ }
+ if (outputJson.isMember("errors"))
+ {
+ if (!outputJson["errors"].isArray())
+ {
+ cout << "Output JSON has \"errors\" but it is not an array." << endl;
+ abort();
+ }
+ for (Json::Value const& error: outputJson["errors"])
+ {
+ string invalid = contains(error.asString(), vector<string>{
+ "Internal compiler error",
+ "Exception during compilation",
+ "Unknown exception during compilation",
+ "Unknown exception while generating contract data output",
+ "Unknown exception while generating formal method output",
+ "Unknown exception while generating source name output",
+ "Unknown error while generating JSON"
+ });
+ if (!invalid.empty())
+ {
+ cout << "Invalid error: \"" << error.asString() << "\"" << endl;
+ abort();
+ }
+ }
+ }
+ else if (!outputJson.isMember("contracts"))
+ {
+ cout << "Output JSON has neither \"errors\" nor \"contracts\"." << endl;
+ abort();
+ }
+ return 0;
+}
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index 8744d96f..9035599b 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -20,14 +20,19 @@
* Unit tests for inline assembly.
*/
-#include <string>
-#include <memory>
-#include <libevmasm/Assembly.h>
-#include <libsolidity/parsing/Scanner.h>
+#include "../TestHelper.h"
+
#include <libsolidity/inlineasm/AsmStack.h>
+#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/ast/AST.h>
-#include "../TestHelper.h"
+#include <test/libsolidity/ErrorCheck.h>
+#include <libevmasm/Assembly.h>
+
+#include <boost/optional.hpp>
+
+#include <string>
+#include <memory>
using namespace std;
@@ -41,31 +46,44 @@ namespace test
namespace
{
-bool successParse(std::string const& _source, bool _assemble = false, bool _allowWarnings = true)
+boost::optional<Error> parseAndReturnFirstError(string const& _source, bool _assemble = false, bool _allowWarnings = true)
{
assembly::InlineAssemblyStack stack;
+ bool success = false;
try
{
- if (!stack.parse(std::make_shared<Scanner>(CharStream(_source))))
- return false;
- if (_assemble)
- {
+ success = stack.parse(std::make_shared<Scanner>(CharStream(_source)));
+ if (success && _assemble)
stack.assemble();
- if (!stack.errors().empty())
- if (!_allowWarnings || !Error::containsOnlyWarnings(stack.errors()))
- return false;
- }
}
catch (FatalError const&)
{
- if (Error::containsErrorOfType(stack.errors(), Error::Type::ParserError))
- return false;
+ BOOST_FAIL("Fatal error leaked.");
+ success = false;
+ }
+ if (!success)
+ {
+ BOOST_CHECK_EQUAL(stack.errors().size(), 1);
+ return *stack.errors().front();
}
- if (Error::containsErrorOfType(stack.errors(), Error::Type::ParserError))
- return false;
+ else
+ {
+ // If success is true, there might still be an error in the assembly stage.
+ if (_allowWarnings && Error::containsOnlyWarnings(stack.errors()))
+ return {};
+ else if (!stack.errors().empty())
+ {
+ if (!_allowWarnings)
+ BOOST_CHECK_EQUAL(stack.errors().size(), 1);
+ return *stack.errors().front();
+ }
+ }
+ return {};
+}
- BOOST_CHECK(Error::containsOnlyWarnings(stack.errors()));
- return true;
+bool successParse(std::string const& _source, bool _assemble = false, bool _allowWarnings = true)
+{
+ return !parseAndReturnFirstError(_source, _assemble, _allowWarnings);
}
bool successAssemble(string const& _source, bool _allowWarnings = true)
@@ -73,6 +91,14 @@ bool successAssemble(string const& _source, bool _allowWarnings = true)
return successParse(_source, true, _allowWarnings);
}
+Error expectError(std::string const& _source, bool _assemble, bool _allowWarnings = false)
+{
+
+ auto error = parseAndReturnFirstError(_source, _assemble, _allowWarnings);
+ BOOST_REQUIRE(error);
+ return *error;
+}
+
void parsePrintCompare(string const& _source)
{
assembly::InlineAssemblyStack stack;
@@ -83,6 +109,21 @@ void parsePrintCompare(string const& _source)
}
+#define CHECK_ERROR(text, assemble, typ, substring) \
+do \
+{ \
+ Error err = expectError((text), (assemble), false); \
+ BOOST_CHECK(err.type() == (Error::Type::typ)); \
+ BOOST_CHECK(searchErrorMessage(err, (substring))); \
+} while(0)
+
+#define CHECK_PARSE_ERROR(text, type, substring) \
+CHECK_ERROR(text, false, type, substring)
+
+#define CHECK_ASSEMBLE_ERROR(text, type, substring) \
+CHECK_ERROR(text, true, type, substring)
+
+
BOOST_AUTO_TEST_SUITE(SolidityInlineAssembly)
@@ -159,6 +200,21 @@ BOOST_AUTO_TEST_CASE(blocks)
BOOST_CHECK(successParse("{ let x := 7 { let y := 3 } { let z := 2 } }"));
}
+BOOST_AUTO_TEST_CASE(function_definitions)
+{
+ BOOST_CHECK(successParse("{ function f() { } function g(a) -> (x) { } }"));
+}
+
+BOOST_AUTO_TEST_CASE(function_definitions_multiple_args)
+{
+ BOOST_CHECK(successParse("{ function f(a, d) { } function g(a, d) -> (x, y) { } }"));
+}
+
+BOOST_AUTO_TEST_CASE(function_calls)
+{
+ BOOST_CHECK(successParse("{ g(1, 2, f(mul(2, 3))) x() }"));
+}
+
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(Printing)
@@ -209,6 +265,16 @@ BOOST_AUTO_TEST_CASE(print_string_literal_unicode)
parsePrintCompare(parsed);
}
+BOOST_AUTO_TEST_CASE(function_definitions_multiple_args)
+{
+ parsePrintCompare("{\n function f(a, d)\n {\n mstore(a, d)\n }\n function g(a, d) -> (x, y)\n {\n }\n}");
+}
+
+BOOST_AUTO_TEST_CASE(function_calls)
+{
+ parsePrintCompare("{\n g(1, mul(2, x), f(mul(2, 3)))\n x()\n}");
+}
+
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(Analysis)
@@ -220,7 +286,7 @@ BOOST_AUTO_TEST_CASE(string_literals)
BOOST_AUTO_TEST_CASE(oversize_string_literals)
{
- BOOST_CHECK(!successAssemble("{ let x := \"123456789012345678901234567890123\" }"));
+ CHECK_ASSEMBLE_ERROR("{ let x := \"123456789012345678901234567890123\" }", TypeError, "String literal too long");
}
BOOST_AUTO_TEST_CASE(assignment_after_tag)
@@ -230,15 +296,16 @@ BOOST_AUTO_TEST_CASE(assignment_after_tag)
BOOST_AUTO_TEST_CASE(magic_variables)
{
- BOOST_CHECK(!successAssemble("{ this }"));
- BOOST_CHECK(!successAssemble("{ ecrecover }"));
+ CHECK_ASSEMBLE_ERROR("{ this pop }", DeclarationError, "Identifier not found or not unique");
+ CHECK_ASSEMBLE_ERROR("{ ecrecover pop }", DeclarationError, "Identifier not found or not unique");
BOOST_CHECK(successAssemble("{ let ecrecover := 1 ecrecover }"));
}
BOOST_AUTO_TEST_CASE(imbalanced_stack)
{
BOOST_CHECK(successAssemble("{ 1 2 mul pop }", false));
- BOOST_CHECK(!successAssemble("{ 1 }", false));
+ CHECK_ASSEMBLE_ERROR("{ 1 }", Warning, "Inline assembly block is not balanced. It leaves");
+ CHECK_ASSEMBLE_ERROR("{ pop }", Warning, "Inline assembly block is not balanced. It takes");
BOOST_CHECK(successAssemble("{ let x := 4 7 add }", false));
}
@@ -254,20 +321,17 @@ BOOST_AUTO_TEST_CASE(designated_invalid_instruction)
BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_declaration)
{
- // Error message: "Cannot use instruction names for identifier names."
- BOOST_CHECK(!successAssemble("{ let gas := 1 }"));
+ CHECK_ASSEMBLE_ERROR("{ let gas := 1 }", ParserError, "Cannot use instruction names for identifier names.");
}
BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_assignment)
{
- // Error message: "Identifier expected, got instruction name."
- BOOST_CHECK(!successAssemble("{ 2 =: gas }"));
+ CHECK_ASSEMBLE_ERROR("{ 2 =: gas }", ParserError, "Identifier expected, got instruction name.");
}
BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_functional_assignment)
{
- // Error message: "Cannot use instruction names for identifier names."
- BOOST_CHECK(!successAssemble("{ gas := 2 }"));
+ CHECK_ASSEMBLE_ERROR("{ gas := 2 }", ParserError, "Label name / variable name must precede \":\"");
}
BOOST_AUTO_TEST_CASE(revert)
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 19665a26..130b0d3a 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -1681,6 +1681,42 @@ BOOST_AUTO_TEST_CASE(send_ether)
BOOST_CHECK_EQUAL(balanceAt(address), amount);
}
+BOOST_AUTO_TEST_CASE(transfer_ether)
+{
+ char const* sourceCode = R"(
+ contract A {
+ function A() payable {}
+ function a(address addr, uint amount) returns (uint) {
+ addr.transfer(amount);
+ return this.balance;
+ }
+ function b(address addr, uint amount) {
+ addr.transfer(amount);
+ }
+ }
+
+ contract B {
+ }
+
+ contract C {
+ function () payable {
+ throw;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "B");
+ u160 const nonPayableRecipient = m_contractAddress;
+ compileAndRun(sourceCode, 0, "C");
+ u160 const oogRecipient = m_contractAddress;
+ compileAndRun(sourceCode, 20, "A");
+ u160 payableRecipient(23);
+ BOOST_CHECK(callContractFunction("a(address,uint256)", payableRecipient, 10) == encodeArgs(10));
+ BOOST_CHECK_EQUAL(balanceAt(payableRecipient), 10);
+ BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10);
+ BOOST_CHECK(callContractFunction("b(address,uint256)", nonPayableRecipient, 10) == encodeArgs());
+ BOOST_CHECK(callContractFunction("b(address,uint256)", oogRecipient, 10) == encodeArgs());
+}
+
BOOST_AUTO_TEST_CASE(log0)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 1a4f3cdc..3b137572 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -2950,6 +2950,19 @@ BOOST_AUTO_TEST_CASE(multi_variable_declaration_wildcards_fail_6)
CHECK_ERROR(text, TypeError, "");
}
+BOOST_AUTO_TEST_CASE(tuple_assignment_from_void_function)
+{
+ char const* text = R"(
+ contract C {
+ function f() { }
+ function g() {
+ var (x,) = (f(), f());
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Cannot declare variable with void (empty tuple) type.");
+}
+
BOOST_AUTO_TEST_CASE(member_access_parser_ambiguity)
{
char const* text = R"(
@@ -4736,6 +4749,23 @@ BOOST_AUTO_TEST_CASE(delete_external_function_type_invalid)
CHECK_ERROR(text, TypeError, "");
}
+BOOST_AUTO_TEST_CASE(external_function_to_function_type_calldata_parameter)
+{
+ // This is a test that checks that the type of the `bytes` parameter is
+ // correctly changed from its own type `bytes calldata` to `bytes memory`
+ // when converting to a function type.
+ char const* text = R"(
+ contract C {
+ function f(function(bytes memory x) external g) { }
+ function callback(bytes x) external {}
+ function g() {
+ f(this.callback);
+ }
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
BOOST_AUTO_TEST_CASE(external_function_type_to_address)
{
char const* text = R"(
@@ -4852,6 +4882,19 @@ BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_negative_stack)
CHECK_WARNING(text, "Inline assembly block is not balanced");
}
+BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_two_stack_load)
+{
+ char const* text = R"(
+ contract c {
+ uint8 x;
+ function f() {
+ assembly { x pop }
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Inline assembly block is not balanced");
+}
+
BOOST_AUTO_TEST_CASE(inline_assembly_in_modifier)
{
char const* text = R"(
@@ -5079,6 +5122,40 @@ BOOST_AUTO_TEST_CASE(invalid_address_length)
CHECK_WARNING(text, "checksum");
}
+BOOST_AUTO_TEST_CASE(early_exit_on_fatal_errors)
+{
+ // This tests a crash that occured because we did not stop for fatal errors.
+ char const* text = R"(
+ contract C {
+ struct S {
+ ftring a;
+ }
+ S public s;
+ function s() s {
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Identifier not found or not unique");
+}
+
+BOOST_AUTO_TEST_CASE(address_methods)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ address addr;
+ uint balance = addr.balance;
+ bool callRet = addr.call();
+ bool callcodeRet = addr.callcode();
+ bool delegatecallRet = addr.delegatecall();
+ bool sendRet = addr.send(1);
+ addr.transfer(1);
+ }
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
BOOST_AUTO_TEST_SUITE_END()
}