aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt4
-rw-r--r--test/Metadata.cpp80
-rw-r--r--test/Metadata.h37
-rw-r--r--test/RPCSession.cpp4
-rwxr-xr-xtest/cmdlineTests.sh7
-rw-r--r--test/contracts/FixedFeeRegistrar.cpp4
-rw-r--r--test/contracts/Wallet.cpp16
-rw-r--r--test/fuzzer.cpp1
-rw-r--r--test/libdevcore/MiniMoustache.cpp127
-rw-r--r--test/libdevcore/UTF8.cpp216
-rw-r--r--test/libjulia/Parser.cpp231
-rw-r--r--test/liblll/EndToEndTest.cpp426
-rw-r--r--test/liblll/Parser.cpp8
-rw-r--r--test/libsolidity/ASTJSON.cpp56
-rw-r--r--test/libsolidity/Assembly.cpp18
-rw-r--r--test/libsolidity/ErrorCheck.cpp11
-rw-r--r--test/libsolidity/GasMeter.cpp6
-rw-r--r--test/libsolidity/InlineAssembly.cpp328
-rw-r--r--test/libsolidity/JSONCompiler.cpp111
-rw-r--r--test/libsolidity/Metadata.cpp63
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp22
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp434
-rw-r--r--test/libsolidity/SolidityExpressionCompiler.cpp10
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp486
-rw-r--r--test/libsolidity/SolidityNatspecJSON.cpp4
-rw-r--r--test/libsolidity/SolidityOptimizer.cpp159
-rw-r--r--test/libsolidity/SolidityParser.cpp34
-rw-r--r--test/libsolidity/StandardCompiler.cpp86
28 files changed, 2660 insertions, 329 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 01a9a188..8e7b8916 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -4,8 +4,10 @@ aux_source_directory(. SRC_LIST)
aux_source_directory(libdevcore SRC_LIST)
aux_source_directory(libevmasm SRC_LIST)
aux_source_directory(libsolidity SRC_LIST)
+aux_source_directory(libjulia SRC_LIST)
aux_source_directory(contracts SRC_LIST)
aux_source_directory(liblll SRC_LIST)
+aux_source_directory(libjulia SRC_LIST)
list(REMOVE_ITEM SRC_LIST "./fuzzer.cpp")
@@ -18,7 +20,7 @@ eth_simple_add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
eth_use(${EXECUTABLE} REQUIRED Solidity::solidity Solidity::lll)
include_directories(BEFORE ..)
-target_link_libraries(${EXECUTABLE} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
+target_link_libraries(${EXECUTABLE} soljson ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
add_executable(solfuzzer fuzzer.cpp)
target_link_libraries(solfuzzer soljson ${Boost_PROGRAM_OPTIONS_LIBRARIES})
diff --git a/test/Metadata.cpp b/test/Metadata.cpp
new file mode 100644
index 00000000..03f905b1
--- /dev/null
+++ b/test/Metadata.cpp
@@ -0,0 +1,80 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Metadata processing helpers.
+ */
+
+#include <string>
+#include <iostream>
+#include <regex>
+#include <libdevcore/JSON.h>
+
+using namespace std;
+
+namespace dev
+{
+namespace test
+{
+
+string bytecodeSansMetadata(string const& _bytecode)
+{
+ /// The metadata hash takes up 43 bytes (or 86 characters in hex)
+ /// /a165627a7a72305820([0-9a-f]{64})0029$/
+
+ if (_bytecode.size() < 88)
+ return _bytecode;
+
+ if (_bytecode.substr(_bytecode.size() - 4, 4) != "0029")
+ return _bytecode;
+
+ if (_bytecode.substr(_bytecode.size() - 86, 18) != "a165627a7a72305820")
+ return _bytecode;
+
+ return _bytecode.substr(0, _bytecode.size() - 86);
+}
+
+bool isValidMetadata(string const& _metadata)
+{
+ Json::Value metadata;
+ if (!Json::Reader().parse(_metadata, metadata, false))
+ return false;
+
+ if (
+ !metadata.isObject() ||
+ !metadata.isMember("version") ||
+ !metadata.isMember("language") ||
+ !metadata.isMember("compiler") ||
+ !metadata.isMember("settings") ||
+ !metadata.isMember("sources") ||
+ !metadata.isMember("output")
+ )
+ return false;
+
+ if (!metadata["version"].isNumeric() || metadata["version"] != 1)
+ return false;
+
+ if (!metadata["language"].isString() || metadata["language"].asString() != "Solidity")
+ return false;
+
+ /// @TODO add more strict checks
+
+ return true;
+}
+
+}
+} // end namespaces
diff --git a/test/Metadata.h b/test/Metadata.h
new file mode 100644
index 00000000..cd92ecd8
--- /dev/null
+++ b/test/Metadata.h
@@ -0,0 +1,37 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Metadata processing helpers.
+ */
+
+#include <string>
+
+namespace dev
+{
+namespace test
+{
+
+/// Returns the bytecode with the metadata hash stripped out.
+std::string bytecodeSansMetadata(std::string const& _bytecode);
+
+/// Expects a serialised metadata JSON and returns true if the
+/// content is valid metadata.
+bool isValidMetadata(std::string const& _metadata);
+
+}
+} // end namespaces
diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp
index 3ea3b1fe..c4fbfefb 100644
--- a/test/RPCSession.cpp
+++ b/test/RPCSession.cpp
@@ -316,9 +316,9 @@ Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const&
request += "],\"id\":" + to_string(m_rpcSequence) + "}";
++m_rpcSequence;
- // cout << "Request: " << request << endl;
+ BOOST_TEST_MESSAGE("Request: " + request);
string reply = m_ipcSocket.sendRequest(request);
- // cout << "Reply: " << reply << endl;
+ BOOST_TEST_MESSAGE("Reply: " + reply);
Json::Value result;
BOOST_REQUIRE(Json::Reader().parse(reply, result, false));
diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh
index 6dc3f77f..4074ce55 100755
--- a/test/cmdlineTests.sh
+++ b/test/cmdlineTests.sh
@@ -79,7 +79,14 @@ TMPDIR=$(mktemp -d)
"$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/test/
for f in *.sol
do
+ set +e
"$REPO_ROOT"/build/test/solfuzzer --quiet < "$f"
+ if [ $? -ne 0 ]; then
+ echo "Fuzzer failed on:"
+ cat "$f"
+ exit 1
+ fi
+ set -e
done
)
rm -rf "$TMPDIR"
diff --git a/test/contracts/FixedFeeRegistrar.cpp b/test/contracts/FixedFeeRegistrar.cpp
index 39c32eb7..d2904b5f 100644
--- a/test/contracts/FixedFeeRegistrar.cpp
+++ b/test/contracts/FixedFeeRegistrar.cpp
@@ -82,7 +82,7 @@ contract FixedFeeRegistrar is Registrar {
}
}
function disown(string _name, address _refund) onlyrecordowner(_name) {
- delete m_recordData[uint(sha3(_name)) / 8];
+ delete m_recordData[uint(keccak256(_name)) / 8];
if (!_refund.send(c_fee))
throw;
Changed(_name);
@@ -118,7 +118,7 @@ contract FixedFeeRegistrar is Registrar {
Record[2**253] m_recordData;
function m_record(string _name) constant internal returns (Record storage o_record) {
- return m_recordData[uint(sha3(_name)) / 8];
+ return m_recordData[uint(keccak256(_name)) / 8];
}
uint constant c_fee = 69 ether;
}
diff --git a/test/contracts/Wallet.cpp b/test/contracts/Wallet.cpp
index 80f06613..ef345d86 100644
--- a/test/contracts/Wallet.cpp
+++ b/test/contracts/Wallet.cpp
@@ -128,7 +128,7 @@ contract multiowned {
}
// Replaces an owner `_from` with another `_to`.
- function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external {
+ function changeOwner(address _from, address _to) onlymanyowners(keccak256(msg.data)) external {
if (isOwner(_to)) return;
uint ownerIndex = m_ownerIndex[uint(_from)];
if (ownerIndex == 0) return;
@@ -140,7 +140,7 @@ contract multiowned {
OwnerChanged(_from, _to);
}
- function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external {
+ function addOwner(address _owner) onlymanyowners(keccak256(msg.data)) external {
if (isOwner(_owner)) return;
clearPending();
@@ -154,7 +154,7 @@ contract multiowned {
OwnerAdded(_owner);
}
- function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external {
+ function removeOwner(address _owner) onlymanyowners(keccak256(msg.data)) external {
uint ownerIndex = m_ownerIndex[uint(_owner)];
if (ownerIndex == 0) return;
if (m_required > m_numOwners - 1) return;
@@ -166,7 +166,7 @@ contract multiowned {
OwnerRemoved(_owner);
}
- function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external {
+ function changeRequirement(uint _newRequired) onlymanyowners(keccak256(msg.data)) external {
if (_newRequired > m_numOwners) return;
m_required = _newRequired;
clearPending();
@@ -293,11 +293,11 @@ contract daylimit is multiowned {
m_lastDay = today();
}
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today.
- function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external {
+ function setDailyLimit(uint _newLimit) onlymanyowners(keccak256(msg.data)) external {
m_dailyLimit = _newLimit;
}
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today.
- function resetSpentToday() onlymanyowners(sha3(msg.data)) external {
+ function resetSpentToday() onlymanyowners(keccak256(msg.data)) external {
m_spentToday = 0;
}
@@ -374,7 +374,7 @@ contract Wallet is multisig, multiowned, daylimit {
}
// destroys the contract sending everything to `_to`.
- function kill(address _to) onlymanyowners(sha3(msg.data)) external {
+ function kill(address _to) onlymanyowners(keccak256(msg.data)) external {
selfdestruct(_to);
}
@@ -398,7 +398,7 @@ contract Wallet is multisig, multiowned, daylimit {
return 0;
}
// determine our operation hash.
- _r = sha3(msg.data, block.number);
+ _r = keccak256(msg.data, block.number);
if (!confirm(_r) && m_txs[_r].to == 0) {
m_txs[_r].to = _to;
m_txs[_r].value = _value;
diff --git a/test/fuzzer.cpp b/test/fuzzer.cpp
index 053d880f..cf99755f 100644
--- a/test/fuzzer.cpp
+++ b/test/fuzzer.cpp
@@ -152,7 +152,6 @@ void testCompiler()
"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"
});
diff --git a/test/libdevcore/MiniMoustache.cpp b/test/libdevcore/MiniMoustache.cpp
new file mode 100644
index 00000000..84149173
--- /dev/null
+++ b/test/libdevcore/MiniMoustache.cpp
@@ -0,0 +1,127 @@
+/*
+ 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/>.
+*/
+/**
+ * Unit tests for the mini moustache class.
+ */
+
+#include <libdevcore/Whiskers.h>
+
+#include "../TestHelper.h"
+
+using namespace std;
+
+namespace dev
+{
+namespace test
+{
+
+BOOST_AUTO_TEST_SUITE(WhiskersTest)
+
+BOOST_AUTO_TEST_CASE(no_templates)
+{
+ string templ = "this text does not contain templates";
+ BOOST_CHECK_EQUAL(Whiskers(templ).render(), templ);
+}
+
+BOOST_AUTO_TEST_CASE(basic_replacement)
+{
+ string templ = "a <b> x <c> -> <d>.";
+ string result = Whiskers(templ)
+ ("b", "BE")
+ ("c", "CE")
+ ("d", "DE")
+ .render();
+ BOOST_CHECK_EQUAL(result, "a BE x CE -> DE.");
+}
+
+BOOST_AUTO_TEST_CASE(tag_unavailable)
+{
+ string templ = "<b>";
+ Whiskers m(templ);
+ BOOST_CHECK_THROW(m.render(), WhiskersError);
+}
+
+BOOST_AUTO_TEST_CASE(complicated_replacement)
+{
+ string templ = "a <b> x <complicated> \n <nes<ted>>.";
+ string result = Whiskers(templ)
+ ("b", "BE")
+ ("complicated", "CO<M>PL")
+ ("nes<ted", "NEST")
+ .render();
+ BOOST_CHECK_EQUAL(result, "a BE x CO<M>PL \n NEST>.");
+}
+
+BOOST_AUTO_TEST_CASE(non_existing_list)
+{
+ string templ = "a <#b></b>";
+ Whiskers m(templ);
+ BOOST_CHECK_THROW(m.render(), WhiskersError);
+}
+
+BOOST_AUTO_TEST_CASE(empty_list)
+{
+ string templ = "a <#b></b>x";
+ string result = Whiskers(templ)("b", vector<Whiskers::StringMap>{}).render();
+ BOOST_CHECK_EQUAL(result, "a x");
+}
+
+BOOST_AUTO_TEST_CASE(list)
+{
+ string templ = "a<#b>( <g> - <h> )</b>x";
+ vector<map<string, string>> list(2);
+ list[0]["g"] = "GE";
+ list[0]["h"] = "H";
+ list[1]["g"] = "2GE";
+ list[1]["h"] = "2H";
+ string result = Whiskers(templ)("b", list).render();
+ BOOST_CHECK_EQUAL(result, "a( GE - H )( 2GE - 2H )x");
+}
+
+BOOST_AUTO_TEST_CASE(recursive_list)
+{
+ // Check that templates resulting from lists are not expanded again
+ string templ = "a<#b> 1<g>3 </b><x>";
+ vector<map<string, string>> list(1);
+ list[0]["g"] = "<x>";
+ string result = Whiskers(templ)("x", "X")("b", list).render();
+ BOOST_CHECK_EQUAL(result, "a 1<x>3 X");
+}
+
+BOOST_AUTO_TEST_CASE(list_can_access_upper)
+{
+ string templ = "<#b>(<a>)</b>";
+ vector<map<string, string>> list(2);
+ Whiskers m(templ);
+ string result = m("a", "A")("b", list).render();
+ BOOST_CHECK_EQUAL(result, "(A)(A)");
+}
+
+BOOST_AUTO_TEST_CASE(parameter_collision)
+{
+ string templ = "a <#b></b>";
+ vector<map<string, string>> list(1);
+ list[0]["a"] = "x";
+ Whiskers m(templ);
+ m("a", "X")("b", list);
+ BOOST_CHECK_THROW(m.render(), WhiskersError);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
diff --git a/test/libdevcore/UTF8.cpp b/test/libdevcore/UTF8.cpp
new file mode 100644
index 00000000..719ada72
--- /dev/null
+++ b/test/libdevcore/UTF8.cpp
@@ -0,0 +1,216 @@
+/*
+ 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/>.
+*/
+/**
+ * Unit tests for UTF-8 validation.
+ */
+
+#include <libdevcore/CommonData.h>
+#include <libdevcore/UTF8.h>
+
+#include "../TestHelper.h"
+
+using namespace std;
+
+namespace dev
+{
+namespace test
+{
+
+BOOST_AUTO_TEST_SUITE(UTF8)
+
+namespace {
+
+bool isValidUTF8(string const& _value)
+{
+ size_t pos;
+ return validateUTF8(asString(fromHex(_value)), pos);
+}
+
+bool isInvalidUTF8(string const& _value, size_t _expectedPos)
+{
+ size_t pos;
+ if (validateUTF8(asString(fromHex(_value)), pos))
+ return false;
+ if (pos != _expectedPos)
+ return false;
+ return true;
+}
+
+}
+
+BOOST_AUTO_TEST_CASE(valid)
+{
+ BOOST_CHECK(isValidUTF8("00"));
+ BOOST_CHECK(isValidUTF8("20"));
+ BOOST_CHECK(isValidUTF8("7f"));
+ BOOST_CHECK(isValidUTF8("c281"));
+ BOOST_CHECK(isValidUTF8("df81"));
+ BOOST_CHECK(isValidUTF8("e0a081"));
+ BOOST_CHECK(isValidUTF8("e18081"));
+ BOOST_CHECK(isValidUTF8("ec8081"));
+ BOOST_CHECK(isValidUTF8("ed8081"));
+ BOOST_CHECK(isValidUTF8("ee8081"));
+ BOOST_CHECK(isValidUTF8("ef8081"));
+ BOOST_CHECK(isValidUTF8("f0908081"));
+ BOOST_CHECK(isValidUTF8("f3808081"));
+ BOOST_CHECK(isValidUTF8("f2808081"));
+ BOOST_CHECK(isValidUTF8("f3808081"));
+ BOOST_CHECK(isValidUTF8("f48e8081"));
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+ // anything between 0x80 and 0xc0 is disallowed
+ BOOST_CHECK(isInvalidUTF8("80", 0)); // invalid per table 3.6
+ BOOST_CHECK(isInvalidUTF8("a0", 0)); // invalid per table 3.6
+ BOOST_CHECK(isInvalidUTF8("c0", 0)); // invalid per table 3.7
+ BOOST_CHECK(isInvalidUTF8("c1", 0)); // invalid per table 3.7
+ BOOST_CHECK(isInvalidUTF8("c2", 0)); // too short (position is reported as the first byte)
+ BOOST_CHECK(isInvalidUTF8("e08081", 2)); // e0 must be followed by >= a0
+ BOOST_CHECK(isInvalidUTF8("e180", 0)); // too short
+ BOOST_CHECK(isInvalidUTF8("ec80", 0)); // too short
+ BOOST_CHECK(isInvalidUTF8("f08f8001", 2)); // f0 must be followed by >= 90
+ BOOST_CHECK(isInvalidUTF8("f18080", 0)); // too short
+ BOOST_CHECK(isInvalidUTF8("f4908081", 2)); // f4 must be followed by < 90
+ // anything above 0xf7 is disallowed
+ BOOST_CHECK(isInvalidUTF8("f8", 0)); // invalid per table 3.7
+ BOOST_CHECK(isInvalidUTF8("f9", 0)); // invalid per table 3.7
+}
+
+BOOST_AUTO_TEST_CASE(corpus)
+{
+ string source = R"(
+κόσμε
+
+hélló
+
+Ā ā Ă ă Ą ą
+
+ƀ Ɓ Ƃ ƃ Ƅ ƅ
+
+ɐ ɑ ɒ ɓ ɔ ɕ
+
+ʰ ʱ ʲ ʳ ʴ ʵ
+
+̀ ́ ̂ ̃ ̄ ̅
+
+ϩ Ϫ ϫ Ϭ ϭ Ϯ
+
+Ё Ђ Ѓ Є Ѕ І
+
+Ա Բ Գ Դ Ե Զ
+
+ ק ר ש ת װ ױ
+
+ځ ڂ ڃ ڄ څ چ
+
+ऑ ऒ ओ औ क ख
+
+ও ঔ ক খ গ ঘ
+
+ਘ ਙ ਚ ਛ ਜ ਝ
+
+ઓ ઔ ક ખ ગ ઘ
+
+ଗ ଘ ଙ ଚ ଛ ଜ
+
+ஔ க ங ச ஜ ஞ
+
+ఎ ఏ ఐ ఒ ఓ ఔ
+
+ಓ ಔ ಕ ಖ ಗ ಘ
+
+ഐ ഒ ഓ ഔ ക
+
+ฒ ณ ด ต ถ ท
+
+ມ ຢ ຣ ລ ວ ສ
+
+༄ ༅ ༆ ༇ ༈ ༉
+
+Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ
+
+ᄌ ᄍ ᄎ ᄏ ᄐ
+
+Ḕ ḕ Ḗ ḗ Ḙ ḙ Ḛ
+
+ἐ ἑ ἒ ἓ ἔ ἕ
+
+₠ ₡ ₢ ₣ ₤ ₥
+
+⃐ ⃑ ⃒ ⃓ ⃔ ⃕ ⃖ ⃗ ⃘ ⃙ ⃚
+
+ℋ ℌ ℍ ℎ ℏ ℐ ℑ
+
+⅓ ⅔ ⅕ ⅖ ⅗
+
+∬ ∭ ∮ ∯ ∰
+
+⌖ ⌗ ⌘ ⌙ ⌚ ⌛
+
+␀ ␁ ␂ ␃ ␄ ␅
+
+⑀ ⑁ ⑂ ⑃ ⑄
+
+① ② ③ ④ ⑤
+
+╘ ╙ ╚ ╛ ╜ ╝
+
+▁ ▂ ▃ ▄ ▅ ▆
+
+▤ ▥ ▦ ▧ ▨
+
+♔ ♕ ♖ ♗ ♘ ♙
+
+✈ ✉ ✌ ✍ ✎
+
+ぁ あ ぃ い ぅ
+
+ァ ア ィ イ ゥ
+
+ㄅ ㄆ ㄇ ㄈ ㄉ
+
+ㄱ ㄲ ㄳ ㄴ ㄵ
+
+㆚ ㆛ ㆜ ㆝ ㆞
+
+㈀ ㈁ ㈂ ㈃ ㈄
+
+㌀ ㌁ ㌂ ㌃ ㌄
+
+乺 乻 乼 乽 乾
+
+걺 걻 걼 걽 걾
+
+豈 更 車 賈 滑
+
+שּׁ שּׂ אַ אָ אּ
+
+ﮄ ﮅ ﮆ ﮇ ﮈ ﮉ
+
+ ﺵ ﺶ ﺷ ﺸ
+
+「 」 、 ・ ヲ ァ ィ ゥ
+ )";
+ size_t pos;
+ BOOST_CHECK(validateUTF8(source, pos));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
diff --git a/test/libjulia/Parser.cpp b/test/libjulia/Parser.cpp
new file mode 100644
index 00000000..fa7c45ed
--- /dev/null
+++ b/test/libjulia/Parser.cpp
@@ -0,0 +1,231 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for parsing Julia.
+ */
+
+#include "../TestHelper.h"
+
+#include <test/libsolidity/ErrorCheck.h>
+
+#include <libsolidity/inlineasm/AsmParser.h>
+#include <libsolidity/inlineasm/AsmAnalysis.h>
+#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
+#include <libsolidity/parsing/Scanner.h>
+#include <libsolidity/interface/ErrorReporter.h>
+
+#include <boost/optional.hpp>
+#include <boost/algorithm/string/replace.hpp>
+
+#include <string>
+#include <memory>
+
+using namespace std;
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+namespace
+{
+
+bool parse(string const& _source, ErrorReporter& errorReporter)
+{
+ try
+ {
+ auto scanner = make_shared<Scanner>(CharStream(_source));
+ auto parserResult = assembly::Parser(errorReporter, true).parse(scanner);
+ if (parserResult)
+ {
+ assembly::AsmAnalysisInfo analysisInfo;
+ return (assembly::AsmAnalyzer(analysisInfo, errorReporter, true)).analyze(*parserResult);
+ }
+ }
+ catch (FatalError const&)
+ {
+ BOOST_FAIL("Fatal error leaked.");
+ }
+ return false;
+}
+
+boost::optional<Error> parseAndReturnFirstError(string const& _source, bool _allowWarnings = true)
+{
+ ErrorList errors;
+ ErrorReporter errorReporter(errors);
+ if (!parse(_source, errorReporter))
+ {
+ BOOST_REQUIRE_EQUAL(errors.size(), 1);
+ return *errors.front();
+ }
+ else
+ {
+ // If success is true, there might still be an error in the assembly stage.
+ if (_allowWarnings && Error::containsOnlyWarnings(errors))
+ return {};
+ else if (!errors.empty())
+ {
+ if (!_allowWarnings)
+ BOOST_CHECK_EQUAL(errors.size(), 1);
+ return *errors.front();
+ }
+ }
+ return {};
+}
+
+bool successParse(std::string const& _source, bool _allowWarnings = true)
+{
+ return !parseAndReturnFirstError(_source, _allowWarnings);
+}
+
+Error expectError(std::string const& _source, bool _allowWarnings = false)
+{
+
+ auto error = parseAndReturnFirstError(_source, _allowWarnings);
+ BOOST_REQUIRE(error);
+ return *error;
+}
+
+}
+
+#define CHECK_ERROR(text, typ, substring) \
+do \
+{ \
+ Error err = expectError((text), false); \
+ BOOST_CHECK(err.type() == (Error::Type::typ)); \
+ BOOST_CHECK(searchErrorMessage(err, (substring))); \
+} while(0)
+
+BOOST_AUTO_TEST_SUITE(JuliaParser)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ BOOST_CHECK(successParse("{ }"));
+}
+
+BOOST_AUTO_TEST_CASE(vardecl)
+{
+ BOOST_CHECK(successParse("{ let x:u256 := 7:u256 }"));
+}
+
+BOOST_AUTO_TEST_CASE(vardecl_bool)
+{
+ BOOST_CHECK(successParse("{ let x:bool := true:bool }"));
+ BOOST_CHECK(successParse("{ let x:bool := false:bool }"));
+}
+
+BOOST_AUTO_TEST_CASE(assignment)
+{
+ BOOST_CHECK(successParse("{ let x:u256 := 2:u256 let y:u256 := x }"));
+}
+
+BOOST_AUTO_TEST_CASE(vardecl_complex)
+{
+ BOOST_CHECK(successParse("{ function add(a:u256, b:u256) -> c:u256 {} let y:u256 := 2:u256 let x:u256 := add(7:u256, add(6:u256, y)) }"));
+}
+
+BOOST_AUTO_TEST_CASE(blocks)
+{
+ BOOST_CHECK(successParse("{ let x:u256 := 7:u256 { let y:u256 := 3:u256 } { let z:u256 := 2:u256 } }"));
+}
+
+BOOST_AUTO_TEST_CASE(function_definitions)
+{
+ BOOST_CHECK(successParse("{ function f() { } function g(a:u256) -> x:u256 { } }"));
+}
+
+BOOST_AUTO_TEST_CASE(function_definitions_multiple_args)
+{
+ BOOST_CHECK(successParse("{ function f(a:u256, d:u256) { } function g(a:u256, d:u256) -> x:u256, y:u256 { } }"));
+}
+
+BOOST_AUTO_TEST_CASE(function_calls)
+{
+ BOOST_CHECK(successParse("{ function f(a:u256) -> b:u256 {} function g(a:u256, b:u256, c:u256) {} function x() { g(1:u256, 2:u256, f(3:u256)) x() } }"));
+}
+
+BOOST_AUTO_TEST_CASE(tuple_assignment)
+{
+ BOOST_CHECK(successParse("{ function f() -> a:u256, b:u256, c:u256 {} let x:u256, y:u256, z:u256 := f() }"));
+}
+
+BOOST_AUTO_TEST_CASE(label)
+{
+ CHECK_ERROR("{ label: }", ParserError, "Labels are not supported.");
+}
+
+BOOST_AUTO_TEST_CASE(instructions)
+{
+ CHECK_ERROR("{ pop }", ParserError, "Call or assignment expected.");
+}
+
+BOOST_AUTO_TEST_CASE(push)
+{
+ CHECK_ERROR("{ 0x42:u256 }", ParserError, "Call or assignment expected.");
+}
+
+BOOST_AUTO_TEST_CASE(assign_from_stack)
+{
+ CHECK_ERROR("{ =: x:u256 }", ParserError, "Literal or identifier expected.");
+}
+
+BOOST_AUTO_TEST_CASE(empty_call)
+{
+ CHECK_ERROR("{ () }", ParserError, "Literal or identifier expected.");
+}
+
+BOOST_AUTO_TEST_CASE(lacking_types)
+{
+ CHECK_ERROR("{ let x := 1:u256 }", ParserError, "Expected token Identifier got 'Assign'");
+ CHECK_ERROR("{ let x:u256 := 1 }", ParserError, "Expected token Colon got 'RBrace'");
+ CHECK_ERROR("{ function f(a) {} }", ParserError, "Expected token Colon got 'RParen'");
+ CHECK_ERROR("{ function f(a:u256) -> b {} }", ParserError, "Expected token Colon got 'LBrace'");
+}
+
+BOOST_AUTO_TEST_CASE(invalid_types)
+{
+ /// testing invalid literal
+ /// NOTE: these will need to change when types are compared
+ CHECK_ERROR("{ let x:bool := 1:invalid }", TypeError, "\"invalid\" is not a valid type (user defined types are not yet supported).");
+ /// testing invalid variable declaration
+ CHECK_ERROR("{ let x:invalid := 1:bool }", TypeError, "\"invalid\" is not a valid type (user defined types are not yet supported).");
+ CHECK_ERROR("{ function f(a:invalid) {} }", TypeError, "\"invalid\" is not a valid type (user defined types are not yet supported).");
+}
+
+BOOST_AUTO_TEST_CASE(builtin_types)
+{
+ BOOST_CHECK(successParse("{ let x:bool := true:bool }"));
+ BOOST_CHECK(successParse("{ let x:u8 := 1:u8 }"));
+ BOOST_CHECK(successParse("{ let x:s8 := 1:u8 }"));
+ BOOST_CHECK(successParse("{ let x:u32 := 1:u32 }"));
+ BOOST_CHECK(successParse("{ let x:s32 := 1:s32 }"));
+ BOOST_CHECK(successParse("{ let x:u64 := 1:u64 }"));
+ BOOST_CHECK(successParse("{ let x:s64 := 1:s64 }"));
+ BOOST_CHECK(successParse("{ let x:u128 := 1:u128 }"));
+ BOOST_CHECK(successParse("{ let x:s128 := 1:s128 }"));
+ BOOST_CHECK(successParse("{ let x:u256 := 1:u256 }"));
+ BOOST_CHECK(successParse("{ let x:s256 := 1:s256 }"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+} // end namespaces
diff --git a/test/liblll/EndToEndTest.cpp b/test/liblll/EndToEndTest.cpp
index c7c1fd3b..f3bfb438 100644
--- a/test/liblll/EndToEndTest.cpp
+++ b/test/liblll/EndToEndTest.cpp
@@ -57,6 +57,114 @@ BOOST_AUTO_TEST_CASE(panic)
BOOST_REQUIRE(m_output.empty());
}
+BOOST_AUTO_TEST_CASE(macro_zeroarg)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (def 'zeroarg () (seq (mstore 0 0x1234) (return 0 32)))
+ (zeroarg)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(0x1234)));
+}
+
+BOOST_AUTO_TEST_CASE(macros)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (def 'x 1)
+ (def 'y () { (def 'x (+ x 2)) })
+ (y)
+ (return x)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(3)));
+}
+
+BOOST_AUTO_TEST_CASE(variables)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (set 'x 1)
+ (set 'y 2)
+ ;; this should equal to 3
+ (set 'z (add (get 'x) (get 'y)))
+ ;; overwriting it here
+ (set 'y 4)
+ ;; each variable has a 32 byte slot, starting from memory location 0x80
+ ;; variable addresses can also be retrieved by x or (ref 'x)
+ (set 'k (add (add (ref 'x) (ref 'y)) z))
+ (return (add (add (get 'x) (add (get 'y) (get 'z))) (get 'k)))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(488)));
+}
+
+BOOST_AUTO_TEST_CASE(when)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (when (= (calldatasize) 0) (return 1))
+ (when (!= (calldatasize) 0) (return 2))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2)));
+ BOOST_CHECK(callFallback() == toBigEndian(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(unless)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (unless (!= (calldatasize) 0) (return 1))
+ (unless (= (calldatasize) 0) (return 2))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2)));
+ BOOST_CHECK(callFallback() == toBigEndian(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_literal)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (return (if (= (calldatasize) 0) 1 2))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2)));
+ BOOST_CHECK(callFallback() == toBigEndian(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (if (= (calldatasize) 0) (return 1) (return 2))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2)));
+ BOOST_CHECK(callFallback() == toBigEndian(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_seq)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (return (if (= (calldatasize) 0) { 0 2 1 } { 0 1 2 }))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2)));
+ BOOST_CHECK(callFallback() == toBigEndian(u256(1)));
+}
+
BOOST_AUTO_TEST_CASE(exp_operator_const)
{
char const* sourceCode = R"(
@@ -272,13 +380,329 @@ BOOST_AUTO_TEST_CASE(assembly_codecopy)
(seq
(lit 0x00 "abcdef")
(asm
- 0x06 0x16 0x20 codecopy
+ 0x06 6 codesize sub 0x20 codecopy
0x20 0x20 return)))
)";
compileAndRun(sourceCode);
BOOST_CHECK(callFallback() == encodeArgs(string("abcdef")));
}
+
+BOOST_AUTO_TEST_CASE(keccak256_32bytes)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (mstore 0x00 0x01)
+ (return (keccak256 0x00 0x20))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6")));
+}
+
+// The following tests are for the built-in macros.
+// Note that panic, returnlll and return_one_arg are well covered above.
+
+BOOST_AUTO_TEST_CASE(allgas)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return (- (gas) allgas)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(16))); // == 21 - SUB - GAS
+}
+
+BOOST_AUTO_TEST_CASE(send_two_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (send 0xdead 42))
+ )";
+ compileAndRun(sourceCode);
+ callFallbackWithValue(42);
+ BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
+}
+
+BOOST_AUTO_TEST_CASE(send_three_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (send allgas 0xdead 42))
+ )";
+ compileAndRun(sourceCode);
+ callFallbackWithValue(42);
+ BOOST_CHECK(balanceAt(Address(0xdead)) == 42);
+}
+
+BOOST_AUTO_TEST_CASE(msg_six_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (when (= 0 (calldatasize))
+ (seq
+ (mstore 0x40 1)
+ (def 'outsize 0x20)
+ (return (msg 1000 (address) 42 0x40 0x20 outsize) outsize)))
+ (when (= 1 (calldataload 0x00))
+ (return (callvalue)))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(msg_five_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (when (= 0 (calldatasize))
+ (seq
+ (mstore 0x20 1)
+ (mstore 0x40 2)
+ (return (msg 1000 (address) 42 0x20 0x40))))
+ (when (= 3 (+ (calldataload 0x00) (calldataload 0x20)))
+ (return (callvalue)))))
+
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(msg_four_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (when (= 0 (calldatasize))
+ (return (msg 1000 (address) 42 0xff)))
+ (return (callvalue))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(msg_three_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (when (= 0 (calldatasize))
+ (return (msg (address) 42 0xff)))
+ (return (callvalue))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(msg_two_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (when (= 0 (calldatasize))
+ (return (msg (address) 0xff)))
+ (return 42)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(create_one_arg)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (call allgas
+ (create (returnlll (return 42)))
+ 0 0 0 0x00 0x20)
+ (return 0x00 0x20)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(create_two_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (call allgas
+ (create 42 (returnlll (return (balance (address)))))
+ 0 0 0 0x00 0x20)
+ (return 0x00 0x20)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(sha3_two_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (mstore 0x00 0x01)
+ (return (sha3 0x00 0x20))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6")));
+}
+
+BOOST_AUTO_TEST_CASE(sha3_one_arg)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return (sha3 0x01)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6")));
+}
+
+BOOST_AUTO_TEST_CASE(sha3pair)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return (sha3pair 0x01 0x02)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("0xe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0")));
+}
+
+BOOST_AUTO_TEST_CASE(sha3trip)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return (sha3trip 0x01 0x02 0x03)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("0x6e0c627900b24bd432fe7b1f713f1b0744091a646a9fe4a65a18dfed21f2949c")));
+}
+
+BOOST_AUTO_TEST_CASE(makeperm) // Covers makeperm (implicit), permcount and perm
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (perm 'x) (x (+ 1 x))
+ (perm 'y) (y (+ 10 y))
+ (when (= 2 permcount)
+ (return (+ x y)))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(11)));
+}
+
+BOOST_AUTO_TEST_CASE(ecrecover)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return
+ (ecrecover
+ ; Hash of 'hello world'
+ 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad
+ ; v = 1 + 27
+ 0x1c
+ ; r
+ 0xdebaaa0cddb321b2dcaaf846d39605de7b97e77ba6106587855b9106cb104215
+ ; s
+ 0x61a22d94fa8b8a687ff9c911c844d1c016d1a685a9166858f9c7c1bc85128aca)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(fromHex("0x8743523d96a1b2cbe0c6909653a56da18ed484af")));
+}
+
+BOOST_AUTO_TEST_CASE(sha256_two_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF")
+ (lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!")
+ (sha256 0x20 0x40)
+ (return 0x00 0x20)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("0xcf25a9fe3d86ae228c226c81d2d8c64c687cd6dc4586d10d8e7e4e5b6706d429")));
+}
+
+BOOST_AUTO_TEST_CASE(ripemd160_two_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (lit 0x20 "abcdefghijklmnopqrstuvwxyzABCDEF")
+ (lit 0x40 "GHIJKLMNOPQRSTUVWXYZ0123456789?!")
+ (ripemd160 0x20 0x40)
+ (return 0x00 0x20)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("0x36c6b90a49e17d4c1e1b0e634ec74124d9b207da")));
+}
+
+BOOST_AUTO_TEST_CASE(sha256_one_arg)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (sha256 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546)
+ (return 0x00 0x20)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("0xcfd2f1fad75a1978da0a444883db7251414b139f31f5a04704c291fdb0e175e6")));
+}
+
+BOOST_AUTO_TEST_CASE(ripemd160_one_arg)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (ripemd160 0x6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546)
+ (return 0x00 0x20)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(
+ fromHex("0xac5ab22e07b0fb80c69b6207902f725e2507e546")));
+}
+
+BOOST_AUTO_TEST_CASE(wei_szabo_finney_ether)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return (+ wei (+ szabo (+ finney ether)))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(1001001000000000001)));
+}
+
+BOOST_AUTO_TEST_CASE(shift_left)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return (shl 1 8)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(256)));
+}
+
+BOOST_AUTO_TEST_CASE(shift_right)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return (shr 65536 8)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(256)));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/liblll/Parser.cpp b/test/liblll/Parser.cpp
index 0d5d9ea5..fc977b81 100644
--- a/test/liblll/Parser.cpp
+++ b/test/liblll/Parser.cpp
@@ -171,7 +171,13 @@ BOOST_AUTO_TEST_CASE(list)
BOOST_CHECK_EQUAL(parse(text), R"(( 1234 ))");
BOOST_CHECK(successParse("( 1234 5467 )"));
- BOOST_CHECK(!successParse("()"));
+ BOOST_CHECK(successParse("()"));
+}
+
+BOOST_AUTO_TEST_CASE(macro_with_zero_args)
+{
+ char const* text = "(def 'zeroargs () (asm INVALID))";
+ BOOST_CHECK(successParse(text));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp
index d23815b4..4fb4f20c 100644
--- a/test/libsolidity/ASTJSON.cpp
+++ b/test/libsolidity/ASTJSON.cpp
@@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit");
}
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(source_location)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit");
BOOST_CHECK_EQUAL(astJson["children"][0]["name"], "ContractDefinition");
BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["name"], "FunctionDefinition");
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(inheritance_specifier)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
BOOST_CHECK_EQUAL(astJson["children"][1]["attributes"]["name"], "C2");
BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["name"], "InheritanceSpecifier");
BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["src"], "30:2:1");
@@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(using_for_directive)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value usingFor = astJson["children"][1]["children"][0];
BOOST_CHECK_EQUAL(usingFor["name"], "UsingForDirective");
BOOST_CHECK_EQUAL(usingFor["src"], "26:17:1");
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(enum_value)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value enumDefinition = astJson["children"][0]["children"][0];
BOOST_CHECK_EQUAL(enumDefinition["children"][0]["name"], "EnumValue");
BOOST_CHECK_EQUAL(enumDefinition["children"][0]["attributes"]["name"], "A");
@@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(modifier_definition)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value modifier = astJson["children"][0]["children"][0];
BOOST_CHECK_EQUAL(modifier["name"], "ModifierDefinition");
BOOST_CHECK_EQUAL(modifier["attributes"]["name"], "M");
@@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value modifier = astJson["children"][0]["children"][1]["children"][2];
BOOST_CHECK_EQUAL(modifier["name"], "ModifierInvocation");
BOOST_CHECK_EQUAL(modifier["src"], "52:4:1");
@@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(event_definition)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value event = astJson["children"][0]["children"][0];
BOOST_CHECK_EQUAL(event["name"], "EventDefinition");
BOOST_CHECK_EQUAL(event["attributes"]["name"], "E");
@@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(array_type_name)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value array = astJson["children"][0]["children"][0]["children"][0];
BOOST_CHECK_EQUAL(array["name"], "ArrayTypeName");
BOOST_CHECK_EQUAL(array["src"], "13:6:1");
@@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(placeholder_statement)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value placeholder = astJson["children"][0]["children"][0]["children"][1]["children"][0];
BOOST_CHECK_EQUAL(placeholder["name"], "PlaceholderStatement");
BOOST_CHECK_EQUAL(placeholder["src"], "26:1:1");
@@ -188,11 +188,11 @@ BOOST_AUTO_TEST_CASE(non_utf8)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value literal = astJson["children"][0]["children"][0]["children"][2]["children"][0]["children"][1];
BOOST_CHECK_EQUAL(literal["name"], "Literal");
BOOST_CHECK_EQUAL(literal["attributes"]["hexvalue"], "ff");
- BOOST_CHECK_EQUAL(literal["attributes"]["token"], Json::nullValue);
+ BOOST_CHECK_EQUAL(literal["attributes"]["token"], "string");
BOOST_CHECK_EQUAL(literal["attributes"]["value"], Json::nullValue);
BOOST_CHECK(literal["attributes"]["type"].asString().find("invalid") != string::npos);
}
@@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(function_type)
c.parseAndAnalyze();
map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1;
- Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
+ Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
Json::Value fun = astJson["children"][0]["children"][0];
BOOST_CHECK_EQUAL(fun["name"], "FunctionDefinition");
Json::Value argument = fun["children"][0]["children"][0];
@@ -228,6 +228,36 @@ BOOST_AUTO_TEST_CASE(function_type)
BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external");
}
+BOOST_AUTO_TEST_CASE(documentation)
+{
+ CompilerStack c;
+ c.addSource("a", "/**This contract is empty*/ contract C {}");
+ c.addSource("b",
+ "/**This contract is empty"
+ " and has a line-breaking comment.*/"
+ "contract C {}"
+ );
+ c.parseAndAnalyze();
+ map<string, unsigned> sourceIndices;
+ sourceIndices["a"] = 0;
+ sourceIndices["b"] = 1;
+ Json::Value astJsonA = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a"));
+ Json::Value documentationA = astJsonA["children"][0]["attributes"]["documentation"];
+ BOOST_CHECK_EQUAL(documentationA, "This contract is empty");
+ Json::Value astJsonB = ASTJsonConverter(true, sourceIndices).toJson(c.ast("b"));
+ Json::Value documentationB = astJsonB["children"][0]["attributes"]["documentation"];
+ BOOST_CHECK_EQUAL(documentationB, "This contract is empty and has a line-breaking comment.");
+ //same tests for non-legacy mode
+ astJsonA = ASTJsonConverter(false, sourceIndices).toJson(c.ast("a"));
+ documentationA = astJsonA["nodes"][0]["documentation"];
+ BOOST_CHECK_EQUAL(documentationA, "This contract is empty");
+ astJsonB = ASTJsonConverter(false, sourceIndices).toJson(c.ast("b"));
+ documentationB = astJsonB["nodes"][0]["documentation"];
+ BOOST_CHECK_EQUAL(documentationB, "This contract is empty and has a line-breaking comment.");
+
+}
+
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index c4ec0d20..99a2996e 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -31,6 +31,7 @@
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/TypeChecker.h>
+#include <libsolidity/interface/ErrorReporter.h>
using namespace std;
using namespace dev::eth;
@@ -48,28 +49,29 @@ namespace
eth::AssemblyItems compileContract(const string& _sourceCode)
{
ErrorList errors;
- Parser parser(errors);
+ ErrorReporter errorReporter(errors);
+ Parser parser(errorReporter);
ASTPointer<SourceUnit> sourceUnit;
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
BOOST_CHECK(!!sourceUnit);
map<ASTNode const*, shared_ptr<DeclarationContainer>> scopes;
- NameAndTypeResolver resolver({}, scopes, errors);
- solAssert(Error::containsOnlyWarnings(errors), "");
+ NameAndTypeResolver resolver({}, scopes, errorReporter);
+ solAssert(Error::containsOnlyWarnings(errorReporter.errors()), "");
resolver.registerDeclarations(*sourceUnit);
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
- if (!Error::containsOnlyWarnings(errors))
+ if (!Error::containsOnlyWarnings(errorReporter.errors()))
return AssemblyItems();
}
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
- TypeChecker checker(errors);
+ TypeChecker checker(errorReporter);
BOOST_REQUIRE_NO_THROW(checker.checkTypeRequirements(*contract));
- if (!Error::containsOnlyWarnings(errors))
+ if (!Error::containsOnlyWarnings(errorReporter.errors()))
return AssemblyItems();
}
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
@@ -117,8 +119,8 @@ BOOST_AUTO_TEST_CASE(location_test)
shared_ptr<string const> n = make_shared<string>("");
AssemblyItems items = compileContract(sourceCode);
vector<SourceLocation> locations =
- vector<SourceLocation>(17, SourceLocation(2, 75, n)) +
- vector<SourceLocation>(30, SourceLocation(20, 72, n)) +
+ vector<SourceLocation>(19, SourceLocation(2, 75, n)) +
+ vector<SourceLocation>(32, SourceLocation(20, 72, n)) +
vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} +
vector<SourceLocation>(2, SourceLocation(58, 67, n)) +
vector<SourceLocation>(3, SourceLocation(20, 72, n));
diff --git a/test/libsolidity/ErrorCheck.cpp b/test/libsolidity/ErrorCheck.cpp
index 75555c9b..9b0f9fb7 100644
--- a/test/libsolidity/ErrorCheck.cpp
+++ b/test/libsolidity/ErrorCheck.cpp
@@ -29,6 +29,15 @@ using namespace std;
bool dev::solidity::searchErrorMessage(Error const& _err, std::string const& _substr)
{
if (string const* errorMessage = boost::get_error_info<dev::errinfo_comment>(_err))
- return errorMessage->find(_substr) != std::string::npos;
+ {
+ if (errorMessage->find(_substr) == std::string::npos)
+ {
+ cout << "Expected message \"" << _substr << "\" but found" << *errorMessage << endl;
+ return false;
+ }
+ return true;
+ }
+ else
+ cout << "Expected error message but found none." << endl;
return _substr.empty();
}
diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp
index f90cb105..ef560b12 100644
--- a/test/libsolidity/GasMeter.cpp
+++ b/test/libsolidity/GasMeter.cpp
@@ -151,20 +151,20 @@ BOOST_AUTO_TEST_CASE(simple_contract)
contract test {
bytes32 public shaValue;
function f(uint a) {
- shaValue = sha3(a);
+ shaValue = keccak256(a);
}
}
)";
testCreationTimeGas(sourceCode);
}
-BOOST_AUTO_TEST_CASE(store_sha3)
+BOOST_AUTO_TEST_CASE(store_keccak256)
{
char const* sourceCode = R"(
contract test {
bytes32 public shaValue;
function test(uint a) {
- shaValue = sha3(a);
+ shaValue = keccak256(a);
}
}
)";
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index 8bf4df8e..5197f649 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -22,7 +22,7 @@
#include "../TestHelper.h"
-#include <libsolidity/inlineasm/AsmStack.h>
+#include <libsolidity/interface/AssemblyStack.h>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/ast/AST.h>
@@ -47,49 +47,56 @@ namespace test
namespace
{
-boost::optional<Error> parseAndReturnFirstError(string const& _source, bool _assemble = false, bool _allowWarnings = true)
+boost::optional<Error> parseAndReturnFirstError(
+ string const& _source,
+ bool _assemble = false,
+ bool _allowWarnings = true,
+ AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM
+)
{
- assembly::InlineAssemblyStack stack;
+ AssemblyStack stack;
bool success = false;
try
{
- success = stack.parse(std::make_shared<Scanner>(CharStream(_source)));
+ success = stack.parseAndAnalyze("", _source);
if (success && _assemble)
- stack.assemble();
+ stack.assemble(_machine);
}
catch (FatalError const&)
{
BOOST_FAIL("Fatal error leaked.");
success = false;
}
- if (!success)
- {
- BOOST_REQUIRE_EQUAL(stack.errors().size(), 1);
- return *stack.errors().front();
- }
- else
+ shared_ptr<Error const> error;
+ for (auto const& e: stack.errors())
{
- // 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();
- }
+ if (_allowWarnings && e->type() == Error::Type::Warning)
+ continue;
+ if (error)
+ BOOST_FAIL("Found more than one error.");
+ error = e;
}
+ if (!success)
+ BOOST_REQUIRE(error);
+ if (error)
+ return *error;
return {};
}
-bool successParse(std::string const& _source, bool _assemble = false, bool _allowWarnings = true)
+bool successParse(
+ string const& _source,
+ bool _assemble = false,
+ bool _allowWarnings = true,
+ AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM
+)
{
- return !parseAndReturnFirstError(_source, _assemble, _allowWarnings);
+ return !parseAndReturnFirstError(_source, _assemble, _allowWarnings, _machine);
}
bool successAssemble(string const& _source, bool _allowWarnings = true)
{
- return successParse(_source, true, _allowWarnings);
+ return successParse(_source, true, _allowWarnings, AssemblyStack::Machine::EVM) &&
+ successParse(_source, true, _allowWarnings, AssemblyStack::Machine::EVM15);
}
Error expectError(std::string const& _source, bool _assemble, bool _allowWarnings = false)
@@ -100,29 +107,35 @@ Error expectError(std::string const& _source, bool _assemble, bool _allowWarning
return *error;
}
-void parsePrintCompare(string const& _source)
+void parsePrintCompare(string const& _source, bool _canWarn = false)
{
- assembly::InlineAssemblyStack stack;
- BOOST_REQUIRE(stack.parse(std::make_shared<Scanner>(CharStream(_source))));
- BOOST_REQUIRE(stack.errors().empty());
- BOOST_CHECK_EQUAL(stack.toString(), _source);
+ AssemblyStack stack;
+ BOOST_REQUIRE(stack.parseAndAnalyze("", _source));
+ if (_canWarn)
+ BOOST_REQUIRE(Error::containsOnlyWarnings(stack.errors()));
+ else
+ BOOST_REQUIRE(stack.errors().empty());
+ BOOST_CHECK_EQUAL(stack.print(), _source);
}
}
-#define CHECK_ERROR(text, assemble, typ, substring) \
+#define CHECK_ERROR(text, assemble, typ, substring, warnings) \
do \
{ \
- Error err = expectError((text), (assemble), false); \
+ Error err = expectError((text), (assemble), warnings); \
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)
+CHECK_ERROR(text, false, type, substring, false)
+
+#define CHECK_PARSE_WARNING(text, type, substring) \
+CHECK_ERROR(text, false, type, substring, false)
#define CHECK_ASSEMBLE_ERROR(text, type, substring) \
-CHECK_ERROR(text, true, type, substring)
+CHECK_ERROR(text, true, type, substring, false)
@@ -161,6 +174,27 @@ BOOST_AUTO_TEST_CASE(vardecl)
BOOST_CHECK(successParse("{ let x := 7 }"));
}
+BOOST_AUTO_TEST_CASE(vardecl_name_clashes)
+{
+ CHECK_PARSE_ERROR("{ let x := 1 let x := 2 }", DeclarationError, "Variable name x already taken in this scope.");
+}
+
+BOOST_AUTO_TEST_CASE(vardecl_multi)
+{
+ BOOST_CHECK(successParse("{ function f() -> x, y {} let x, y := f() }"));
+}
+
+BOOST_AUTO_TEST_CASE(vardecl_multi_conflict)
+{
+ CHECK_PARSE_ERROR("{ function f() -> x, y {} let x, x := f() }", DeclarationError, "Variable name x already taken in this scope.");
+}
+
+BOOST_AUTO_TEST_CASE(vardecl_bool)
+{
+ CHECK_PARSE_ERROR("{ let x := true }", ParserError, "True and false are not valid literals.");
+ CHECK_PARSE_ERROR("{ let x := false }", ParserError, "True and false are not valid literals.");
+}
+
BOOST_AUTO_TEST_CASE(assignment)
{
BOOST_CHECK(successParse("{ let x := 2 7 8 add =: x }"));
@@ -181,6 +215,16 @@ BOOST_AUTO_TEST_CASE(functional)
BOOST_CHECK(successParse("{ let x := 2 add(7, mul(6, x)) mul(7, 8) add =: x }"));
}
+BOOST_AUTO_TEST_CASE(functional_partial)
+{
+ CHECK_PARSE_ERROR("{ let x := byte }", ParserError, "Expected token \"(\"");
+}
+
+BOOST_AUTO_TEST_CASE(functional_partial_success)
+{
+ BOOST_CHECK(successParse("{ let x := byte(1, 2) }"));
+}
+
BOOST_AUTO_TEST_CASE(functional_assignment)
{
BOOST_CHECK(successParse("{ let x := 2 x := 7 }"));
@@ -202,6 +246,89 @@ BOOST_AUTO_TEST_CASE(variable_use_before_decl)
CHECK_PARSE_ERROR("{ let x := mul(2, x) }", DeclarationError, "Variable x used before it was declared.");
}
+BOOST_AUTO_TEST_CASE(switch_statement)
+{
+ BOOST_CHECK(successParse("{ switch 42 default {} }"));
+ BOOST_CHECK(successParse("{ switch 42 case 1 {} }"));
+ BOOST_CHECK(successParse("{ switch 42 case 1 {} case 2 {} }"));
+ BOOST_CHECK(successParse("{ switch 42 case 1 {} default {} }"));
+ BOOST_CHECK(successParse("{ switch 42 case 1 {} case 2 {} default {} }"));
+ BOOST_CHECK(successParse("{ switch mul(1, 2) case 1 {} case 2 {} default {} }"));
+ BOOST_CHECK(successParse("{ function f() -> x {} switch f() case 1 {} case 2 {} default {} }"));
+}
+
+BOOST_AUTO_TEST_CASE(switch_no_cases)
+{
+ CHECK_PARSE_ERROR("{ switch 42 }", ParserError, "Switch statement without any cases.");
+}
+
+BOOST_AUTO_TEST_CASE(switch_duplicate_case)
+{
+ CHECK_PARSE_ERROR("{ switch 42 case 1 {} case 1 {} default {} }", DeclarationError, "Duplicate case defined");
+}
+
+BOOST_AUTO_TEST_CASE(switch_invalid_expression)
+{
+ CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected.");
+ CHECK_PARSE_ERROR("{ switch calldatasize default {} }", ParserError, "Instructions are not supported as expressions for switch.");
+ CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
+}
+
+BOOST_AUTO_TEST_CASE(switch_default_before_case)
+{
+ CHECK_PARSE_ERROR("{ switch 42 default {} case 1 {} }", ParserError, "Case not allowed after default case.");
+}
+
+BOOST_AUTO_TEST_CASE(switch_duplicate_default_case)
+{
+ CHECK_PARSE_ERROR("{ switch 42 default {} default {} }", ParserError, "Only one default case allowed.");
+}
+
+BOOST_AUTO_TEST_CASE(switch_invalid_case)
+{
+ CHECK_PARSE_ERROR("{ switch 42 case mul(1, 2) {} case 2 {} default {} }", ParserError, "Literal expected.");
+}
+
+BOOST_AUTO_TEST_CASE(switch_invalid_body)
+{
+ CHECK_PARSE_ERROR("{ switch 42 case 1 mul case 2 {} default {} }", ParserError, "Expected token LBrace got 'Identifier'");
+}
+
+BOOST_AUTO_TEST_CASE(for_statement)
+{
+ BOOST_CHECK(successParse("{ for {} 1 {} {} }"));
+ BOOST_CHECK(successParse("{ for { let i := 1 } lt(i, 5) { i := add(i, 1) } {} }"));
+}
+
+BOOST_AUTO_TEST_CASE(for_invalid_expression)
+{
+ CHECK_PARSE_ERROR("{ for {} {} {} {} }", ParserError, "Literal, identifier or instruction expected.");
+ CHECK_PARSE_ERROR("{ for 1 1 {} {} }", ParserError, "Expected token LBrace got 'Number'");
+ CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected token LBrace got 'Number'");
+ CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected token LBrace got 'Number'");
+ CHECK_PARSE_ERROR("{ for {} calldatasize {} {} }", ParserError, "Instructions are not supported as conditions for the for statement.");
+ CHECK_PARSE_ERROR("{ for {} mstore(1, 1) {} {} }", ParserError, "Instruction \"mstore\" not allowed in this context");
+}
+
+BOOST_AUTO_TEST_CASE(for_visibility)
+{
+ BOOST_CHECK(successParse("{ for { let i := 1 } i { pop(i) } { pop(i) } }"));
+ CHECK_PARSE_ERROR("{ for {} i { let i := 1 } {} }", DeclarationError, "Identifier not found");
+ CHECK_PARSE_ERROR("{ for {} 1 { let i := 1 } { pop(i) } }", DeclarationError, "Identifier not found");
+ CHECK_PARSE_ERROR("{ for {} 1 { pop(i) } { let i := 1 } }", DeclarationError, "Identifier not found");
+ CHECK_PARSE_ERROR("{ for { pop(i) } 1 { let i := 1 } {} }", DeclarationError, "Identifier not found");
+ CHECK_PARSE_ERROR("{ for { pop(i) } 1 { } { let i := 1 } }", DeclarationError, "Identifier not found");
+ CHECK_PARSE_ERROR("{ for {} i {} { let i := 1 } }", DeclarationError, "Identifier not found");
+ CHECK_PARSE_ERROR("{ for {} 1 { pop(i) } { let i := 1 } }", DeclarationError, "Identifier not found");
+ CHECK_PARSE_ERROR("{ for { let x := 1 } 1 { let x := 1 } {} }", DeclarationError, "Variable name x already taken in this scope");
+ CHECK_PARSE_ERROR("{ for { let x := 1 } 1 {} { let x := 1 } }", DeclarationError, "Variable name x already taken in this scope");
+ CHECK_PARSE_ERROR("{ let x := 1 for { let x := 1 } 1 {} {} }", DeclarationError, "Variable name x already taken in this scope");
+ CHECK_PARSE_ERROR("{ let x := 1 for {} 1 { let x := 1 } {} }", DeclarationError, "Variable name x already taken in this scope");
+ CHECK_PARSE_ERROR("{ let x := 1 for {} 1 {} { let x := 1 } }", DeclarationError, "Variable name x already taken in this scope");
+ // Check that body and post are not sub-scopes of each other.
+ BOOST_CHECK(successParse("{ for {} 1 { let x := 1 } { let x := 1 } }"));
+}
+
BOOST_AUTO_TEST_CASE(blocks)
{
BOOST_CHECK(successParse("{ let x := 7 { let y := 3 } { let z := 2 } }"));
@@ -243,6 +370,23 @@ BOOST_AUTO_TEST_CASE(variable_access_cross_functions)
CHECK_PARSE_ERROR("{ let x := 2 function g() { x pop } }", DeclarationError, "Identifier not found.");
}
+BOOST_AUTO_TEST_CASE(invalid_tuple_assignment)
+{
+ /// The push(42) is added here to silence the unbalanced stack error, so that there's only one error reported.
+ CHECK_PARSE_ERROR("{ 42 let x, y := 1 }", DeclarationError, "Variable count mismatch.");
+}
+
+BOOST_AUTO_TEST_CASE(instruction_too_few_arguments)
+{
+ CHECK_PARSE_ERROR("{ mul() }", ParserError, "Expected expression (\"mul\" expects 2 arguments)");
+ CHECK_PARSE_ERROR("{ mul(1) }", ParserError, "Expected comma (\"mul\" expects 2 arguments)");
+}
+
+BOOST_AUTO_TEST_CASE(instruction_too_many_arguments)
+{
+ CHECK_PARSE_ERROR("{ mul(1, 2, 3) }", ParserError, "Expected ')' (\"mul\" expects 2 arguments)");
+}
+
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(Printing)
@@ -269,7 +413,7 @@ BOOST_AUTO_TEST_CASE(print_functional)
BOOST_AUTO_TEST_CASE(print_label)
{
- parsePrintCompare("{\n loop:\n jump(loop)\n}");
+ parsePrintCompare("{\n loop:\n jump(loop)\n}", true);
}
BOOST_AUTO_TEST_CASE(print_assignments)
@@ -277,6 +421,11 @@ BOOST_AUTO_TEST_CASE(print_assignments)
parsePrintCompare("{\n let x := mul(2, 3)\n 7\n =: x\n x := add(1, 2)\n}");
}
+BOOST_AUTO_TEST_CASE(print_multi_assignments)
+{
+ parsePrintCompare("{\n function f() -> x, y\n {\n }\n let x, y := f()\n}");
+}
+
BOOST_AUTO_TEST_CASE(print_string_literals)
{
parsePrintCompare("{\n \"\\n'\\xab\\x95\\\"\"\n pop\n}");
@@ -286,13 +435,23 @@ BOOST_AUTO_TEST_CASE(print_string_literal_unicode)
{
string source = "{ let x := \"\\u1bac\" }";
string parsed = "{\n let x := \"\\xe1\\xae\\xac\"\n}";
- assembly::InlineAssemblyStack stack;
- BOOST_REQUIRE(stack.parse(std::make_shared<Scanner>(CharStream(source))));
+ AssemblyStack stack;
+ BOOST_REQUIRE(stack.parseAndAnalyze("", source));
BOOST_REQUIRE(stack.errors().empty());
- BOOST_CHECK_EQUAL(stack.toString(), parsed);
+ BOOST_CHECK_EQUAL(stack.print(), parsed);
parsePrintCompare(parsed);
}
+BOOST_AUTO_TEST_CASE(print_switch)
+{
+ parsePrintCompare("{\n switch 42\n case 1 {\n }\n case 2 {\n }\n default {\n }\n}");
+}
+
+BOOST_AUTO_TEST_CASE(print_for)
+{
+ parsePrintCompare("{\n let ret := 5\n for {\n let i := 1\n }\n lt(i, 15)\n {\n i := add(i, 1)\n }\n {\n ret := mul(ret, i)\n }\n}");
+}
+
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}");
@@ -358,7 +517,7 @@ BOOST_AUTO_TEST_CASE(imbalanced_stack)
BOOST_AUTO_TEST_CASE(error_tag)
{
- BOOST_CHECK(successAssemble("{ jump(invalidJumpLabel) }"));
+ CHECK_ERROR("{ jump(invalidJumpLabel) }", true, DeclarationError, "Identifier not found", true);
}
BOOST_AUTO_TEST_CASE(designated_invalid_instruction)
@@ -386,6 +545,101 @@ BOOST_AUTO_TEST_CASE(revert)
BOOST_CHECK(successAssemble("{ revert(0, 0) }"));
}
+BOOST_AUTO_TEST_CASE(function_calls)
+{
+ BOOST_CHECK(successAssemble("{ function f() {} }"));
+ BOOST_CHECK(successAssemble("{ function f() { let y := 2 } }"));
+ BOOST_CHECK(successAssemble("{ function f() -> z { let y := 2 } }"));
+ BOOST_CHECK(successAssemble("{ function f(a) { let y := 2 } }"));
+ BOOST_CHECK(successAssemble("{ function f(a) { let y := a } }"));
+ BOOST_CHECK(successAssemble("{ function f() -> x, y, z {} }"));
+ BOOST_CHECK(successAssemble("{ function f(x, y, z) {} }"));
+ BOOST_CHECK(successAssemble("{ function f(a, b) -> x, y, z { y := a } }"));
+ BOOST_CHECK(successAssemble("{ function f() {} f() }"));
+ BOOST_CHECK(successAssemble("{ function f() -> x, y { x := 1 y := 2} let a, b := f() }"));
+ BOOST_CHECK(successAssemble("{ function f(a, b) -> x, y { x := b y := a } let a, b := f(2, 3) }"));
+ BOOST_CHECK(successAssemble("{ function rec(a) { rec(sub(a, 1)) } rec(2) }"));
+ BOOST_CHECK(successAssemble("{ let r := 2 function f() -> x, y { x := 1 y := 2} let a, b := f() b := r }"));
+ BOOST_CHECK(successAssemble("{ function f() { g() } function g() { f() } }"));
+}
+
+BOOST_AUTO_TEST_CASE(embedded_functions)
+{
+ BOOST_CHECK(successAssemble("{ function f(r, s) -> x { function g(a) -> b { } x := g(2) } let x := f(2, 3) }"));
+}
+
+BOOST_AUTO_TEST_CASE(switch_statement)
+{
+ BOOST_CHECK(successAssemble("{ switch 1 default {} }"));
+ BOOST_CHECK(successAssemble("{ switch 1 case 1 {} default {} }"));
+ BOOST_CHECK(successAssemble("{ switch 1 case 1 {} }"));
+ BOOST_CHECK(successAssemble("{ let a := 3 switch a case 1 { a := 1 } case 2 { a := 5 } a := 9}"));
+ BOOST_CHECK(successAssemble("{ let a := 2 switch calldataload(0) case 1 { a := 1 } case 2 { a := 5 } }"));
+}
+
+BOOST_AUTO_TEST_CASE(for_statement)
+{
+ BOOST_CHECK(successAssemble("{ for {} 1 {} {} }"));
+ BOOST_CHECK(successAssemble("{ let x := calldatasize() for { let i := 0} lt(i, x) { i := add(i, 1) } { mstore(i, 2) } }"));
+}
+
+
+BOOST_AUTO_TEST_CASE(large_constant)
+{
+ auto source = R"({
+ switch mul(1, 2)
+ case 0x0000000000000000000000000000000000000000000000000000000026121ff0 {
+ }
+ })";
+ BOOST_CHECK(successAssemble(source));
+}
+
+BOOST_AUTO_TEST_CASE(keccak256)
+{
+ BOOST_CHECK(successAssemble("{ 0 0 keccak256 pop }"));
+ BOOST_CHECK(successAssemble("{ pop(keccak256(0, 0)) }"));
+ BOOST_CHECK(successAssemble("{ 0 0 sha3 pop }"));
+ BOOST_CHECK(successAssemble("{ pop(sha3(0, 0)) }"));
+}
+
+BOOST_AUTO_TEST_CASE(returndatasize)
+{
+ BOOST_CHECK(successAssemble("{ let r := returndatasize }"));
+}
+
+BOOST_AUTO_TEST_CASE(returndatasize_functional)
+{
+ BOOST_CHECK(successAssemble("{ let r := returndatasize() }"));
+}
+
+BOOST_AUTO_TEST_CASE(returndatacopy)
+{
+ BOOST_CHECK(successAssemble("{ 64 32 0 returndatacopy }"));
+}
+
+BOOST_AUTO_TEST_CASE(returndatacopy_functional)
+{
+ BOOST_CHECK(successAssemble("{ returndatacopy(0, 32, 64) }"));
+}
+
+BOOST_AUTO_TEST_CASE(staticcall)
+{
+ BOOST_CHECK(successAssemble("{ pop(staticcall(10000, 0x123, 64, 0x10, 128, 0x10)) }"));
+}
+
+BOOST_AUTO_TEST_CASE(create2)
+{
+ BOOST_CHECK(successAssemble("{ pop(create2(10, 0x123, 32, 64)) }"));
+}
+
+BOOST_AUTO_TEST_CASE(jump_warning)
+{
+ CHECK_PARSE_WARNING("{ 1 jump }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ 1 2 jumpi }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ a: jump(a) }", Warning, "Jump instructions");
+ CHECK_PARSE_WARNING("{ a: jumpi(a, 2) }", Warning, "Jump instructions");
+}
+
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/JSONCompiler.cpp b/test/libsolidity/JSONCompiler.cpp
new file mode 100644
index 00000000..aa690f0b
--- /dev/null
+++ b/test/libsolidity/JSONCompiler.cpp
@@ -0,0 +1,111 @@
+/*
+ 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/>.
+*/
+/**
+ * @date 2017
+ * Unit tests for solc/jsonCompiler.cpp.
+ */
+
+#include <string>
+#include <iostream>
+#include <regex>
+#include <boost/test/unit_test.hpp>
+#include <libdevcore/JSON.h>
+
+#include "../Metadata.h"
+#include "../TestHelper.h"
+
+using namespace std;
+
+extern "C"
+{
+extern char const* compileJSONMulti(char const* _input, bool _optimize);
+}
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+namespace
+{
+
+Json::Value compile(string const& _input)
+{
+ string output(compileJSONMulti(_input.c_str(), dev::test::Options::get().optimize));
+ Json::Value ret;
+ BOOST_REQUIRE(Json::Reader().parse(output, ret, false));
+ return ret;
+}
+
+} // end anonymous namespace
+
+BOOST_AUTO_TEST_SUITE(JSONCompiler)
+
+BOOST_AUTO_TEST_CASE(basic_compilation)
+{
+ char const* input = R"(
+ {
+ "sources": {
+ "fileA": "contract A { }"
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(result.isObject());
+ BOOST_CHECK(result["contracts"].isObject());
+ BOOST_CHECK(result["contracts"]["fileA:A"].isObject());
+ Json::Value contract = result["contracts"]["fileA:A"];
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["interface"].isString());
+ BOOST_CHECK_EQUAL(contract["interface"].asString(), "[]");
+ BOOST_CHECK(contract["bytecode"].isString());
+ BOOST_CHECK_EQUAL(
+ dev::test::bytecodeSansMetadata(contract["bytecode"].asString()),
+ "60606040523415600e57600080fd5b5b603680601c6000396000f30060606040525b600080fd00"
+ );
+ BOOST_CHECK(contract["runtimeBytecode"].isString());
+ BOOST_CHECK_EQUAL(
+ dev::test::bytecodeSansMetadata(contract["runtimeBytecode"].asString()),
+ "60606040525b600080fd00"
+ );
+ BOOST_CHECK(contract["functionHashes"].isObject());
+ BOOST_CHECK(contract["gasEstimates"].isObject());
+ BOOST_CHECK_EQUAL(
+ dev::jsonCompactPrint(contract["gasEstimates"]),
+ "{\"creation\":[62,10800],\"external\":{},\"internal\":{}}"
+ );
+ BOOST_CHECK(contract["metadata"].isString());
+ BOOST_CHECK(dev::test::isValidMetadata(contract["metadata"].asString()));
+ BOOST_CHECK(result["sources"].isObject());
+ BOOST_CHECK(result["sources"]["fileA"].isObject());
+ BOOST_CHECK(result["sources"]["fileA"]["AST"].isObject());
+ BOOST_CHECK_EQUAL(
+ dev::jsonCompactPrint(result["sources"]["fileA"]["AST"]),
+ "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]}},"
+ "\"children\":[{\"attributes\":{\"baseContracts\":[null],\"contractDependencies\":[null],"
+ "\"contractKind\":\"contract\",\"documentation\":null,\"fullyImplemented\":true,\"linearizedBaseContracts\":[1],"
+ "\"name\":\"A\",\"nodes\":[null],\"scope\":2},\"id\":1,\"name\":\"ContractDefinition\","
+ "\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}"
+ );
+}
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+} // end namespaces
diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp
new file mode 100644
index 00000000..60bb2e4e
--- /dev/null
+++ b/test/libsolidity/Metadata.cpp
@@ -0,0 +1,63 @@
+/*
+ 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/>.
+ */
+/**
+ * @date 2017
+ * Unit tests for the metadata output.
+ */
+
+#include "../Metadata.h"
+#include "../TestHelper.h"
+#include <libsolidity/interface/CompilerStack.h>
+#include <libdevcore/SwarmHash.h>
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+BOOST_AUTO_TEST_SUITE(Metadata)
+
+BOOST_AUTO_TEST_CASE(metadata_stamp)
+{
+ // Check that the metadata stamp is at the end of the runtime bytecode.
+ char const* sourceCode = R"(
+ pragma solidity >=0.0;
+ contract test {
+ function g(function(uint) external returns (uint) x) {}
+ }
+ )";
+ CompilerStack compilerStack;
+ BOOST_REQUIRE(compilerStack.compile(std::string(sourceCode)));
+ bytes const& bytecode = compilerStack.runtimeObject("test").bytecode;
+ std::string const& metadata = compilerStack.onChainMetadata("test");
+ BOOST_CHECK(dev::test::isValidMetadata(metadata));
+ bytes hash = dev::swarmHash(metadata).asBytes();
+ BOOST_REQUIRE(hash.size() == 32);
+ BOOST_REQUIRE(bytecode.size() >= 2);
+ size_t metadataCBORSize = (size_t(bytecode.end()[-2]) << 8) + size_t(bytecode.end()[-1]);
+ BOOST_REQUIRE(metadataCBORSize < bytecode.size() - 2);
+ bytes expectation = bytes{0xa1, 0x65, 'b', 'z', 'z', 'r', '0', 0x58, 0x20} + hash;
+ BOOST_CHECK(std::equal(expectation.begin(), expectation.end(), bytecode.end() - metadataCBORSize - 2));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+}
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index bdcc5b10..f87390e1 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -44,7 +44,7 @@ public:
{
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parseAndAnalyze("pragma solidity >=0.0;\n" + _code), "Parsing contract failed");
- Json::Value generatedInterface = m_compilerStack.metadata("", DocumentationType::ABIInterface);
+ Json::Value generatedInterface = m_compilerStack.contractABI("");
Json::Value expectedInterface;
m_reader.parse(_expectedInterfaceString, expectedInterface);
BOOST_CHECK_MESSAGE(
@@ -752,26 +752,6 @@ BOOST_AUTO_TEST_CASE(function_type)
checkInterface(sourceCode, interface);
}
-BOOST_AUTO_TEST_CASE(metadata_stamp)
-{
- // Check that the metadata stamp is at the end of the runtime bytecode.
- char const* sourceCode = R"(
- pragma solidity >=0.0;
- contract test {
- function g(function(uint) external returns (uint) x) {}
- }
- )";
- BOOST_REQUIRE(m_compilerStack.compile(std::string(sourceCode)));
- bytes const& bytecode = m_compilerStack.runtimeObject("test").bytecode;
- bytes hash = dev::swarmHash(m_compilerStack.onChainMetadata("test")).asBytes();
- BOOST_REQUIRE(hash.size() == 32);
- BOOST_REQUIRE(bytecode.size() >= 2);
- size_t metadataCBORSize = (size_t(bytecode.end()[-2]) << 8) + size_t(bytecode.end()[-1]);
- BOOST_REQUIRE(metadataCBORSize < bytecode.size() - 2);
- bytes expectation = bytes{0xa1, 0x65, 'b', 'z', 'z', 'r', '0', 0x58, 0x20} + hash;
- BOOST_CHECK(std::equal(expectation.begin(), expectation.end(), bytecode.end() - metadataCBORSize - 2));
-}
-
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index f2f4b8b0..a6c01283 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -1355,7 +1355,7 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
function test() {
data = 8;
name = "Celina";
- a_hash = sha3(123);
+ a_hash = keccak256(123);
an_address = address(0x1337);
super_secret_data = 42;
}
@@ -1864,12 +1864,12 @@ BOOST_AUTO_TEST_CASE(selfdestruct)
BOOST_CHECK_EQUAL(balanceAt(address), amount);
}
-BOOST_AUTO_TEST_CASE(sha3)
+BOOST_AUTO_TEST_CASE(keccak256)
{
char const* sourceCode = R"(
contract test {
- function a(bytes32 input) returns (bytes32 sha3hash) {
- return sha3(input);
+ function a(bytes32 input) returns (bytes32 hash) {
+ return keccak256(input);
}
}
)";
@@ -1883,6 +1883,23 @@ BOOST_AUTO_TEST_CASE(sha3)
testContractAgainstCpp("a(bytes32)", f, u256(-1));
}
+BOOST_AUTO_TEST_CASE(sha3)
+{
+ char const* sourceCode = R"(
+ contract test {
+ // to confuse the optimiser
+ function b(bytes32 input) returns (bytes32) {
+ return sha3(input);
+ }
+ function a(bytes32 input) returns (bool) {
+ return keccak256(input) == b(input);
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_REQUIRE(callContractFunction("a(bytes32)", u256(42)) == encodeArgs(true));
+}
+
BOOST_AUTO_TEST_CASE(sha256)
{
char const* sourceCode = R"(
@@ -3110,13 +3127,13 @@ BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
BOOST_CHECK(callContractFunction("f(uint256)", 9) == encodeArgs(9));
}
-BOOST_AUTO_TEST_CASE(sha3_multiple_arguments)
+BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments)
{
char const* sourceCode = R"(
contract c {
function foo(uint a, uint b, uint c) returns (bytes32 d)
{
- d = sha3(a, b, c);
+ d = keccak256(a, b, c);
}
}
)";
@@ -3129,13 +3146,13 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments)
toBigEndian(u256(13)))));
}
-BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_numeric_literals)
+BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_numeric_literals)
{
char const* sourceCode = R"(
contract c {
function foo(uint a, uint16 b) returns (bytes32 d)
{
- d = sha3(a, b, 145);
+ d = keccak256(a, b, 145);
}
}
)";
@@ -3148,17 +3165,17 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_numeric_literals)
bytes(1, 0x91))));
}
-BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals)
+BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_string_literals)
{
char const* sourceCode = R"(
contract c {
function foo() returns (bytes32 d)
{
- d = sha3("foo");
+ d = keccak256("foo");
}
function bar(uint a, uint16 b) returns (bytes32 d)
{
- d = sha3(a, b, 145, "foo");
+ d = keccak256(a, b, 145, "foo");
}
}
)";
@@ -3174,7 +3191,7 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals)
bytes{0x66, 0x6f, 0x6f})));
}
-BOOST_AUTO_TEST_CASE(sha3_with_bytes)
+BOOST_AUTO_TEST_CASE(keccak256_with_bytes)
{
char const* sourceCode = R"(
contract c {
@@ -3185,7 +3202,7 @@ BOOST_AUTO_TEST_CASE(sha3_with_bytes)
data[0] = "f";
data[1] = "o";
data[2] = "o";
- return sha3(data) == sha3("foo");
+ return keccak256(data) == keccak256("foo");
}
}
)";
@@ -3193,7 +3210,7 @@ BOOST_AUTO_TEST_CASE(sha3_with_bytes)
BOOST_CHECK(callContractFunction("foo()") == encodeArgs(true));
}
-BOOST_AUTO_TEST_CASE(iterated_sha3_with_bytes)
+BOOST_AUTO_TEST_CASE(iterated_keccak256_with_bytes)
{
char const* sourceCode = R"(
contract c {
@@ -3204,7 +3221,7 @@ BOOST_AUTO_TEST_CASE(iterated_sha3_with_bytes)
data[0] = "x";
data[1] = "y";
data[2] = "z";
- return sha3("b", sha3(data), "a");
+ return keccak256("b", keccak256(data), "a");
}
}
)";
@@ -3214,13 +3231,13 @@ BOOST_AUTO_TEST_CASE(iterated_sha3_with_bytes)
));
}
-BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments)
+BOOST_AUTO_TEST_CASE(sha3_multiple_arguments)
{
char const* sourceCode = R"(
contract c {
function foo(uint a, uint b, uint c) returns (bytes32 d)
{
- d = keccak256(a, b, c);
+ d = sha3(a, b, c);
}
})";
compileAndRun(sourceCode);
@@ -3245,7 +3262,7 @@ BOOST_AUTO_TEST_CASE(generic_call)
function sender() payable {}
function doSend(address rec) returns (uint d)
{
- bytes4 signature = bytes4(bytes32(sha3("receive(uint256)")));
+ bytes4 signature = bytes4(bytes32(keccak256("receive(uint256)")));
rec.call.value(2)(signature, 23);
return receiver(rec).received();
}
@@ -3270,7 +3287,7 @@ BOOST_AUTO_TEST_CASE(generic_callcode)
function Sender() payable { }
function doSend(address rec) returns (uint d)
{
- bytes4 signature = bytes4(bytes32(sha3("receive(uint256)")));
+ bytes4 signature = bytes4(bytes32(keccak256("receive(uint256)")));
rec.callcode.value(2)(signature, 23);
return Receiver(rec).received();
}
@@ -3307,7 +3324,7 @@ BOOST_AUTO_TEST_CASE(generic_delegatecall)
function Sender() payable {}
function doSend(address rec) payable
{
- bytes4 signature = bytes4(bytes32(sha3("receive(uint256)")));
+ bytes4 signature = bytes4(bytes32(keccak256("receive(uint256)")));
if (rec.delegatecall(signature, 23)) {}
}
}
@@ -3372,7 +3389,7 @@ BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory)
char const* sourceCode = R"(
contract C {
function f() returns (bytes32) {
- return sha3("abc", msg.data);
+ return keccak256("abc", msg.data);
}
}
)";
@@ -3685,6 +3702,50 @@ BOOST_AUTO_TEST_CASE(enum_explicit_overflow)
BOOST_CHECK(callContractFunction("getChoiceExp(uint256)", 0) == encodeArgs(0));
}
+BOOST_AUTO_TEST_CASE(storing_invalid_boolean)
+{
+ char const* sourceCode = R"(
+ contract C {
+ event Ev(bool);
+ bool public perm;
+ function set() returns(uint) {
+ bool tmp;
+ assembly {
+ tmp := 5
+ }
+ perm = tmp;
+ return 1;
+ }
+ function ret() returns(bool) {
+ bool tmp;
+ assembly {
+ tmp := 5
+ }
+ return tmp;
+ }
+ function ev() returns(uint) {
+ bool tmp;
+ assembly {
+ tmp := 5
+ }
+ Ev(tmp);
+ return 1;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("set()") == encodeArgs(1));
+ BOOST_CHECK(callContractFunction("perm()") == encodeArgs(1));
+ BOOST_CHECK(callContractFunction("ret()") == encodeArgs(1));
+ BOOST_CHECK(callContractFunction("ev()") == encodeArgs(1));
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
+ BOOST_CHECK(m_logs[0].data == encodeArgs(1));
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
+ BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Ev(bool)")));
+}
+
+
BOOST_AUTO_TEST_CASE(using_contract_enums_with_explicit_contract_name)
{
char const* sourceCode = R"(
@@ -4466,6 +4527,38 @@ BOOST_AUTO_TEST_CASE(array_copy_including_mapping)
BOOST_CHECK(storageEmpty(m_contractAddress));
}
+BOOST_AUTO_TEST_CASE(swap_in_storage_overwrite)
+{
+ // This tests a swap in storage which does not work as one
+ // might expect because we do not have temporary storage.
+ // (x, y) = (y, x) is the same as
+ // y = x;
+ // x = y;
+ char const* sourceCode = R"(
+ contract c {
+ struct S { uint a; uint b; }
+ S public x;
+ S public y;
+ function set() {
+ x.a = 1; x.b = 2;
+ y.a = 3; y.b = 4;
+ }
+ function swap() {
+ (x, y) = (y, x);
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(0), u256(0)));
+ BOOST_CHECK(callContractFunction("y()") == encodeArgs(u256(0), u256(0)));
+ BOOST_CHECK(callContractFunction("set()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1), u256(2)));
+ BOOST_CHECK(callContractFunction("y()") == encodeArgs(u256(3), u256(4)));
+ BOOST_CHECK(callContractFunction("swap()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1), u256(2)));
+ BOOST_CHECK(callContractFunction("y()") == encodeArgs(u256(1), u256(2)));
+}
+
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base)
{
char const* sourceCode = R"(
@@ -5294,7 +5387,7 @@ BOOST_AUTO_TEST_CASE(reusing_memory)
mapping(uint => uint) map;
function f(uint x) returns (uint) {
map[x] = x;
- return (new Helper(uint(sha3(this.g(map[x]))))).flag();
+ return (new Helper(uint(keccak256(this.g(map[x]))))).flag();
}
function g(uint a) returns (uint)
{
@@ -7445,6 +7538,33 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_access)
BOOST_CHECK(callContractFunction("z()") == encodeArgs(u256(7)));
}
+BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_inside_function)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint16 x;
+ uint16 public y;
+ uint public z;
+ function f() returns (bool) {
+ uint off1;
+ uint off2;
+ assembly {
+ function f() -> o1 {
+ sstore(z_slot, 7)
+ o1 := y_offset
+ }
+ off2 := f()
+ }
+ assert(off2 == 2);
+ return true;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("z()") == encodeArgs(u256(7)));
+}
+
BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_via_pointer)
{
char const* sourceCode = R"(
@@ -7518,6 +7638,178 @@ BOOST_AUTO_TEST_CASE(inline_assembly_function_access)
BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(10)));
}
+BOOST_AUTO_TEST_CASE(inline_assembly_function_call)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() {
+ assembly {
+ function asmfun(a, b, c) -> x, y, z {
+ x := a
+ y := b
+ z := 7
+ }
+ let a1, b1, c1 := asmfun(1, 2, 3)
+ mstore(0x00, a1)
+ mstore(0x20, b1)
+ mstore(0x40, c1)
+ return(0, 0x60)
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7)));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_function_call2)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() {
+ assembly {
+ let d := 0x10
+ function asmfun(a, b, c) -> x, y, z {
+ x := a
+ y := b
+ z := 7
+ }
+ let a1, b1, c1 := asmfun(1, 2, 3)
+ mstore(0x00, a1)
+ mstore(0x20, b1)
+ mstore(0x40, c1)
+ mstore(0x60, d)
+ return(0, 0x80)
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7), u256(0x10)));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_embedded_function_call)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() {
+ assembly {
+ let d := 0x10
+ function asmfun(a, b, c) -> x, y, z {
+ x := g(a)
+ function g(r) -> s { s := mul(r, r) }
+ y := g(b)
+ z := 7
+ }
+ let a1, b1, c1 := asmfun(1, 2, 3)
+ mstore(0x00, a1)
+ mstore(0x20, b1)
+ mstore(0x40, c1)
+ mstore(0x60, d)
+ return(0, 0x80)
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(4), u256(7), u256(0x10)));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_switch)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f(uint a) returns (uint b) {
+ assembly {
+ switch a
+ case 1 { b := 8 }
+ case 2 { b := 9 }
+ default { b := 2 }
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(0)) == encodeArgs(u256(2)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(1)) == encodeArgs(u256(8)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(2)) == encodeArgs(u256(9)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(3)) == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_recursion)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f(uint a) returns (uint b) {
+ assembly {
+ function fac(n) -> nf {
+ switch n
+ case 0 { nf := 1 }
+ case 1 { nf := 1 }
+ default { nf := mul(n, fac(sub(n, 1))) }
+ }
+ b := fac(a)
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(0)) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(1)) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(2)) == encodeArgs(u256(2)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(3)) == encodeArgs(u256(6)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(4)) == encodeArgs(u256(24)));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_for)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f(uint a) returns (uint b) {
+ assembly {
+ function fac(n) -> nf {
+ nf := 1
+ for { let i := n } gt(i, 0) { i := sub(i, 1) } {
+ nf := mul(nf, i)
+ }
+ }
+ b := fac(a)
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(0)) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(1)) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(2)) == encodeArgs(u256(2)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(3)) == encodeArgs(u256(6)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(4)) == encodeArgs(u256(24)));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_for2)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint st;
+ function f(uint a) returns (uint b, uint c, uint d) {
+ st = 0;
+ assembly {
+ function sideeffect(r) -> x { sstore(0, add(sload(0), r)) x := 1}
+ for { let i := a } eq(i, sideeffect(2)) { d := add(d, 3) } {
+ b := i
+ i := 0
+ }
+ }
+ c = st;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(0)) == encodeArgs(u256(0), u256(2), u256(0)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(1)) == encodeArgs(u256(1), u256(4), u256(3)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(2)) == encodeArgs(u256(0), u256(2), u256(0)));
+}
+
BOOST_AUTO_TEST_CASE(index_access_with_type_conversion)
{
// Test for a bug where higher order bits cleanup was not done for array index access.
@@ -9126,21 +9418,6 @@ BOOST_AUTO_TEST_CASE(packed_storage_overflow)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0x1234), u256(0), u256(0), u256(0xfffe)));
}
-BOOST_AUTO_TEST_CASE(inline_assembly_invalidjumplabel)
-{
- char const* sourceCode = R"(
- contract C {
- function f() {
- assembly {
- jump(invalidJumpLabel)
- }
- }
- }
- )";
- compileAndRun(sourceCode, 0, "C");
- BOOST_CHECK(callContractFunction("f()") == encodeArgs());
-}
-
BOOST_AUTO_TEST_CASE(contracts_separated_with_comment)
{
char const* sourceCode = R"(
@@ -9268,6 +9545,50 @@ BOOST_AUTO_TEST_CASE(revert)
BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(42)));
}
+BOOST_AUTO_TEST_CASE(negative_stack_height)
+{
+ // This code was causing negative stack height during code generation
+ // because the stack height was not adjusted at the beginning of functions.
+ char const* sourceCode = R"(
+ contract C {
+ mapping(uint => Invoice) public invoices;
+ struct Invoice {
+ uint AID;
+ bool Aboola;
+ bool Aboolc;
+ bool exists;
+ }
+ function nredit(uint startindex) public constant returns(uint[500] CIDs, uint[500] dates, uint[500] RIDs, bool[500] Cboolas, uint[500] amounts){}
+ function return500InvoicesByDates(uint begindate, uint enddate, uint startindex) public constant returns(uint[500] AIDs, bool[500] Aboolas, uint[500] dates, bytes32[3][500] Abytesas, bytes32[3][500] bytesbs, bytes32[2][500] bytescs, uint[500] amounts, bool[500] Aboolbs, bool[500] Aboolcs){}
+ function return500PaymentsByDates(uint begindate, uint enddate, uint startindex) public constant returns(uint[500] BIDs, uint[500] dates, uint[500] RIDs, bool[500] Bboolas, bytes32[3][500] bytesbs,bytes32[2][500] bytescs, uint[500] amounts, bool[500] Bboolbs){}
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+}
+
+BOOST_AUTO_TEST_CASE(literal_empty_string)
+{
+ char const* sourceCode = R"(
+ contract C {
+ bytes32 public x;
+ uint public a;
+ function f(bytes32 _x, uint _a) {
+ x = _x;
+ a = _a;
+ }
+ function g() {
+ this.f("", 2);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(2)));
+}
+
BOOST_AUTO_TEST_CASE(scientific_notation)
{
char const* sourceCode = R"(
@@ -9336,6 +9657,45 @@ BOOST_AUTO_TEST_CASE(interface)
BOOST_CHECK(callContractFunction("f(address)", recipient) == encodeArgs(true));
}
+BOOST_AUTO_TEST_CASE(keccak256_assembly)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() returns (bytes32 ret) {
+ assembly {
+ ret := keccak256(0, 0)
+ }
+ }
+ function g() returns (bytes32 ret) {
+ assembly {
+ 0
+ 0
+ keccak256
+ =: ret
+ }
+ }
+ function h() returns (bytes32 ret) {
+ assembly {
+ ret := sha3(0, 0)
+ }
+ }
+ function i() returns (bytes32 ret) {
+ assembly {
+ 0
+ 0
+ sha3
+ =: ret
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
+ BOOST_CHECK(callContractFunction("g()") == fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
+ BOOST_CHECK(callContractFunction("h()") == fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
+ BOOST_CHECK(callContractFunction("i()") == fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp
index 3116aea8..58efa0a2 100644
--- a/test/libsolidity/SolidityExpressionCompiler.cpp
+++ b/test/libsolidity/SolidityExpressionCompiler.cpp
@@ -29,6 +29,7 @@
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/TypeChecker.h>
+#include <libsolidity/interface/ErrorReporter.h>
#include "../TestHelper.h"
using namespace std;
@@ -98,7 +99,8 @@ bytes compileFirstExpression(
try
{
ErrorList errors;
- sourceUnit = Parser(errors).parse(make_shared<Scanner>(CharStream(_sourceCode)));
+ ErrorReporter errorReporter(errors);
+ sourceUnit = Parser(errorReporter).parse(make_shared<Scanner>(CharStream(_sourceCode)));
if (!sourceUnit)
return bytes();
}
@@ -114,8 +116,9 @@ bytes compileFirstExpression(
declarations.push_back(variable.get());
ErrorList errors;
+ ErrorReporter errorReporter(errors);
map<ASTNode const*, shared_ptr<DeclarationContainer>> scopes;
- NameAndTypeResolver resolver(declarations, scopes, errors);
+ NameAndTypeResolver resolver(declarations, scopes, errorReporter);
resolver.registerDeclarations(*sourceUnit);
vector<ContractDefinition const*> inheritanceHierarchy;
@@ -128,7 +131,8 @@ bytes compileFirstExpression(
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
- TypeChecker typeChecker(errors);
+ ErrorReporter errorReporter(errors);
+ TypeChecker typeChecker(errorReporter);
BOOST_REQUIRE(typeChecker.checkTypeRequirements(*contract));
}
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 3a9f7295..d0aee3d0 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -30,7 +30,7 @@
#include <libsolidity/analysis/StaticAnalyzer.h>
#include <libsolidity/analysis/PostTypeChecker.h>
#include <libsolidity/analysis/SyntaxChecker.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/interface/ErrorReporter.h>
#include <libsolidity/analysis/GlobalContext.h>
#include <libsolidity/analysis/TypeChecker.h>
@@ -56,7 +56,8 @@ parseAnalyseAndReturnError(string const& _source, bool _reportWarnings = false,
// Silence compiler version warning
string source = _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source;
ErrorList errors;
- Parser parser(errors);
+ ErrorReporter errorReporter(errors);
+ Parser parser(errorReporter);
ASTPointer<SourceUnit> sourceUnit;
// catch exceptions for a transition period
try
@@ -65,14 +66,14 @@ parseAnalyseAndReturnError(string const& _source, bool _reportWarnings = false,
if(!sourceUnit)
BOOST_FAIL("Parsing failed in type checker test.");
- SyntaxChecker syntaxChecker(errors);
+ SyntaxChecker syntaxChecker(errorReporter);
if (!syntaxChecker.checkSyntax(*sourceUnit))
- return make_pair(sourceUnit, errors.at(0));
+ return make_pair(sourceUnit, errorReporter.errors().at(0));
std::shared_ptr<GlobalContext> globalContext = make_shared<GlobalContext>();
map<ASTNode const*, shared_ptr<DeclarationContainer>> scopes;
- NameAndTypeResolver resolver(globalContext->declarations(), scopes, errors);
- solAssert(Error::containsOnlyWarnings(errors), "");
+ NameAndTypeResolver resolver(globalContext->declarations(), scopes, errorReporter);
+ solAssert(Error::containsOnlyWarnings(errorReporter.errors()), "");
resolver.registerDeclarations(*sourceUnit);
bool success = true;
@@ -92,26 +93,32 @@ parseAnalyseAndReturnError(string const& _source, bool _reportWarnings = false,
globalContext->setCurrentContract(*contract);
resolver.updateDeclaration(*globalContext->currentThis());
- TypeChecker typeChecker(errors);
+ TypeChecker typeChecker(errorReporter);
bool success = typeChecker.checkTypeRequirements(*contract);
- BOOST_CHECK(success || !errors.empty());
+ BOOST_CHECK(success || !errorReporter.errors().empty());
}
if (success)
- if (!PostTypeChecker(errors).check(*sourceUnit))
+ if (!PostTypeChecker(errorReporter).check(*sourceUnit))
success = false;
if (success)
- if (!StaticAnalyzer(errors).analyze(*sourceUnit))
+ if (!StaticAnalyzer(errorReporter).analyze(*sourceUnit))
success = false;
- if (errors.size() > 1 && !_allowMultipleErrors)
- BOOST_FAIL("Multiple errors found");
- for (auto const& currentError: errors)
+ std::shared_ptr<Error const> error;
+ for (auto const& currentError: errorReporter.errors())
{
if (
(_reportWarnings && currentError->type() == Error::Type::Warning) ||
(!_reportWarnings && currentError->type() != Error::Type::Warning)
)
- return make_pair(sourceUnit, currentError);
+ {
+ if (error && !_allowMultipleErrors)
+ BOOST_FAIL("Multiple errors found");
+ if (!error)
+ error = currentError;
+ }
}
+ if (error)
+ return make_pair(sourceUnit, error);
}
catch (InternalCompilerError const& _e)
{
@@ -192,11 +199,16 @@ CHECK_ERROR_OR_WARNING(text, type, substring, false, false)
#define CHECK_ERROR_ALLOW_MULTI(text, type, substring) \
CHECK_ERROR_OR_WARNING(text, type, substring, false, true)
-// [checkWarning(text, type, substring)] asserts that the compilation down to typechecking
-// emits a warning of type [type] and with a message containing [substring].
+// [checkWarning(text, substring)] asserts that the compilation down to typechecking
+// emits a warning and with a message containing [substring].
#define CHECK_WARNING(text, substring) \
CHECK_ERROR_OR_WARNING(text, Warning, substring, true, false)
+// [checkWarningAllowMulti(text, substring)] aserts that the compilation down to typechecking
+// emits a warning and with a message containing [substring].
+#define CHECK_WARNING_ALLOW_MULTI(text, substring) \
+CHECK_ERROR_OR_WARNING(text, Warning, substring, true, true)
+
// [checkSuccess(text)] asserts that the compilation down to typechecking succeeds.
#define CHECK_SUCCESS(text) do { BOOST_CHECK(success((text))); } while(0)
@@ -548,6 +560,51 @@ BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
CHECK_SUCCESS(text);
}
+BOOST_AUTO_TEST_CASE(comparison_of_function_types)
+{
+ char const* text = R"(
+ contract C {
+ function f() returns (bool ret) {
+ return this.f < this.f;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Operator < not compatible");
+ text = R"(
+ contract C {
+ function f() returns (bool ret) {
+ return f < f;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Operator < not compatible");
+ text = R"(
+ contract C {
+ function f() returns (bool ret) {
+ return f == f;
+ }
+ function g() returns (bool ret) {
+ return f != f;
+ }
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
+BOOST_AUTO_TEST_CASE(comparison_of_mapping_types)
+{
+ char const* text = R"(
+ contract C {
+ mapping(uint => uint) x;
+ function f() returns (bool ret) {
+ var y = x;
+ return x == y;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Operator == not compatible");
+}
+
BOOST_AUTO_TEST_CASE(function_no_implementation)
{
ASTPointer<SourceUnit> sourceUnit;
@@ -1043,6 +1100,28 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
CHECK_SUCCESS(text);
}
+BOOST_AUTO_TEST_CASE(function_modifier_double_invocation)
+{
+ char const* text = R"(
+ contract B {
+ function f(uint x) mod(x) mod(2) { }
+ modifier mod(uint a) { if (a > 0) _; }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Modifier already used for this function");
+}
+
+BOOST_AUTO_TEST_CASE(base_constructor_double_invocation)
+{
+ char const* text = R"(
+ contract C { function C(uint a) {} }
+ contract B is C {
+ function B() C(2) C(2) {}
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Base constructor already provided");
+}
+
BOOST_AUTO_TEST_CASE(legal_modifier_override)
{
char const* text = R"(
@@ -1069,7 +1148,7 @@ BOOST_AUTO_TEST_CASE(modifier_overrides_function)
)";
// Error: Identifier already declared.
// Error: Override changes modifier to function.
- CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, "");
+ CHECK_ERROR_ALLOW_MULTI(text, DeclarationError, "Identifier already declared");
}
BOOST_AUTO_TEST_CASE(function_overrides_modifier)
@@ -1591,6 +1670,16 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter)
CHECK_SUCCESS(text);
}
+BOOST_AUTO_TEST_CASE(constant_input_parameter)
+{
+ char const* text = R"(
+ contract test {
+ function f(uint[] constant a) { }
+ }
+ )";
+ CHECK_ERROR_ALLOW_MULTI(text, TypeError, "Illegal use of \"constant\" specifier.");
+}
+
BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
{
char const* text = R"(
@@ -1698,6 +1787,46 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base)
CHECK_SUCCESS(sourceCode);
}
+
+BOOST_AUTO_TEST_CASE(warn_var_from_zero)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f() returns (uint) {
+ var i = 1;
+ return i;
+ }
+ }
+ )";
+ CHECK_WARNING(sourceCode, "uint8, which can hold values between 0 and 255");
+ sourceCode = R"(
+ contract test {
+ function f() {
+ var i = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
+ i;
+ }
+ }
+ )";
+ CHECK_WARNING(sourceCode, "uint256, which can hold values between 0 and 115792089237316195423570985008687907853269984665640564039457584007913129639935");
+ sourceCode = R"(
+ contract test {
+ function f() {
+ var i = -2;
+ i;
+ }
+ }
+ )";
+ CHECK_WARNING(sourceCode, "int8, which can hold values between -128 and 127");
+ sourceCode = R"(
+ contract test {
+ function f() {
+ for (var i = 0; i < msg.data.length; i++) { }
+ }
+ }
+ )";
+ CHECK_WARNING(sourceCode, "uint8, which can hold");
+}
+
BOOST_AUTO_TEST_CASE(enum_member_access)
{
char const* text = R"(
@@ -2167,6 +2296,36 @@ BOOST_AUTO_TEST_CASE(test_byte_is_alias_of_byte1)
ETH_TEST_REQUIRE_NO_THROW(parseAndAnalyse(text), "Type resolving failed");
}
+BOOST_AUTO_TEST_CASE(warns_assigning_decimal_to_bytesxx)
+{
+ char const* text = R"(
+ contract Foo {
+ bytes32 a = 7;
+ }
+ )";
+ CHECK_WARNING(text, "Decimal literal assigned to bytesXX variable will be left-aligned.");
+}
+
+BOOST_AUTO_TEST_CASE(does_not_warn_assigning_hex_number_to_bytesxx)
+{
+ char const* text = R"(
+ contract Foo {
+ bytes32 a = 0x1234;
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(explicit_conversion_from_decimal_to_bytesxx)
+{
+ char const* text = R"(
+ contract Foo {
+ bytes32 a = bytes32(7);
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(assigning_value_to_const_variable)
{
char const* text = R"(
@@ -2268,6 +2427,16 @@ BOOST_AUTO_TEST_CASE(constant_struct)
CHECK_ERROR(text, TypeError, "implemented");
}
+BOOST_AUTO_TEST_CASE(address_is_constant)
+{
+ char const* text = R"(
+ contract C {
+ address constant x = 0x1212121212121212121212121212121212121212;
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(uninitialized_const_variable)
{
char const* text = R"(
@@ -2416,6 +2585,16 @@ BOOST_AUTO_TEST_CASE(invalid_utf8_explicit)
CHECK_ERROR(sourceCode, TypeError, "Explicit type conversion not allowed");
}
+BOOST_AUTO_TEST_CASE(large_utf8_codepoint)
+{
+ char const* sourceCode = R"(
+ contract C {
+ string s = "\xf0\x9f\xa6\x84";
+ }
+ )";
+ CHECK_SUCCESS(sourceCode);
+}
+
BOOST_AUTO_TEST_CASE(string_index)
{
char const* sourceCode = R"(
@@ -2933,12 +3112,12 @@ BOOST_AUTO_TEST_CASE(non_initialized_references)
CHECK_WARNING(text, "Uninitialized storage pointer");
}
-BOOST_AUTO_TEST_CASE(sha3_with_large_integer_constant)
+BOOST_AUTO_TEST_CASE(keccak256_with_large_integer_constant)
{
char const* text = R"(
contract c
{
- function f() { sha3(2**500); }
+ function f() { keccak256(2**500); }
}
)";
CHECK_ERROR(text, TypeError, "");
@@ -3042,9 +3221,9 @@ BOOST_AUTO_TEST_CASE(tuples)
contract C {
function f() {
uint a = (1);
- var (b,) = (1,);
- var (c,d) = (1, 2 + a);
- var (e,) = (1, 2, b);
+ var (b,) = (uint8(1),);
+ var (c,d) = (uint32(1), 2 + a);
+ var (e,) = (uint64(1), 2, b);
a;b;c;d;e;
}
}
@@ -3682,12 +3861,12 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
byte[2] memory a;
byte[2] memory b;
var k = true ? a : b;
- k[0] = 0; //Avoid unused var warning
+ k[0] = byte(0); //Avoid unused var warning
bytes memory e;
bytes memory f;
var l = true ? e : f;
- l[0] = 0; // Avoid unused var warning
+ l[0] = byte(0); // Avoid unused var warning
// fixed bytes
bytes2 c;
@@ -4500,7 +4679,7 @@ BOOST_AUTO_TEST_CASE(unused_return_value_callcode)
}
}
)";
- CHECK_WARNING(text, "Return value of low-level calls not used");
+ CHECK_WARNING_ALLOW_MULTI(text, "Return value of low-level calls not used");
}
BOOST_AUTO_TEST_CASE(unused_return_value_delegatecall)
@@ -4515,6 +4694,31 @@ BOOST_AUTO_TEST_CASE(unused_return_value_delegatecall)
CHECK_WARNING(text, "Return value of low-level calls not used");
}
+BOOST_AUTO_TEST_CASE(warn_about_callcode)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ var x = address(0x12).callcode;
+ x;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "\"callcode\" has been deprecated in favour");
+}
+
+BOOST_AUTO_TEST_CASE(no_warn_about_callcode_as_local)
+{
+ char const* text = R"(
+ contract test {
+ function callcode() {
+ var x = this.callcode;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(modifier_without_underscore)
{
char const* text = R"(
@@ -4996,6 +5200,26 @@ BOOST_AUTO_TEST_CASE(external_function_type_to_uint)
CHECK_ERROR(text, TypeError, "Explicit type conversion not allowed");
}
+BOOST_AUTO_TEST_CASE(warn_function_type_parameters_with_names)
+{
+ char const* text = R"(
+ contract C {
+ function(uint a) f;
+ }
+ )";
+ CHECK_WARNING(text, "Naming function type parameters is deprecated.");
+}
+
+BOOST_AUTO_TEST_CASE(warn_function_type_return_parameters_with_names)
+{
+ char const* text = R"(
+ contract C {
+ function(uint) returns(bool ret) f;
+ }
+ )";
+ CHECK_WARNING(text, "Naming function type return parameters is deprecated.");
+}
+
BOOST_AUTO_TEST_CASE(shift_constant_left_negative_rvalue)
{
char const* text = R"(
@@ -5158,6 +5382,52 @@ BOOST_AUTO_TEST_CASE(inline_assembly_constant_access)
CHECK_ERROR(text, TypeError, "Constant variables not supported by inline assembly");
}
+BOOST_AUTO_TEST_CASE(inline_assembly_local_variable_access_out_of_functions)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ uint a;
+ assembly {
+ function g() -> x { x := a }
+ }
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Cannot access local Solidity variables from inside an inline assembly function.");
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_local_variable_access_out_of_functions_storage_ptr)
+{
+ char const* text = R"(
+ contract test {
+ uint[] r;
+ function f() {
+ uint[] storage a = r;
+ assembly {
+ function g() -> x { x := a_offset }
+ }
+ }
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Cannot access local Solidity variables from inside an inline assembly function.");
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_storage_variable_access_out_of_functions)
+{
+ char const* text = R"(
+ contract test {
+ uint a;
+ function f() {
+ assembly {
+ function g() -> x { x := a_slot }
+ }
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(invalid_mobile_type)
{
char const* text = R"(
@@ -5319,7 +5589,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_checksum)
char const* text = R"(
contract C {
function f() {
- var x = 0xFA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
+ address x = 0xFA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
x;
}
}
@@ -5332,7 +5602,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_no_checksum)
char const* text = R"(
contract C {
function f() {
- var x = 0xfa0bfc97e48458494ccd857e1a85dc91f7f0046e;
+ address x = 0xfa0bfc97e48458494ccd857e1a85dc91f7f0046e;
x;
}
}
@@ -5345,7 +5615,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_length)
char const* text = R"(
contract C {
function f() {
- var x = 0xA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
+ address x = 0xA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
x;
}
}
@@ -5353,6 +5623,25 @@ BOOST_AUTO_TEST_CASE(invalid_address_length)
CHECK_WARNING(text, "checksum");
}
+BOOST_AUTO_TEST_CASE(address_test_for_bug_in_implementation)
+{
+ // A previous implementation claimed the string would be an address
+ char const* text = R"(
+ contract AddrString {
+ address public test = "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c";
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "is not implicitly convertible to expected type address");
+ text = R"(
+ contract AddrString {
+ function f() returns (address) {
+ return "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c";
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "is not implicitly convertible to expected type");
+}
+
BOOST_AUTO_TEST_CASE(early_exit_on_fatal_errors)
{
// This tests a crash that occured because we did not stop for fatal errors.
@@ -5400,7 +5689,7 @@ BOOST_AUTO_TEST_CASE(cyclic_dependency_for_constants)
contract C {
uint constant a = b * c;
uint constant b = 7;
- uint constant c = b + uint(sha3(d));
+ uint constant c = b + uint(keccak256(d));
uint constant d = 2 + a;
}
)";
@@ -5409,7 +5698,7 @@ BOOST_AUTO_TEST_CASE(cyclic_dependency_for_constants)
contract C {
uint constant a = b * c;
uint constant b = 7;
- uint constant c = 4 + uint(sha3(d));
+ uint constant c = 4 + uint(keccak256(d));
uint constant d = 2 + b;
}
)";
@@ -5520,6 +5809,16 @@ BOOST_AUTO_TEST_CASE(interface_variables)
CHECK_ERROR(text, TypeError, "Variables cannot be declared in interfaces");
}
+BOOST_AUTO_TEST_CASE(interface_function_parameters)
+{
+ char const* text = R"(
+ interface I {
+ function f(uint a) returns(bool);
+ }
+ )";
+ success(text);
+}
+
BOOST_AUTO_TEST_CASE(interface_enums)
{
char const* text = R"(
@@ -5608,6 +5907,80 @@ BOOST_AUTO_TEST_CASE(pure_statement_check_for_regular_for_loop)
success(text);
}
+BOOST_AUTO_TEST_CASE(warn_multiple_storage_storage_copies)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; uint b; }
+ S x; S y;
+ function f() {
+ (x, y) = (y, x);
+ }
+ }
+ )";
+ CHECK_WARNING(text, "This assignment performs two copies to storage.");
+}
+
+BOOST_AUTO_TEST_CASE(warn_multiple_storage_storage_copies_fill_right)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; uint b; }
+ S x; S y;
+ function f() {
+ (x, y, ) = (y, x, 1, 2);
+ }
+ }
+ )";
+ CHECK_WARNING(text, "This assignment performs two copies to storage.");
+}
+
+BOOST_AUTO_TEST_CASE(warn_multiple_storage_storage_copies_fill_left)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; uint b; }
+ S x; S y;
+ function f() {
+ (,x, y) = (1, 2, y, x);
+ }
+ }
+ )";
+ CHECK_WARNING(text, "This assignment performs two copies to storage.");
+}
+
+BOOST_AUTO_TEST_CASE(nowarn_swap_memory)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; uint b; }
+ function f() {
+ S memory x;
+ S memory y;
+ (x, y) = (y, x);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(nowarn_swap_storage_pointers)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; uint b; }
+ S x; S y;
+ function f() {
+ S storage x_local = x;
+ S storage y_local = y;
+ S storage z_local = x;
+ (x, y_local, x_local, z_local) = (y, x_local, y_local, y);
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(warn_unused_local)
{
char const* text = R"(
@@ -5625,7 +5998,7 @@ BOOST_AUTO_TEST_CASE(warn_unused_local_assigned)
char const* text = R"(
contract C {
function f() {
- var a = 1;
+ uint a = 1;
}
}
)";
@@ -5718,7 +6091,58 @@ BOOST_AUTO_TEST_CASE(no_unused_dec_after_use)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(no_unused_inline_asm)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ uint a;
+ assembly {
+ a := 1
+ }
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(callable_crash)
+{
+ char const* text = R"(
+ contract C {
+ struct S { uint a; bool x; }
+ S public s;
+ function C() {
+ 3({a: 1, x: true});
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Type is not callable");
+}
+
+BOOST_AUTO_TEST_CASE(returndatacopy_as_variable)
+{
+ char const* text = R"(
+ contract c { function f() { uint returndatasize; assembly { returndatasize }}}
+ )";
+ CHECK_WARNING_ALLOW_MULTI(text, "Variable is shadowed in inline assembly by an instruction of the same name");
+}
+
+BOOST_AUTO_TEST_CASE(create2_as_variable)
+{
+ char const* text = R"(
+ contract c { function f() { uint create2; assembly { create2(0, 0, 0, 0) }}}
+ )";
+ CHECK_WARNING_ALLOW_MULTI(text, "Variable is shadowed in inline assembly by an instruction of the same name");
+}
+BOOST_AUTO_TEST_CASE(shadowing_warning_can_be_removed)
+{
+ char const* text = R"(
+ contract C {function f() {assembly {}}}
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp
index 78c1a0ee..2a7376b9 100644
--- a/test/libsolidity/SolidityNatspecJSON.cpp
+++ b/test/libsolidity/SolidityNatspecJSON.cpp
@@ -49,9 +49,9 @@ public:
Json::Value generatedDocumentation;
if (_userDocumentation)
- generatedDocumentation = m_compilerStack.metadata("", DocumentationType::NatspecUser);
+ generatedDocumentation = m_compilerStack.natspec("", DocumentationType::NatspecUser);
else
- generatedDocumentation = m_compilerStack.metadata("", DocumentationType::NatspecDev);
+ generatedDocumentation = m_compilerStack.natspec("", DocumentationType::NatspecDev);
Json::Value expectedDocumentation;
m_reader.parse(_expectedDocumentationString, expectedDocumentation);
BOOST_CHECK_MESSAGE(
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index d705e3c8..a4d80c99 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -322,18 +322,18 @@ BOOST_AUTO_TEST_CASE(storage_write_in_loops)
// Information in joining branches is not retained anymore.
BOOST_AUTO_TEST_CASE(retain_information_in_branches)
{
- // This tests that the optimizer knows that we already have "z == sha3(y)" inside both branches.
+ // This tests that the optimizer knows that we already have "z == keccak256(y)" inside both branches.
char const* sourceCode = R"(
contract c {
bytes32 d;
uint a;
function f(uint x, bytes32 y) returns (uint r_a, bytes32 r_d) {
- bytes32 z = sha3(y);
+ bytes32 z = keccak256(y);
if (x > 8) {
- z = sha3(y);
+ z = keccak256(y);
a = x;
} else {
- z = sha3(y);
+ z = keccak256(y);
a = x;
}
r_a = a;
@@ -349,7 +349,7 @@ BOOST_AUTO_TEST_CASE(retain_information_in_branches)
bytes optimizedBytecode = compileAndRunWithOptimizer(sourceCode, 0, "c", true);
size_t numSHA3s = 0;
eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) {
- if (_instr == Instruction::SHA3)
+ if (_instr == Instruction::KECCAK256)
numSHA3s++;
});
// TEST DISABLED - OPTIMIZER IS NOT EFFECTIVE ON THIS ONE ANYMORE
@@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(retain_information_in_branches)
BOOST_AUTO_TEST_CASE(store_tags_as_unions)
{
- // This calls the same function from two sources and both calls have a certain sha3 on
+ // This calls the same function from two sources and both calls have a certain Keccak-256 on
// the stack at the same position.
// Without storing tags as unions, the return from the shared function would not know where to
// jump and thus all jumpdests are forced to clear their state and we do not know about the
@@ -370,19 +370,19 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions)
contract test {
bytes32 data;
function f(uint x, bytes32 y) external returns (uint r_a, bytes32 r_d) {
- r_d = sha3(y);
+ r_d = keccak256(y);
shared(y);
- r_d = sha3(y);
+ r_d = keccak256(y);
r_a = 5;
}
function g(uint x, bytes32 y) external returns (uint r_a, bytes32 r_d) {
- r_d = sha3(y);
+ r_d = keccak256(y);
shared(y);
- r_d = bytes32(uint(sha3(y)) + 2);
+ r_d = bytes32(uint(keccak256(y)) + 2);
r_a = 7;
}
function shared(bytes32 y) internal {
- data = sha3(y);
+ data = keccak256(y);
}
}
)";
@@ -392,7 +392,7 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions)
bytes optimizedBytecode = compileAndRunWithOptimizer(sourceCode, 0, "test", true);
size_t numSHA3s = 0;
eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) {
- if (_instr == Instruction::SHA3)
+ if (_instr == Instruction::KECCAK256)
numSHA3s++;
});
// TEST DISABLED UNTIL 93693404 IS IMPLEMENTED
@@ -401,8 +401,8 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions)
BOOST_AUTO_TEST_CASE(incorrect_storage_access_bug)
{
- // This bug appeared because a sha3 operation with too low sequence number was used,
- // resulting in memory not being rewritten before the sha3. The fix was to
+ // This bug appeared because a Keccak-256 operation with too low sequence number was used,
+ // resulting in memory not being rewritten before the Keccak-256. The fix was to
// take the max of the min sequence numbers when merging the states.
char const* sourceCode = R"(
contract C
@@ -697,59 +697,6 @@ BOOST_AUTO_TEST_CASE(cse_interleaved_storage_at_known_location_offset)
});
}
-BOOST_AUTO_TEST_CASE(cse_interleaved_memory_at_known_location_offset)
-{
- // stores and reads to/from two locations which are known to be different,
- // should not optimize away the first store, because the location overlaps with the load,
- // but it should optimize away the second, because we know that the location is different by 32
- AssemblyItems input{
- u256(0x50),
- Instruction::DUP2,
- u256(2),
- Instruction::ADD,
- Instruction::MSTORE, // ["DUP1"+2] = 0x50
- u256(0x60),
- Instruction::DUP2,
- u256(32),
- Instruction::ADD,
- Instruction::MSTORE, // ["DUP1"+32] = 0x60
- Instruction::DUP1,
- Instruction::MLOAD, // read from "DUP1"
- u256(0x70),
- Instruction::DUP3,
- u256(32),
- Instruction::ADD,
- Instruction::MSTORE, // ["DUP1"+32] = 0x70
- u256(0x80),
- Instruction::DUP3,
- u256(2),
- Instruction::ADD,
- Instruction::MSTORE, // ["DUP1"+2] = 0x80
- };
- // If the actual code changes too much, we could also simply check that the output contains
- // exactly 3 MSTORE and exactly 1 MLOAD instruction.
- checkCSE(input, {
- u256(0x50),
- u256(2),
- Instruction::DUP3,
- Instruction::ADD,
- Instruction::SWAP1,
- Instruction::DUP2,
- Instruction::MSTORE, // ["DUP1"+2] = 0x50
- Instruction::DUP2,
- Instruction::MLOAD, // read from "DUP1"
- u256(0x70),
- u256(32),
- Instruction::DUP5,
- Instruction::ADD,
- Instruction::MSTORE, // ["DUP1"+32] = 0x70
- u256(0x80),
- Instruction::SWAP1,
- Instruction::SWAP2,
- Instruction::MSTORE // ["DUP1"+2] = 0x80
- });
-}
-
BOOST_AUTO_TEST_CASE(cse_deep_stack)
{
AssemblyItems input{
@@ -821,19 +768,19 @@ BOOST_AUTO_TEST_CASE(cse_jumpi_jump)
});
}
-BOOST_AUTO_TEST_CASE(cse_empty_sha3)
+BOOST_AUTO_TEST_CASE(cse_empty_keccak256)
{
AssemblyItems input{
u256(0),
Instruction::DUP2,
- Instruction::SHA3
+ Instruction::KECCAK256
};
checkCSE(input, {
u256(dev::keccak256(bytesConstRef()))
});
}
-BOOST_AUTO_TEST_CASE(cse_partial_sha3)
+BOOST_AUTO_TEST_CASE(cse_partial_keccak256)
{
AssemblyItems input{
u256(0xabcd) << (256 - 16),
@@ -841,7 +788,7 @@ BOOST_AUTO_TEST_CASE(cse_partial_sha3)
Instruction::MSTORE,
u256(2),
u256(0),
- Instruction::SHA3
+ Instruction::KECCAK256
};
checkCSE(input, {
u256(0xabcd) << (256 - 16),
@@ -851,19 +798,19 @@ BOOST_AUTO_TEST_CASE(cse_partial_sha3)
});
}
-BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_location)
+BOOST_AUTO_TEST_CASE(cse_keccak256_twice_same_location)
{
- // sha3 twice from same dynamic location
+ // Keccak-256 twice from same dynamic location
AssemblyItems input{
Instruction::DUP2,
Instruction::DUP1,
Instruction::MSTORE,
u256(64),
Instruction::DUP2,
- Instruction::SHA3,
+ Instruction::KECCAK256,
u256(64),
Instruction::DUP3,
- Instruction::SHA3
+ Instruction::KECCAK256
};
checkCSE(input, {
Instruction::DUP2,
@@ -871,27 +818,27 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_location)
Instruction::MSTORE,
u256(64),
Instruction::DUP2,
- Instruction::SHA3,
+ Instruction::KECCAK256,
Instruction::DUP1
});
}
-BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content)
+BOOST_AUTO_TEST_CASE(cse_keccak256_twice_same_content)
{
- // sha3 twice from different dynamic location but with same content
+ // Keccak-256 twice from different dynamic location but with same content
AssemblyItems input{
Instruction::DUP1,
u256(0x80),
Instruction::MSTORE, // m[128] = DUP1
u256(0x20),
u256(0x80),
- Instruction::SHA3, // sha3(m[128..(128+32)])
+ Instruction::KECCAK256, // keccak256(m[128..(128+32)])
Instruction::DUP2,
u256(12),
Instruction::MSTORE, // m[12] = DUP1
u256(0x20),
u256(12),
- Instruction::SHA3 // sha3(m[12..(12+32)])
+ Instruction::KECCAK256 // keccak256(m[12..(12+32)])
};
checkCSE(input, {
u256(0x80),
@@ -900,7 +847,7 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content)
Instruction::MSTORE,
u256(0x20),
Instruction::SWAP1,
- Instruction::SHA3,
+ Instruction::KECCAK256,
u256(12),
Instruction::DUP3,
Instruction::SWAP1,
@@ -909,10 +856,10 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content)
});
}
-BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_dynamic_store_in_between)
+BOOST_AUTO_TEST_CASE(cse_keccak256_twice_same_content_dynamic_store_in_between)
{
- // sha3 twice from different dynamic location but with same content,
- // dynamic mstore in between, which forces us to re-calculate the sha3
+ // Keccak-256 twice from different dynamic location but with same content,
+ // dynamic mstore in between, which forces us to re-calculate the hash
AssemblyItems input{
u256(0x80),
Instruction::DUP2,
@@ -921,7 +868,7 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_dynamic_store_in_between)
u256(0x20),
Instruction::DUP1,
Instruction::DUP3,
- Instruction::SHA3, // sha3(m[128..(128+32)])
+ Instruction::KECCAK256, // keccak256(m[128..(128+32)])
u256(12),
Instruction::DUP5,
Instruction::DUP2,
@@ -932,15 +879,15 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_dynamic_store_in_between)
Instruction::SWAP2,
Instruction::SWAP1,
Instruction::SWAP2,
- Instruction::SHA3 // sha3(m[12..(12+32)])
+ Instruction::KECCAK256 // keccak256(m[12..(12+32)])
};
checkCSE(input, input);
}
-BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_noninterfering_store_in_between)
+BOOST_AUTO_TEST_CASE(cse_keccak256_twice_same_content_noninterfering_store_in_between)
{
- // sha3 twice from different dynamic location but with same content,
- // dynamic mstore in between, but does not force us to re-calculate the sha3
+ // Keccak-256 twice from different dynamic location but with same content,
+ // dynamic mstore in between, but does not force us to re-calculate the hash
AssemblyItems input{
u256(0x80),
Instruction::DUP2,
@@ -949,7 +896,7 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_noninterfering_store_in_between
u256(0x20),
Instruction::DUP1,
Instruction::DUP3,
- Instruction::SHA3, // sha3(m[128..(128+32)])
+ Instruction::KECCAK256, // keccak256(m[128..(128+32)])
u256(12),
Instruction::DUP5,
Instruction::DUP2,
@@ -962,12 +909,12 @@ BOOST_AUTO_TEST_CASE(cse_sha3_twice_same_content_noninterfering_store_in_between
Instruction::MSTORE, // does not destoy memory knowledge
u256(0x20),
u256(12),
- Instruction::SHA3 // sha3(m[12..(12+32)])
+ Instruction::KECCAK256 // keccak256(m[12..(12+32)])
};
// if this changes too often, only count the number of SHA3 and MSTORE instructions
AssemblyItems output = CSE(input);
BOOST_CHECK_EQUAL(4, count(output.begin(), output.end(), AssemblyItem(Instruction::MSTORE)));
- BOOST_CHECK_EQUAL(1, count(output.begin(), output.end(), AssemblyItem(Instruction::SHA3)));
+ BOOST_CHECK_EQUAL(1, count(output.begin(), output.end(), AssemblyItem(Instruction::KECCAK256)));
}
BOOST_AUTO_TEST_CASE(cse_with_initially_known_stack)
@@ -1189,6 +1136,32 @@ BOOST_AUTO_TEST_CASE(clear_unreachable_code)
);
}
+BOOST_AUTO_TEST_CASE(peephole_double_push)
+{
+ AssemblyItems items{
+ u256(0),
+ u256(0),
+ u256(5),
+ u256(5),
+ u256(4),
+ u256(5)
+ };
+ AssemblyItems expectation{
+ u256(0),
+ Instruction::DUP1,
+ u256(5),
+ Instruction::DUP1,
+ u256(4),
+ u256(5)
+ };
+ PeepholeOptimiser peepOpt(items);
+ BOOST_REQUIRE(peepOpt.optimise());
+ BOOST_CHECK_EQUAL_COLLECTIONS(
+ items.begin(), items.end(),
+ expectation.begin(), expectation.end()
+ );
+}
+
BOOST_AUTO_TEST_CASE(computing_constants)
{
char const* sourceCode = R"(
@@ -1296,7 +1269,7 @@ BOOST_AUTO_TEST_CASE(constant_optimization_early_exit)
// Store and hash
assembly {
mstore(32, x)
- ret := sha3(0, 40)
+ ret := keccak256(0, 40)
}
}
}
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index 6e33aba5..78edd4d1 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -24,7 +24,7 @@
#include <memory>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Parser.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/interface/ErrorReporter.h>
#include "../TestHelper.h"
#include "ErrorCheck.h"
@@ -41,7 +41,8 @@ namespace
{
ASTPointer<ContractDefinition> parseText(std::string const& _source, ErrorList& _errors)
{
- ASTPointer<SourceUnit> sourceUnit = Parser(_errors).parse(std::make_shared<Scanner>(CharStream(_source)));
+ ErrorReporter errorReporter(_errors);
+ ASTPointer<SourceUnit> sourceUnit = Parser(errorReporter).parse(std::make_shared<Scanner>(CharStream(_source)));
if (!sourceUnit)
return ASTPointer<ContractDefinition>();
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
@@ -198,6 +199,17 @@ BOOST_AUTO_TEST_CASE(missing_argument_in_named_args)
CHECK_PARSE_ERROR(text, "Expected primary expression");
}
+BOOST_AUTO_TEST_CASE(trailing_comma_in_named_args)
+{
+ char const* text = R"(
+ contract test {
+ function a(uint a, uint b, uint c) returns (uint r) { r = a * 100 + b * 10 + c * 1; }
+ function b() returns (uint r) { r = a({a: 1, b: 2, c: 3, }); }
+ }
+ )";
+ CHECK_PARSE_ERROR(text, "Unexpected trailing comma");
+}
+
BOOST_AUTO_TEST_CASE(two_exact_functions)
{
char const* text = R"(
@@ -889,6 +901,24 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
CHECK_PARSE_ERROR(text, "Visibility already specified");
}
+BOOST_AUTO_TEST_CASE(multiple_payable_specifiers)
+{
+ char const* text = R"(
+ contract c {
+ function f() payable payable {}
+ })";
+ CHECK_PARSE_ERROR(text, "Multiple \"payable\" specifiers.");
+}
+
+BOOST_AUTO_TEST_CASE(multiple_constant_specifiers)
+{
+ char const* text = R"(
+ contract c {
+ function f() constant constant {}
+ })";
+ CHECK_PARSE_ERROR(text, "Multiple \"constant\" specifiers.");
+}
+
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
{
char const* text = R"(
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index ffb0e2c6..be13d46b 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -26,6 +26,7 @@
#include <libsolidity/interface/StandardCompiler.h>
#include <libdevcore/JSON.h>
+#include "../Metadata.h"
using namespace std;
using namespace dev::eth;
@@ -68,60 +69,12 @@ bool containsAtMostWarnings(Json::Value const& _compilerResult)
BOOST_REQUIRE(error.isObject());
BOOST_REQUIRE(error["severity"].isString());
if (error["severity"].asString() != "warning")
- {
- cout << error << std::endl;
return false;
- }
}
return true;
}
-string bytecodeSansMetadata(string const& _bytecode)
-{
- /// The metadata hash takes up 43 bytes (or 86 characters in hex)
- /// /a165627a7a72305820([0-9a-f]{64})0029$/
-
- if (_bytecode.size() < 88)
- return _bytecode;
-
- if (_bytecode.substr(_bytecode.size() - 4, 4) != "0029")
- return _bytecode;
-
- if (_bytecode.substr(_bytecode.size() - 86, 18) != "a165627a7a72305820")
- return _bytecode;
-
- return _bytecode.substr(0, _bytecode.size() - 86);
-}
-
-bool isValidMetadata(string const& _metadata)
-{
- Json::Value metadata;
- if (!Json::Reader().parse(_metadata, metadata, false))
- return false;
-
- if (
- !metadata.isObject() ||
- !metadata.isMember("version") ||
- !metadata.isMember("language") ||
- !metadata.isMember("compiler") ||
- !metadata.isMember("settings") ||
- !metadata.isMember("sources") ||
- !metadata.isMember("output")
- )
- return false;
-
- if (!metadata["version"].isNumeric() || metadata["version"] != 1)
- return false;
-
- if (!metadata["language"].isString() || metadata["language"].asString() != "Solidity")
- return false;
-
- /// @TODO add more strict checks
-
- return true;
-}
-
Json::Value getContractResult(Json::Value const& _compilerResult, string const& _file, string const& _name)
{
if (
@@ -236,34 +189,43 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
Json::Value contract = getContractResult(result, "fileA", "A");
BOOST_CHECK(contract.isObject());
BOOST_CHECK(contract["abi"].isArray());
- BOOST_CHECK(dev::jsonCompactPrint(contract["abi"]) == "[]");
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
BOOST_CHECK(contract["devdoc"].isObject());
- BOOST_CHECK(dev::jsonCompactPrint(contract["devdoc"]) == "{\"methods\":{}}");
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["devdoc"]), "{\"methods\":{}}");
BOOST_CHECK(contract["userdoc"].isObject());
- BOOST_CHECK(dev::jsonCompactPrint(contract["userdoc"]) == "{\"methods\":{}}");
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["userdoc"]), "{\"methods\":{}}");
BOOST_CHECK(contract["evm"].isObject());
/// @TODO check evm.methodIdentifiers, legacyAssembly, bytecode, deployedBytecode
BOOST_CHECK(contract["evm"]["bytecode"].isObject());
BOOST_CHECK(contract["evm"]["bytecode"]["object"].isString());
- BOOST_CHECK(bytecodeSansMetadata(contract["evm"]["bytecode"]["object"].asString()) ==
- "60606040523415600b57fe5b5b60338060196000396000f30060606040525bfe00");
+ BOOST_CHECK_EQUAL(
+ dev::test::bytecodeSansMetadata(contract["evm"]["bytecode"]["object"].asString()),
+ "60606040523415600e57600080fd5b5b603680601c6000396000f30060606040525b600080fd00"
+ );
BOOST_CHECK(contract["evm"]["assembly"].isString());
- BOOST_CHECK(contract["evm"]["assembly"].asString() ==
+ BOOST_CHECK(contract["evm"]["assembly"].asString().find(
" /* \"fileA\":0:14 contract A { } */\n mstore(0x40, 0x60)\n jumpi(tag_1, iszero(callvalue))\n"
- " invalid\ntag_1:\ntag_2:\n dataSize(sub_0)\n dup1\n dataOffset(sub_0)\n 0x0\n codecopy\n 0x0\n"
+ " 0x0\n dup1\n revert\ntag_1:\ntag_2:\n dataSize(sub_0)\n dup1\n dataOffset(sub_0)\n 0x0\n codecopy\n 0x0\n"
" return\nstop\n\nsub_0: assembly {\n /* \"fileA\":0:14 contract A { } */\n"
- " mstore(0x40, 0x60)\n tag_1:\n invalid\n}\n");
+ " mstore(0x40, 0x60)\n tag_1:\n 0x0\n dup1\n revert\n\n"
+ " auxdata: 0xa165627a7a7230582") == 0);
BOOST_CHECK(contract["evm"]["gasEstimates"].isObject());
- BOOST_CHECK(dev::jsonCompactPrint(contract["evm"]["gasEstimates"]) ==
- "{\"creation\":{\"codeDepositCost\":\"10200\",\"executionCost\":\"62\",\"totalCost\":\"10262\"}}");
+ BOOST_CHECK_EQUAL(
+ dev::jsonCompactPrint(contract["evm"]["gasEstimates"]),
+ "{\"creation\":{\"codeDepositCost\":\"10800\",\"executionCost\":\"62\",\"totalCost\":\"10862\"}}"
+ );
BOOST_CHECK(contract["metadata"].isString());
- BOOST_CHECK(isValidMetadata(contract["metadata"].asString()));
+ BOOST_CHECK(dev::test::isValidMetadata(contract["metadata"].asString()));
BOOST_CHECK(result["sources"].isObject());
BOOST_CHECK(result["sources"]["fileA"].isObject());
BOOST_CHECK(result["sources"]["fileA"]["legacyAST"].isObject());
- BOOST_CHECK(dev::jsonCompactPrint(result["sources"]["fileA"]["legacyAST"]) ==
- "{\"children\":[{\"attributes\":{\"fullyImplemented\":true,\"isLibrary\":false,\"linearizedBaseContracts\":[1],"
- "\"name\":\"A\"},\"children\":[],\"id\":1,\"name\":\"ContractDefinition\",\"src\":\"0:14:0\"}],\"name\":\"SourceUnit\"}");
+ BOOST_CHECK_EQUAL(
+ dev::jsonCompactPrint(result["sources"]["fileA"]["legacyAST"]),
+ "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]}},\"children\":"
+ "[{\"attributes\":{\"baseContracts\":[null],\"contractDependencies\":[null],\"contractKind\":\"contract\","
+ "\"documentation\":null,\"fullyImplemented\":true,\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nodes\":[null],\"scope\":2},"
+ "\"id\":1,\"name\":\"ContractDefinition\",\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}"
+ );
}
BOOST_AUTO_TEST_SUITE_END()