aboutsummaryrefslogtreecommitdiffstats
path: root/test/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'test/libsolidity')
-rw-r--r--test/libsolidity/InlineAssembly.cpp124
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp36
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp77
3 files changed, 207 insertions, 30 deletions
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()
}