Skip to content

Commit 6495949

Browse files
committed
Introduce dedicated exception classes for soltest, derived from util::Exception
1 parent 6c74987 commit 6495949

24 files changed

+123
-127
lines changed

test/Common.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#include <range/v3/all.hpp>
3535

3636
#include <iostream>
37-
#include <stdexcept>
3837

3938
namespace fs = boost::filesystem;
4039
namespace po = boost::program_options;

test/Common.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ static constexpr auto evmoneFilename = "libevmone.so";
4848
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.13.0/evmone-0.13.0-linux-x86_64.tar.gz";
4949
#endif
5050

51-
struct ConfigException: public util::Exception {};
51+
struct SoltestError: public util::Exception {};
52+
struct ConfigException: public SoltestError {};
53+
struct ValidationError: public SoltestError {};
54+
struct ExecutionError: public SoltestError {};
5255

5356
struct CommonOptions
5457
{

test/CommonSyntaxTest.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232

3333
#include <istream>
3434
#include <ostream>
35-
#include <stdexcept>
3635

3736
using namespace solidity;
3837
using namespace solidity::util;
@@ -49,7 +48,7 @@ namespace
4948
int parseUnsignedInteger(std::string::iterator& _it, std::string::iterator _end)
5049
{
5150
if (_it == _end || !util::isDigit(*_it))
52-
BOOST_THROW_EXCEPTION(std::runtime_error("Invalid test expectation. Source location expected."));
51+
solThrow(ValidationError, "Invalid test expectation. Source location expected.");
5352
int result = 0;
5453
while (_it != _end && util::isDigit(*_it))
5554
{
@@ -257,8 +256,7 @@ std::vector<SyntaxTestError> CommonSyntaxTest::parseExpectations(std::istream& _
257256

258257
std::string errorTypeStr(typeBegin, it);
259258
std::optional<Error::Type> errorType = Error::parseErrorType(errorTypeStr);
260-
if (!errorType.has_value())
261-
BOOST_THROW_EXCEPTION(std::runtime_error("Invalid error type: " + errorTypeStr));
259+
solRequire(errorType.has_value(), ValidationError, "Invalid error type: " + errorTypeStr);
262260

263261
skipWhitespace(it, line.end());
264262

test/FilesystemUtils.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@
1818

1919
#include <test/FilesystemUtils.h>
2020

21+
#include <test/Common.h>
22+
2123
#include <test/libsolidity/util/SoltestErrors.h>
2224

25+
#include <fmt/format.h>
26+
2327
#include <fstream>
2428

2529
using namespace solidity;
@@ -37,19 +41,19 @@ void solidity::test::createFilesWithParentDirs(std::set<boost::filesystem::path>
3741
newFile << _content;
3842

3943
if (newFile.fail() || !boost::filesystem::exists(path))
40-
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create an empty file: \"" + path.string() + "\"."));
44+
solThrow(ExecutionError, "Failed to create an empty file: \"" + path.string() + "\".");
4145
}
4246
}
4347

4448
void solidity::test::createFileWithContent(boost::filesystem::path const& _path, std::string const& _content)
4549
{
4650
if (boost::filesystem::is_regular_file(_path))
47-
BOOST_THROW_EXCEPTION(std::runtime_error("File already exists: \"" + _path.string() + "\"."));
51+
solThrow(ExecutionError, "File already exists: \"" + _path.string() + "\".");
4852

4953
// Use binary mode to avoid line ending conversion on Windows.
5054
std::ofstream newFile(_path.string(), std::ofstream::binary);
5155
if (newFile.fail() || !boost::filesystem::is_regular_file(_path))
52-
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create a file: \"" + _path.string() + "\"."));
56+
solThrow(ExecutionError, "Failed to create a file: \"" + _path.string() + "\".");
5357

