Skip to content

Soltest error handling refactor #16014

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 14 commits into
base: soltest-cleanup
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
#include <range/v3/view/enumerate.hpp>
#include <range/v3/view/map.hpp>

#include <fstream>
#include <limits>
#include <iterator>
#include <ostream>
#include <stack>

using namespace solidity;
Expand Down
24 changes: 17 additions & 7 deletions libevmasm/EVMAssemblyStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ void EVMAssemblyStack::assemble()
LinkerObject const& EVMAssemblyStack::object(std::string const& _contractName) const
{
solAssert(_contractName == m_name);
return m_object;
return object();
}

LinkerObject const& EVMAssemblyStack::runtimeObject(std::string const& _contractName) const
{
solAssert(_contractName == m_name);
return m_runtimeObject;
return runtimeObject();
}

std::map<std::string, unsigned> EVMAssemblyStack::sourceIndices() const
Expand All @@ -95,13 +95,13 @@ std::map<std::string, unsigned> EVMAssemblyStack::sourceIndices() const
std::string const* EVMAssemblyStack::sourceMapping(std::string const& _contractName) const
{
solAssert(_contractName == m_name);
return &m_sourceMapping;
return &sourceMapping();
}

std::string const* EVMAssemblyStack::runtimeSourceMapping(std::string const& _contractName) const
{
solAssert(_contractName == m_name);
return &m_runtimeSourceMapping;
return &runtimeSourceMapping();
}

Json EVMAssemblyStack::ethdebug(std::string const& _contractName) const
Expand All @@ -123,20 +123,30 @@ Json EVMAssemblyStack::ethdebug() const
return {};
}

Json EVMAssemblyStack::assemblyJSON(std::string const& _contractName) const
Json EVMAssemblyStack::assemblyJSON() const
{
solAssert(_contractName == m_name);
solAssert(m_evmAssembly);
return m_evmAssembly->assemblyJSON(sourceIndices());
}

std::string EVMAssemblyStack::assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const
Json EVMAssemblyStack::assemblyJSON(std::string const& _contractName) const
{
solAssert(_contractName == m_name);
return assemblyJSON();
}

std::string EVMAssemblyStack::assemblyString(StringMap const& _sourceCodes) const
{
solAssert(m_evmAssembly);
return m_evmAssembly->assemblyString(m_debugInfoSelection, _sourceCodes);
}

std::string EVMAssemblyStack::assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const
{
solAssert(_contractName == m_name);
return assemblyString(_sourceCodes);
}

