Skip to content

Commit 5a4e9e5

Browse files
committed
Adds semantic tests to test framework and isoltest.
1 parent 27a4202 commit 5a4e9e5

File tree

4 files changed

+96
-36
lines changed

4 files changed

+96
-36
lines changed

test/boostTest.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,13 @@ int registerTests(
7474
boost::unit_test::test_suite& _suite,
7575
boost::filesystem::path const& _basepath,
7676
boost::filesystem::path const& _path,
77+
std::string const& _ipcPath,
7778
TestCase::TestCaseCreator _testCaseCreator
7879
)
7980
{
8081
int numTestsAdded = 0;
8182
fs::path fullpath = _basepath / _path;
83+
TestCase::Config config{fullpath.string(), _ipcPath};
8284
if (fs::is_directory(fullpath))
8385
{
8486
test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string());
@@ -87,7 +89,7 @@ int registerTests(
8789
fs::directory_iterator()
8890
))
8991
if (fs::is_directory(entry.path()) || TestCase::isTestFilename(entry.path().filename()))
90-
numTestsAdded += registerTests(*sub_suite, _basepath, _path / entry.path().filename(), _testCaseCreator);
92+
numTestsAdded += registerTests(*sub_suite, _basepath, _path / entry.path().filename(), _ipcPath, _testCaseCreator);
9193
_suite.add(sub_suite);
9294
}
9395
else
@@ -96,13 +98,13 @@ int registerTests(
9698

9799
filenames.emplace_back(new string(_path.string()));
98100
_suite.add(make_test_case(
99-
[fullpath, _testCaseCreator]
101+
[config, _testCaseCreator]
100102
{
101103
BOOST_REQUIRE_NO_THROW({
102104
try
103105
{
104106
stringstream errorStream;
105-
if (!_testCaseCreator(fullpath.string())->run(errorStream))
107+
if (!_testCaseCreator(config)->run(errorStream))
106108
BOOST_ERROR("Test expectation mismatch.\n" + errorStream.str());
107109
}
108110
catch (boost::exception const& _e)
@@ -142,6 +144,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
142144
master,
143145
options.testPath / ts.path,
144146
ts.subpath,
147+
options.ipcPath,
145148
ts.testCaseCreator
146149
) > 0, std::string("no ") + ts.title + " tests found");
147150
}

test/libsolidity/SemanticTest.cpp

+39-26
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,20 @@ namespace
4141
using FunctionCallTest = dev::solidity::test::SemanticTest::FunctionCallTest;
4242
using FunctionCall = dev::solidity::test::FunctionCall;
4343

44-
string formatBytes(bytes const& _bytes, ParamList const& _params, bool const _formatInvalid = false)
44+
string formatBytes(bytes const& _bytes, ParamList const& _params)
4545
{
4646
stringstream resultStream;
4747
if (_bytes.empty())
48-
resultStream.str();
48+
return resultStream.str();
4949
auto it = _bytes.begin();
5050
for (auto const& param: _params)
5151
{
52-
bytes byteRange{it, it + param.abiType.size};
53-
// FIXME Check range
54-
// TODO Check range
52+
long offset = static_cast<long>(param.abiType.size);
53+
auto offsetIter = it + offset;
54+
if (offsetIter > _bytes.end())
55+
BOOST_THROW_EXCEPTION(runtime_error("Invalid byte range defined."));
56+
57+
bytes byteRange{it, offsetIter};
5558
switch (param.abiType.type)
5659
{
5760
case ABIType::SignedDec:
@@ -74,16 +77,14 @@ namespace
7477
// If expectations are empty, the encoding type is invalid.
7578
// In order to still print the actual result even if
7679
// empty expectations were detected, it must be forced.
77-
if (_formatInvalid)
78-
resultStream << fromBigEndian<u256>(byteRange);
80+
resultStream << fromBigEndian<u256>(byteRange);
7981
break;
8082
case ABIType::None:
8183
// If expectations are empty, the encoding type is NONE.
82-
if (_formatInvalid)
83-
resultStream << fromBigEndian<u256>(byteRange);
84+
resultStream << fromBigEndian<u256>(byteRange);
8485
break;
8586
}
86-
it += param.abiType.size;
87+
it += offset;
8788
if (it != _bytes.end() && !(param.abiType.type == ABIType::None))
8889
resultStream << ", ";
8990
}
@@ -94,31 +95,43 @@ namespace
9495
FunctionCallTest const& _test,
9596
string const& _linePrefix = "",
9697
bool const _renderResult = false,
97-
bool const _higlight = false
98+
bool const _highlight = false
9899
)
99100
{
101+
using namespace solt;
102+
using Token = solt::Token;
103+
100104
stringstream _stream;
101105
FunctionCall call = _test.call;
102-
bool hightlight = !_test.matchesExpectation() && _higlight;
106+
bool highlight = !_test.matchesExpectation() && _highlight;
103107

104108
auto formatOutput = [&](bool const _singleLine)
105109
{
106-
_stream << _linePrefix << "// " << call.signature;
110+
string ws = " ";
111+
string arrow = formatToken(Token::Arrow);
112+
string colon = formatToken(Token::Colon);
113+
string comma = formatToken(Token::Comma);
114+
string ether = formatToken(Token::Ether);
115+
string newline = formatToken(Token::Newline);
116+
117+
_stream << _linePrefix << newline << ws << call.signature;
107118
if (call.value > u256(0))
108-
_stream << TestFileParser::formatToken(SoltToken::Comma)
109-
<< call.value << " "
110-
<< TestFileParser::formatToken(SoltToken::Ether);
119+
_stream << comma << call.value << ws << ether;
111120
if (!call.arguments.rawBytes().empty())
112-
_stream << ": "
113-
<< formatBytes(call.arguments.rawBytes(), call.arguments.parameters);
121+
{
122+
string output = formatBytes(call.arguments.rawBytes(), call.arguments.parameters);
123+
_stream << colon << ws << output;
124+
}
114125
if (!_singleLine)
115-
_stream << endl << _linePrefix << "// ";
126+
_stream << endl << _linePrefix << newline << ws;
127+
if (_singleLine)
128+
_stream << ws;
129+
_stream << arrow;
116130
if (_singleLine)
117-
_stream << " ";
118-
_stream << "-> ";
131+
_stream << ws;
119132
if (!_singleLine)
120-
_stream << endl << _linePrefix << "// ";
121-
if (hightlight)
133+
_stream << endl << _linePrefix << newline << ws;
134+
if (highlight)
122135
_stream << formatting::RED_BACKGROUND;
123136
bytes output;
124137
if (_renderResult)
@@ -127,7 +140,7 @@ namespace
127140
output = _test.rawBytes;
128141
if (!output.empty())
129142
_stream << formatBytes(output, call.expectations.result);
130-
if (hightlight)
143+
if (highlight)
131144
_stream << formatting::RESET;
132145
};
133146

@@ -202,10 +215,10 @@ void SemanticTest::printSource(ostream& _stream, string const& _linePrefix, bool
202215
_stream << _linePrefix << line << endl;
203216
}
204217

205-
void SemanticTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
218+
void SemanticTest::printUpdatedExpectations(ostream& _stream, string const&) const
206219
{
207220
for (auto const& test: m_tests)
208-
_stream << formatFunctionCallTest(test, _linePrefix, false, false);
221+
_stream << formatFunctionCallTest(test, "", false, false);
209222
}
210223

211224
void SemanticTest::parseExpectations(istream& _stream)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
contract C {
2+
function f() public returns (uint) {
3+
return 1;
4+
}
5+
function g(uint x, uint y) public returns (uint) {
6+
return x - y;
7+
}
8+
function h() public payable returns (uint) {
9+
return f();
10+
}
11+
}
12+
// ----
13+
// g(uint256,uint256): 1, 2 -> -1
14+
// h(),1 ether -> 1
15+
// f()
16+
// ->
17+
// 1

test/tools/isoltest.cpp

+34-7
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ class TestTool
6363
TestCase::TestCaseCreator _testCaseCreator,
6464
string const& _name,
6565
fs::path const& _path,
66+
string const& _ipcPath,
6667
bool _formatted
67-
): m_testCaseCreator(_testCaseCreator), m_formatted(_formatted), m_name(_name), m_path(_path)
68+
): m_testCaseCreator(_testCaseCreator), m_name(_name), m_path(_path), m_ipcPath(_ipcPath), m_formatted(_formatted)
6869
{}
6970

7071
enum class Result
@@ -80,6 +81,7 @@ class TestTool
8081
TestCase::TestCaseCreator _testCaseCreator,
8182
fs::path const& _basepath,
8283
fs::path const& _path,
84+
string const& _ipcPath,
8385
bool const _formatted
8486
);
8587

@@ -95,9 +97,10 @@ class TestTool
9597
Request handleResponse(bool const _exception);
9698

9799
TestCase::TestCaseCreator m_testCaseCreator;
98-
bool const m_formatted = false;
99100
string const m_name;
100101
fs::path const m_path;
102+
string m_ipcPath;
103+
bool const m_formatted = false;
101104
unique_ptr<TestCase> m_test;
102105
static bool m_exitRequested;
103106
};
@@ -114,7 +117,7 @@ TestTool::Result TestTool::process()
114117