5458
newFile << _content;
5559
}
@@ -79,9 +83,10 @@ bool solidity::test::createSymlinkIfSupportedByFilesystem(
7983
)
8084
return false;
8185
else
82-
BOOST_THROW_EXCEPTION(std::runtime_error(
83-
"Failed to create a symbolic link: \"" + _linkName.string() + "\""
84-
" -> " + _targetPath.string() + "\"."
85-
" " + symlinkCreationError.message() + "."
86+
solThrow(ExecutionError, fmt::format(
87+
"Failed to create a symbolic link: \"{}\" -> {}\". {}.",
88+
_linkName.string(),
89+
_targetPath.string(),
90+
symlinkCreationError.message()
8691
));
8792
}

test/TestCase.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@
2020
#include <test/TestCase.h>
2121

2222
#include <libsolutil/AnsiColorized.h>
23+
#include <libsolutil/Exceptions.h>
2324
#include <libsolutil/StringUtils.h>
2425

2526
#include <boost/algorithm/string/predicate.hpp>
2627

2728
#include <iostream>
28-
#include <stdexcept>
2929

30+
using namespace std::string_literals;
3031
using namespace solidity;
3132
using namespace solidity::frontend;
3233
using namespace solidity::frontend::test;
@@ -66,7 +67,7 @@ bool TestCase::shouldRun()
6667
void TestCase::expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c)
6768
{
6869
if (_it == _end || *_it != _c)
69-
BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Invalid test expectation. Expected: \"") + _c + "\"."));
70+
solThrow(ValidationError, "Invalid test expectation. Expected: \""s + _c + "\".");
7071
++_it;
7172
}
7273

@@ -120,8 +121,7 @@ void EVMVersionRestrictedTestCase::processEVMVersionSetting()
120121
version = std::make_optional<langutil::EVMVersion>();
121122
else
122123
version = langutil::EVMVersion::fromString(versionString);
123-
if (!version)
124-
BOOST_THROW_EXCEPTION(std::runtime_error{"Invalid EVM version: \"" + versionString + "\""});
124+
solRequire(version, ValidationError, "Invalid EVM version: \"" + versionString + "\"");
125125

126126
langutil::EVMVersion evmVersion = CommonOptions::get().evmVersion();
127127
bool comparisonResult;
@@ -138,7 +138,7 @@ void EVMVersionRestrictedTestCase::processEVMVersionSetting()
138138
else if (comparator == "!")
139139
comparisonResult = !(evmVersion == version);
140140
else
141-
BOOST_THROW_EXCEPTION(std::runtime_error{"Invalid EVM comparator: \"" + comparator + "\""});
141+
solThrow(ValidationError, "Invalid EVM comparator: \"" + comparator + "\"");
142142

143143
if (!comparisonResult)
144144
m_shouldRun = false;
@@ -160,7 +160,7 @@ void EVMVersionRestrictedTestCase::processBytecodeFormatSetting()
160160
else if (bytecodeFormatString == ">=EOFv1" && !eofVersion.has_value())
161161
m_shouldRun = false;
162162
else if (bytecodeFormatString != "legacy" && bytecodeFormatString != ">=EOFv1" )
163-
BOOST_THROW_EXCEPTION(std::runtime_error{"Invalid bytecodeFormat flag: \"" + bytecodeFormatString + "\""});
163+
solThrow(ValidationError, "Invalid bytecodeFormat flag: \"" + bytecodeFormatString + "\"");
164164
}
165165

166166
EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(std::string const& _filename):

test/TestCaseReader.cpp

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424
#include <boost/filesystem.hpp>
2525

2626
using namespace solidity::frontend::test;
27+
using namespace solidity::test;
2728

2829
namespace fs = boost::filesystem;
2930

30-
TestCaseReader::TestCaseReader(std::string const& _filename): m_fileStream(_filename), m_fileName(_filename)
31+
TestCaseReader::TestCaseReader(std::string const& _filename):
32+
m_fileStream(_filename),
33+
m_fileName(_filename)
3134
{
32-
if (!m_fileStream)
33-
BOOST_THROW_EXCEPTION(std::runtime_error("Cannot open file: \"" + _filename + "\"."));
35+
solRequire(m_fileStream, ValidationError, "Cannot open file: \"" + _filename + "\".");
3436
m_fileStream.exceptions(std::ios::badbit);
3537

3638
std::tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber(m_fileStream);
@@ -47,7 +49,7 @@ TestCaseReader::TestCaseReader(std::istringstream const& _str)
4749
std::string const& TestCaseReader::source() const
4850
{
4951
if (m_sources.sources.size() != 1)
50-
BOOST_THROW_EXCEPTION(std::runtime_error("Expected single source definition, but got multiple sources."));
52+
solThrow(ValidationError, "Expected single source definition, but got multiple sources.");
5153
return m_sources.sources.at(m_sources.mainSourceFile);
5254
}
5355

@@ -68,7 +70,7 @@ bool TestCaseReader::boolSetting(std::string const& _name, bool _defaultValue)
6870
if (value == "true")
6971
return true;
7072

71-
BOOST_THROW_EXCEPTION(std::runtime_error("Invalid Boolean value: " + value + "."));
73+
solThrow(ValidationError, "Invalid Boolean value: " + value + ".");
7274
}
7375