std::string const EVMAssemblyStack::filesystemFriendlyName(std::string const& _contractName) const
{
solAssert(_contractName == m_name);
Expand Down
6 changes: 6 additions & 0 deletions libevmasm/EVMAssemblyStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,26 @@ class EVMAssemblyStack: public AbstractAssemblyStack

std::string const& name() const { return m_name; }

LinkerObject const& object() const { return m_object; }
LinkerObject const& object(std::string const& _contractName) const override;
LinkerObject const& runtimeObject() const { return m_runtimeObject; }
LinkerObject const& runtimeObject(std::string const& _contractName) const override;

std::shared_ptr<evmasm::Assembly> const& evmAssembly() const { return m_evmAssembly; }
std::shared_ptr<evmasm::Assembly> const& evmRuntimeAssembly() const { return m_evmRuntimeAssembly; }

std::string const& sourceMapping() const { return m_sourceMapping; }
std::string const* sourceMapping(std::string const& _contractName) const override;
std::string const& runtimeSourceMapping() const { return m_runtimeSourceMapping; }
std::string const* runtimeSourceMapping(std::string const& _contractName) const override;

Json ethdebug(std::string const& _contractName) const override;
Json ethdebugRuntime(std::string const& _contractName) const override;
Json ethdebug() const override;

Json assemblyJSON() const;
Json assemblyJSON(std::string const& _contractName) const override;
std::string assemblyString(StringMap const& _sourceCodes) const;
std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const override;

std::string const filesystemFriendlyName(std::string const& _contractName) const override;
Expand Down
2 changes: 1 addition & 1 deletion libevmasm/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ using namespace solidity;
using namespace solidity::util;
using namespace solidity::evmasm;

std::map<std::string, Instruction> const solidity::evmasm::c_instructions =
std::map<std::string, Instruction, std::less<>> const solidity::evmasm::c_instructions =
{
{ "STOP", Instruction::STOP },
{ "ADD", Instruction::ADD },
Expand Down
2 changes: 1 addition & 1 deletion libevmasm/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,6 @@ InstructionInfo instructionInfo(Instruction _inst, langutil::EVMVersion _evmVers
bool isValidInstruction(Instruction _inst);

/// Convert from string mnemonic to Instruction type.
extern const std::map<std::string, Instruction> c_instructions;
extern const std::map<std::string, Instruction, std::less<>> c_instructions;

}
4 changes: 4 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ detect_stray_source_files("${libsolutil_sources}" "libsolutil/")

set(libevmasm_sources
libevmasm/Assembler.cpp
libevmasm/EVMAssemblyTest.cpp
libevmasm/EVMAssemblyTest.h
libevmasm/Optimiser.cpp
libevmasm/PlainAssemblyParser.cpp
libevmasm/PlainAssemblyParser.h
)
detect_stray_source_files("${libevmasm_sources}" "libevmasm/")

Expand Down
43 changes: 24 additions & 19 deletions test/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <libyul/backends/evm/EVMDialect.h>

#include <libsolutil/Assertions.h>
#include <libsolutil/Exceptions.h>
#include <libsolutil/StringUtils.h>

#include <boost/algorithm/string.hpp>
Expand All @@ -33,7 +34,6 @@
#include <range/v3/all.hpp>

#include <iostream>
#include <stdexcept>

namespace fs = boost::filesystem;
namespace po = boost::program_options;
Expand Down Expand Up @@ -110,10 +110,10 @@ CommonOptions::CommonOptions(std::string _caption):
void CommonOptions::addOptions()
{
options.add_options()
("evm-version", po::value(&evmVersionString), "which EVM version to use")
("evm-version", po::value(&m_evmVersionString), "which EVM version to use")
// "eof-version" is declared as uint64_t, since uint8_t will be parsed as character by boost.
("eof-version", po::value<uint64_t>()->implicit_value(1u), "which EOF version to use")
("testpath", po::value<fs::path>(&this->testPath)->default_value(solidity::test::testPath()), "path to test files")
("testpath", po::value<fs::path>(&this->testPath)->default_value(test::testPath()), "path to test files")
("vm", po::value<std::vector<fs::path>>(&vmPaths), "path to evmc library, can be supplied multiple times.")
("batches", po::value<size_t>(&this->batches)->default_value(1), "set number of batches to split the tests into")
("selected-batch", po::value<size_t>(&this->selectedBatch)->default_value(0), "zero-based number of batch to execute")
Expand Down Expand Up @@ -185,8 +185,7 @@ bool CommonOptions::parse(int argc, char const* const* argv)
{
// Request as uint64_t, since uint8_t will be parsed as character by boost.
uint64_t eofVersion = arguments["eof-version"].as<uint64_t>();
if (eofVersion != 1)
BOOST_THROW_EXCEPTION(std::runtime_error("Invalid EOF version: " + std::to_string(eofVersion)));
solRequire(eofVersion == 1, ConfigException, "Invalid EOF version: " + std::to_string(eofVersion));
m_eofVersion = 1;
}

Expand All @@ -198,11 +197,7 @@ bool CommonOptions::parse(int argc, char const* const* argv)
(parsedOption.original_tokens.size() == 1 && parsedOption.original_tokens.front().empty())
)
continue; // ignore empty options
std::stringstream errorMessage;
errorMessage << "Unrecognized option: ";
for (auto const& token: parsedOption.original_tokens)
errorMessage << token;
BOOST_THROW_EXCEPTION(std::runtime_error(errorMessage.str()));
solThrow(ConfigException, "Unrecognized option: " + util::joinHumanReadable(parsedOption.original_tokens, ""));
}
}
catch (po::error const& exception)
Expand Down Expand Up @@ -259,11 +254,10 @@ void CommonOptions::printSelectedOptions(std::ostream& _stream, std::string cons

langutil::EVMVersion CommonOptions::evmVersion() const
{
if (!evmVersionString.empty())
if (!m_evmVersionString.empty())
{
auto version = langutil::EVMVersion::fromString(evmVersionString);
if (!version)
BOOST_THROW_EXCEPTION(std::runtime_error("Invalid EVM version: " + evmVersionString));
auto version = langutil::EVMVersion::fromString(m_evmVersionString);
solRequire(version, ConfigException, "Invalid EVM version: " + m_evmVersionString);
return *version;
}
else
Expand All @@ -279,7 +273,7 @@ yul::EVMDialect const& CommonOptions::evmDialect() const
CommonOptions const& CommonOptions::get()
{
if (!m_singleton)
BOOST_THROW_EXCEPTION(std::runtime_error("Options not yet constructed!"));
soltestAssert(false, "Options not yet constructed!");

return *m_singleton;
}
Expand All @@ -306,10 +300,21 @@ bool isValidSemanticTestPath(boost::filesystem::path const& _testPath)
return true;
}

std::set<std::string> testFileExtensions()
{
return {
".sol",
".yul",
".asm",
".asmjson", // Not .json because JSON files that do not represent test cases exist in some test dirs.
".stack",
};
}

boost::unit_test::precondition::predicate_t nonEOF()
{
return [](boost::unit_test::test_unit_id) {
return !solidity::test::CommonOptions::get().eofVersion().has_value();
return !CommonOptions::get().eofVersion().has_value();
};
}

Expand All @@ -325,13 +330,13 @@ bool loadVMs(CommonOptions const& _options)
if (_options.disableSemanticTests)
return true;

bool evmSupported = solidity::test::EVMHost::checkVmPaths(_options.vmPaths);
bool evmSupported = EVMHost::checkVmPaths(_options.vmPaths);
if (!_options.disableSemanticTests && !evmSupported)
{
std::cerr << "Unable to find " << solidity::test::evmoneFilename;
std::cerr << "Unable to find " << evmoneFilename;
std::cerr << ". Please disable semantics tests with --no-semantic-tests or provide a path using --vm <path>." << std::endl;
std::cerr << "You can download it at" << std::endl;
std::cerr << solidity::test::evmoneDownloadLink << std::endl;
std::cerr << evmoneDownloadLink << std::endl;
return false;
}
return true;
Expand Down
12 changes: 9 additions & 3 deletions test/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ static constexpr auto evmoneFilename = "libevmone.so";
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.13.0/evmone-0.13.0-linux-x86_64.tar.gz";
#endif

struct ConfigException: public util::Exception {};
struct SoltestError: public util::Exception {};
struct ConfigException: public SoltestError {};
struct ValidationError: public SoltestError {};
struct ExecutionError: public SoltestError {};

struct CommonOptions
{
Expand Down Expand Up @@ -76,7 +79,7 @@ struct CommonOptions
virtual void addOptions();
// @returns true if the program should continue, false if it should exit immediately without
// reporting an error.
// Throws ConfigException or std::runtime_error if parsing fails.
// Throws ConfigException if parsing fails.
virtual bool parse(int argc, char const* const* argv);
// Throws a ConfigException on error
virtual void validate() const;
Expand All @@ -97,7 +100,7 @@ struct CommonOptions
boost::program_options::options_description options;

private:
std::string evmVersionString;
std::string m_evmVersionString;
std::optional<uint8_t> m_eofVersion;
static std::unique_ptr<CommonOptions const> m_singleton;
};
Expand All @@ -107,6 +110,9 @@ struct CommonOptions
/// Note: @p _testPath can be relative but must include at least the `/test/libsolidity/semanticTests/` part
bool isValidSemanticTestPath(boost::filesystem::path const& _testPath);

/// Returns a list of file extensions allowed for test files.
std::set<std::string> testFileExtensions();

/// Helper that can be used to skip tests when the EVM version selected on the command line
/// is older than @p _minEVMVersion.
/// @return A predicate (function) that can be passed into @a boost::unit_test::precondition().
Expand Down
11 changes: 4 additions & 7 deletions test/CommonSyntaxTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@
#include <boost/test/unit_test.hpp>
#include <boost/throw_exception.hpp>

#include <fstream>
#include <memory>
#include <stdexcept>
#include <istream>
#include <ostream>

using namespace solidity;
using namespace solidity::util;
Expand All @@ -42,15 +41,14 @@ using namespace solidity::frontend;
using namespace solidity::frontend::test;
using namespace solidity::test;
using namespace boost::unit_test;
namespace fs = boost::filesystem;

namespace
{

int parseUnsignedInteger(std::string::iterator& _it, std::string::iterator _end)
{
if (_it == _end || !util::isDigit(*_it))
BOOST_THROW_EXCEPTION(std::runtime_error("Invalid test expectation. Source location expected."));
solThrow(ValidationError, "Invalid test expectation. Source location expected.");
int result = 0;
while (_it != _end && util::isDigit(*_it))
{
Expand Down Expand Up @@ -258,8 +256,7 @@ std::vector<SyntaxTestError> CommonSyntaxTest::parseExpectations(std::istream& _

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

skipWhitespace(it, line.end());

Expand Down
1 change: 0 additions & 1 deletion test/CommonSyntaxTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
#include <iosfwd>
#include <string>
#include <vector>
#include <utility>

namespace solidity::test
{
Expand Down
5 changes: 3 additions & 2 deletions test/EVMHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#endif

#include <test/EVMHost.h>

#include <test/Common.h>
#include <test/libsolidity/util/SoltestErrors.h>

#if defined(__GNUC__) && !defined(__clang__) // GCC-specific pragma
Expand Down Expand Up @@ -91,8 +93,7 @@ bool EVMHost::checkVmPaths(std::vector<boost::filesystem::path> const& _vmPaths)

if (vm.has_capability(EVMC_CAPABILITY_EVM1))
{
if (evmVmFound)
BOOST_THROW_EXCEPTION(std::runtime_error("Multiple evm1 evmc vms defined. Please only define one evm1 evmc vm."));
solRequire(!evmVmFound, ConfigException, "Multiple evm1 evmc vms defined. Please only define one evm1 evmc vm.");
evmVmFound = true;
}
}
Expand Down
2 changes: 0 additions & 2 deletions test/ExecutionFramework.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
#include <libsolutil/FunctionSelector.h>
#include <libsolutil/ErrorCodes.h>

#include <functional>

#include <boost/rational.hpp>
#include <boost/test/unit_test.hpp>

Expand Down
Loading