Skip to content

Commit 7181147

Browse files
chrisethaxic
authored andcommitted
Tests.
1 parent 207b113 commit 7181147

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

test/libyul/YulObjectParser.cpp

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
/**
18+
* @date 2018
19+
* Unit tests for the Yul object parser.
20+
*/
21+
22+
#include <test/Options.h>
23+
24+
#include <test/libsolidity/ErrorCheck.h>
25+
26+
#include <libsolidity/interface/AssemblyStack.h>
27+
28+
#include <boost/optional.hpp>
29+
#include <boost/algorithm/string/replace.hpp>
30+
31+
#include <string>
32+
#include <memory>
33+
34+
using namespace std;
35+
using namespace dev::solidity;
36+
37+
namespace dev
38+
{
39+
namespace yul
40+
{
41+
namespace test
42+
{
43+
44+
namespace
45+
{
46+
47+
std::pair<bool, ErrorList> parse(string const& _source)
48+
{
49+
try
50+
{
51+
solidity::AssemblyStack asmStack(
52+
dev::test::Options::get().evmVersion(),
53+
solidity::AssemblyStack::Language::StrictAssembly
54+
);
55+
bool success = asmStack.parseAndAnalyze("source", _source);
56+
return {success, asmStack.errors()};
57+
}
58+
catch (FatalError const&)
59+
{
60+
BOOST_FAIL("Fatal error leaked.");
61+
}
62+
return {false, {}};
63+
}
64+
65+
boost::optional<Error> parseAndReturnFirstError(string const& _source, bool _allowWarnings = true)
66+
{
67+
bool success;
68+
ErrorList errors;
69+
tie(success, errors) = parse(_source);
70+
if (!success)
71+
{
72+
BOOST_REQUIRE_EQUAL(errors.size(), 1);
73+
return *errors.front();
74+
}
75+
else
76+
{
77+
// If success is true, there might still be an error in the assembly stage.
78+
if (_allowWarnings && Error::containsOnlyWarnings(errors))
79+
return {};
80+
else if (!errors.empty())
81+
{
82+
if (!_allowWarnings)
83+
BOOST_CHECK_EQUAL(errors.size(), 1);
84+
return *errors.front();
85+
}
86+
}
87+
return {};
88+
}
89+
90+
bool successParse(std::string const& _source, bool _allowWarnings = true)
91+
{
92+
return !parseAndReturnFirstError(_source, _allowWarnings);
93+
}
94+
95+
Error expectError(std::string const& _source, bool _allowWarnings = false)
96+
{
97+
98+
auto error = parseAndReturnFirstError(_source, _allowWarnings);
99+
BOOST_REQUIRE(error);
100+
return *error;
101+
}
102+
103+
}
104+
105+
#define CHECK_ERROR(text, typ, substring) \
106+
do \
107+
{ \
108+
Error err = expectError((text), false); \
109+
BOOST_CHECK(err.type() == (Error::Type::typ)); \
110+
BOOST_CHECK(searchErrorMessage(err, (substring))); \
111+
} while(0)
112+
113+
BOOST_AUTO_TEST_SUITE(YulObjectParser)
114+
115+
BOOST_AUTO_TEST_CASE(empty_code)
116+
{
117+
BOOST_CHECK(successParse("{ }"));
118+
}
119+
120+
BOOST_AUTO_TEST_CASE(object_with_empty_code)
121+
{
122+
BOOST_CHECK(successParse("object \"a\" { code { } }"));
123+
}
124+
125+
BOOST_AUTO_TEST_CASE(non_object)
126+
{
127+
CHECK_ERROR("code {}", ParserError, "Expected keyword \"object\"");
128+
}
129+
130+
BOOST_AUTO_TEST_CASE(empty_name)
131+
{
132+
CHECK_ERROR("object \"\" { code {} }", ParserError, "Object name cannot be empty");
133+
}
134+
135+
BOOST_AUTO_TEST_CASE(recursion_depth)
136+
{
137+
string input;
138+
for (size_t i = 0; i < 20000; i++)
139+
input += "object \"a" + to_string(i) + "\" { code {} ";
140+
for (size_t i = 0; i < 20000; i++)
141+
input += "}";
142+
143+
CHECK_ERROR(input, ParserError, "recursion");
144+
}
145+
146+
BOOST_AUTO_TEST_CASE(object_with_code)
147+
{
148+
BOOST_CHECK(successParse("object \"a\" { code { let x := mload(0) sstore(0, x) } }"));
149+
}
150+
151+
BOOST_AUTO_TEST_CASE(object_with_code_and_data)
152+
{
153+
BOOST_CHECK(successParse("object \"a\" { code { let x := mload(0) sstore(0, x) } data \"b\" hex\"01010202\" }"));
154+
}
155+
156+
BOOST_AUTO_TEST_CASE(object_with_non_code_at_start)
157+
{
158+
CHECK_ERROR("object \"a\" { data \"d\" hex\"0102\" code { } }", ParserError, "Expected keyword \"code\"");
159+
}
160+
161+
BOOST_AUTO_TEST_CASE(nested_object)
162+
{
163+
string code = R"(
164+
object "outer" {
165+
code { let x := mload(0) }
166+
data "x" "stringdata"
167+
object "inner" {
168+
code { mstore(0, 1) }
169+
object "inner inner" { code {} }
170+
data "innerx" "abc"
171+
data "innery" "def"
172+
}
173+
}
174+
)";
175+
BOOST_CHECK(successParse(code));
176+
}
177+
178+
BOOST_AUTO_TEST_CASE(incomplete)
179+
{
180+
CHECK_ERROR("object \"abc\" { code {} } object", ParserError, "Expected end of source");
181+
}
182+
183+
BOOST_AUTO_TEST_CASE(reuse_object_name)
184+
{
185+
string code = R"(
186+
object "outer" {
187+
code { }
188+
data "outer" "stringdata"
189+
}
190+
)";
191+
CHECK_ERROR(code, ParserError, "Object name cannot be the same as the name of the containing object");
192+
}
193+
194+
BOOST_AUTO_TEST_CASE(reuse_object_in_subobject)
195+
{
196+
string code = R"(
197+
object "outer" {
198+
code { }
199+
object "outer" { code {} }
200+
}
201+
)";
202+
CHECK_ERROR(code, ParserError, "Object name cannot be the same as the name of the containing object");
203+
}
204+
205+
BOOST_AUTO_TEST_CASE(reuse_object_of_sibling)
206+
{
207+
string code = R"(
208+
object "O" {
209+
code { }
210+
object "i" { code {} }
211+
data "i" "abc"
212+
}
213+
)";
214+
CHECK_ERROR(code, ParserError, "already exists inside the");
215+
}
216+
217+
BOOST_AUTO_TEST_CASE(to_string)
218+
{
219+
string code = R"(
220+
object "O" {
221+
code { let x := mload(0) if x { sstore(0, 1) } }
222+
object "i" { code {} data "j" "def" }
223+
data "j" "abc"
224+
data "k" hex"010203"
225+
}
226+
)";
227+
string expectation = R"(object "O" {
228+
code {
229+
let x := mload(0)
230+
if x
231+
{
232+
sstore(0, 1)
233+
}
234+
}
235+
object "i" {
236+
code {
237+
}
238+
data "j" hex"646566"
239+
}
240+
data "j" hex"616263"
241+
data "k" hex"010203"
242+
}
243+
)";
244+
expectation = boost::replace_all_copy(expectation, "\t", " ");
245+
solidity::AssemblyStack asmStack(
246+
dev::test::Options::get().evmVersion(),
247+
solidity::AssemblyStack::Language::StrictAssembly
248+
);
249+
BOOST_REQUIRE(asmStack.parseAndAnalyze("source", code));
250+
BOOST_CHECK_EQUAL(asmStack.print(), expectation);
251+
}
252+
253+
BOOST_AUTO_TEST_SUITE_END()
254+
255+
}
256+
}
257+
} // end namespaces

0 commit comments

Comments
 (0)