7476
size_t TestCaseReader::sizetSetting(std::string const& _name, size_t _defaultValue)
@@ -94,10 +96,10 @@ std::string TestCaseReader::stringSetting(std::string const& _name, std::string
9496
void TestCaseReader::ensureAllSettingsRead() const
9597
{
9698
if (!m_unreadSettings.empty())
97-
BOOST_THROW_EXCEPTION(std::runtime_error(
98-
"Unknown setting(s): " +
99-
util::joinHumanReadable(m_unreadSettings | ranges::views::keys)
100-
));
99+
solThrow(
100+
ValidationError,
101+
"Unknown setting(s): " + util::joinHumanReadable(m_unreadSettings | ranges::views::keys)
102+
);
101103
}
102104

103105
std::pair<SourceMap, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(std::istream& _stream)
@@ -137,7 +139,7 @@ std::pair<SourceMap, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumb
137139
line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size()
138140
));
139141
if (sources.count(currentSourceName))
140-
BOOST_THROW_EXCEPTION(std::runtime_error("Multiple definitions of test source \"" + currentSourceName + "\"."));
142+
solThrow(ValidationError, "Multiple definitions of test source \"" + currentSourceName + "\".");
141143
}
142144
else if (boost::algorithm::starts_with(line, externalSourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd))
143145
{
@@ -163,16 +165,16 @@ std::pair<SourceMap, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumb
163165
if (!externalSourceTarget.is_relative() || !externalSourceTarget.root_path().empty())
164166
// NOTE: UNC paths (ones starting with // or \\) are considered relative by Boost
165167
// since they have an empty root directory (but non-empty root name).
166-
BOOST_THROW_EXCEPTION(std::runtime_error("External Source paths need to be relative to the location of the test case."));
168+
solThrow(ValidationError, "External Source paths need to be relative to the location of the test case.");
167169
fs::path externalSourceFullPath = testCaseParentDir / externalSourceTarget;
168170
std::string externalSourceContent;
169171
if (!fs::exists(externalSourceFullPath))
170-
BOOST_THROW_EXCEPTION(std::runtime_error("External Source '" + externalSourceTarget.string() + "' not found."));
172+
solThrow(ValidationError, "External Source '" + externalSourceTarget.string() + "' not found.");
171173
else
172174
externalSourceContent = util::readFileAsString(externalSourceFullPath);
173175

174176
if (sources.count(externalSourceName))
175-
BOOST_THROW_EXCEPTION(std::runtime_error("Multiple definitions of test source \"" + externalSourceName + "\"."));
177+
solThrow(ValidationError, "Multiple definitions of test source \"" + externalSourceName + "\".");
176178
sources[externalSourceName] = externalSourceContent;
177179
externalSources[externalSourceName] = externalSourceTarget;
178180
}
@@ -183,15 +185,15 @@ std::pair<SourceMap, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumb
183185
{
184186
size_t colon = line.find(':');
185187
if (colon == std::string::npos)
186-
BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Expected \":\" inside setting.")));
188+
solThrow(ValidationError, "Expected \":\" inside setting.");
187189
std::string key = line.substr(comment.size(), colon - comment.size());
188190
std::string value = line.substr(colon + 1);
189191
boost::algorithm::trim(key);
190192
boost::algorithm::trim(value);
191193
m_settings[key] = value;
192194
}
193195
else
194-
BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Expected \"//\" or \"// ---\" to terminate settings and source.")));
196+
solThrow(ValidationError, "Expected \"//\" or \"// ---\" to terminate settings and source.");
195197
}
196198
// Register the last source as the main one
197199
sources[currentSourceName] = currentSource;
@@ -208,6 +210,6 @@ std::string TestCaseReader::parseSimpleExpectations(std::istream& _file)
208210
else if (line == "//")
209211
result += "\n";
210212
else
211-
BOOST_THROW_EXCEPTION(std::runtime_error("Test expectations must start with \"// \"."));
213+
solThrow(ValidationError, "Test expectations must start with \"// \".");
212214
return result;
213215
}

test/TestCaseReader.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,19 @@
1818

1919
#pragma once
2020

21+
#include <test/Common.h>
22+
2123
#include <test/libsolidity/util/SoltestErrors.h>
2224