115118
try
116119
{
117-
m_test = m_testCaseCreator(m_path.string());
120+
m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_ipcPath});
118121
success = m_test->run(outputMessages, " ", m_formatted);
119122
}
120123
catch(boost::exception const& _e)
@@ -198,6 +201,7 @@ TestStats TestTool::processPath(
198201
TestCase::TestCaseCreator _testCaseCreator,
199202
fs::path const& _basepath,
200203
fs::path const& _path,
204+
string const& _ipcPath,
201205
bool const _formatted
202206
)
203207
{
@@ -229,7 +233,7 @@ TestStats TestTool::processPath(
229233
else
230234
{
231235
++testCount;
232-
TestTool testTool(_testCaseCreator, currentPath.string(), fullpath, _formatted);
236+
TestTool testTool(_testCaseCreator, currentPath.string(), fullpath, _ipcPath, _formatted);
233237
auto result = testTool.process();
234238

235239
switch(result)
@@ -290,6 +294,7 @@ boost::optional<TestStats> runTestSuite(
290294
string const& _name,
291295
fs::path const& _basePath,
292296
fs::path const& _subdirectory,
297+
string const& _ipcPath,
293298
TestCase::TestCaseCreator _testCaseCreator,
294299
bool _formatted
295300
)
@@ -302,7 +307,7 @@ boost::optional<TestStats> runTestSuite(
302307
return {};
303308
}
304309

305-
TestStats stats = TestTool::processPath(_testCaseCreator, _basePath, _subdirectory, _formatted);
310+
TestStats stats = TestTool::processPath(_testCaseCreator, _basePath, _subdirectory, _ipcPath, _formatted);
306311

307312
cout << endl << _name << " Test Summary: ";
308313
FormattedScope(cout, _formatted, {BOLD, stats ? GREEN : RED}) <<
@@ -326,11 +331,13 @@ int main(int argc, char *argv[])
326331
TestTool::editor = "/usr/bin/editor";
327332

328333
fs::path testPath;
334+
string ipcPath;
335+
bool disableIPC = false;
329336
bool disableSMT = false;
330337
bool formatted = true;
331338
po::options_description options(
332339
R"(isoltest, tool for interactively managing test contracts.
333-
Usage: isoltest [Options] --testpath path
340+
Usage: isoltest [Options] --testpath path --ipcpath ipcpath
334341
Interactively validates test contracts.
335342
336343
Allowed options)",
@@ -339,6 +346,8 @@ Allowed options)",
339346
options.add_options()
340347
("help", "Show this help screen.")
341348
("testpath", po::value<fs::path>(&testPath), "path to test files")
349+
("ipcpath", po::value<string>(&ipcPath), "path to ipc socket")
350+
("no-ipc", "disable semantic tests")
342351
("no-smt", "disable SMT checker")
343352
("no-color", "don't use colors")
344353
("editor", po::value<string>(&TestTool::editor), "editor for opening contracts");
@@ -361,8 +370,23 @@ Allowed options)",
361370

362371
po::notify(arguments);
363372

373+
if (arguments.count("no-ipc"))
374+
disableIPC = true;
375+
else
376+
{
377+
solAssert(
378+
!ipcPath.empty(),
379+
"No ipc path specified. The --ipcpath argument is required, unless --no-ipc is used."
380+
);
381+
solAssert(
382+
fs::exists(ipcPath),
383+
"Invalid ipc path specified."
384+
);
385+
}
386+
364387
if (arguments.count("no-smt"))
365388
disableSMT = true;
389+
366390
}
367391
catch (std::exception const& _exception)
368392
{
@@ -379,10 +403,13 @@ Allowed options)",
379403
// Interactive tests are added in InteractiveTests.h
380404
for (auto const& ts: g_interactiveTestsuites)
381405
{
406+
if (ts.ipc && disableIPC)
407+
continue;
408+
382409
if (ts.smt && disableSMT)
383410
continue;
384411

385-
if (auto stats = runTestSuite(ts.title, testPath / ts.path, ts.subpath, ts.testCaseCreator, formatted))
412+
if (auto stats = runTestSuite(ts.title, testPath / ts.path, ts.subpath, ipcPath, ts.testCaseCreator, formatted))
386413
global_stats += *stats;
387414
else
388415
return 1;

0 commit comments

Comments
 (0)