2325
#include <libsolutil/StringUtils.h>
2426

25-
#include <range/v3/view/map.hpp>
26-
2727
#include <boost/filesystem.hpp>
2828
#include <boost/throw_exception.hpp>
2929

30+
#include <fmt/format.h>
31+
32+
#include <range/v3/view/map.hpp>
33+
3034
#include <fstream>
3135
#include <map>
3236
#include <string>
@@ -91,10 +95,11 @@ E TestCaseReader::enumSetting(std::string const& _name, std::map<std::string, E>
9195

9296
std::string value = stringSetting(_name, _defaultChoice);
9397

94-
if (_choices.count(value) == 0)
95-
BOOST_THROW_EXCEPTION(std::runtime_error(
96-
"Invalid Enum value: " + value + ". Available choices: " + util::joinHumanReadable(_choices | ranges::views::keys) + "."
97-
));
98+
solRequire(_choices.count(value) != 0, solidity::test::ValidationError, fmt::format(
99+
"Invalid Enum value: {}. Available choices: {}.",
100+
value,
101+
util::joinHumanReadable(_choices | ranges::views::keys)
102+
));
98103

99104
return _choices.at(value);
100105
}

test/libevmasm/EVMAssemblyTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ EVMAssemblyTest::EVMAssemblyTest(std::string const& _filename):
6464
else if (boost::algorithm::ends_with(_filename, ".asm"))
6565
m_assemblyFormat = AssemblyFormat::Plain;
6666
else
67-
BOOST_THROW_EXCEPTION(std::runtime_error("Not an assembly test: \"" + _filename + "\". Allowed extensions: .asm, .asmjson."));
67+
solThrow(ValidationError, "Not an assembly test: \"" + _filename + "\". Allowed extensions: .asm, .asmjson.");
6868

6969
m_selectedOutputs = m_reader.stringSetting("outputs", "Assembly,Bytecode,Opcodes,SourceMappings");
7070
OptimisationPreset optimizationPreset = m_reader.enumSetting<OptimisationPreset>(

test/libevmasm/PlainAssemblyParser.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Json PlainAssemblyParser::parse(std::string _sourceName, std::string const& _sou
6868
expectNoMoreArguments();
6969

7070
if (!immediateArgument.starts_with("0x"))
71-
BOOST_THROW_EXCEPTION(std::runtime_error(formatError("The immediate argument to PUSH must be a hex number prefixed with '0x'.")));
71+
solThrow(ValidationError, formatError("The immediate argument to PUSH must be a hex number prefixed with '0x'."));
7272

7373
immediateArgument.remove_prefix("0x"s.size());
7474
codeJSON.push_back({{"name", "PUSH"}, {"value", immediateArgument}});
@@ -83,7 +83,7 @@ Json PlainAssemblyParser::parse(std::string _sourceName, std::string const& _sou
8383
codeJSON.push_back({{"name", "JUMPDEST"}});
8484
}
8585
else
86-
BOOST_THROW_EXCEPTION(std::runtime_error(formatError("Unknown instruction.")));
86+
solThrow(ValidationError, formatError("Unknown instruction."));
8787
}
8888
return {{".code", codeJSON}};
8989
}
@@ -113,7 +113,7 @@ std::string_view PlainAssemblyParser::expectArgument()
113113
{
114114
bool hasArgument = advanceToken();
115115
if (!hasArgument)
116-
BOOST_THROW_EXCEPTION(std::runtime_error(formatError("Missing argument(s).")));
116+
solThrow(ValidationError, formatError("Missing argument(s)."));
117117

118118
return currentToken().value;
119119
}
@@ -122,7 +122,7 @@ void PlainAssemblyParser::expectNoMoreArguments()
122122
{
123123
bool hasArgument = advanceToken();
124124
if (hasArgument)
125-
BOOST_THROW_EXCEPTION(std::runtime_error(formatError("Too many arguments.")));
125+
solThrow(ValidationError, formatError("Too many arguments."));
126126
}
127127

128128
void PlainAssemblyParser::advanceLine(std::string_view _line)

test/libevmasm/PlainAssemblyParser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class PlainAssemblyParser
4646
{
4747
public:
4848
/// Parses plain assembly format and returns the equivalent assembly JSON.
49-
/// Errors are reported by throwing runtime_error.
49+
/// Errors are reported by throwing ValidationError.
5050
Json parse(std::string _sourceName, std::string const& _source);
5151

5252
protected:

0 commit comments

Comments
 (0)