mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Introduced TestCaseReader.
This commit is contained in:
parent
e5a49e2556
commit
66783c30ce
@ -54,7 +54,7 @@ inline std::optional<RevertStrings> revertStringsFromString(std::string const& _
|
||||
for (auto i: {RevertStrings::Default, RevertStrings::Strip, RevertStrings::Debug, RevertStrings::VerboseDebug})
|
||||
if (revertStringsToString(i) == _str)
|
||||
return i;
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ set(sources
|
||||
Metadata.h
|
||||
TestCase.cpp
|
||||
TestCase.h
|
||||
TestCaseReader.cpp
|
||||
TestCaseReader.h
|
||||
)
|
||||
detect_stray_source_files("${sources}" ".")
|
||||
|
||||
|
@ -56,16 +56,12 @@ int parseUnsignedInteger(string::iterator& _it, string::iterator _end)
|
||||
|
||||
}
|
||||
|
||||
CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): m_evmVersion(_evmVersion)
|
||||
CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion):
|
||||
EVMVersionRestrictedTestCase(_filename),
|
||||
m_evmVersion(_evmVersion)
|
||||
{
|
||||
ifstream file(_filename);
|
||||
if (!file)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
|
||||
file.exceptions(ios::badbit);
|
||||
|
||||
m_sources = parseSourcesAndSettings(file);
|
||||
|
||||
m_expectations = parseExpectations(file);
|
||||
m_sources = m_reader.sources();
|
||||
m_expectations = parseExpectations(m_reader.stream());
|
||||
}
|
||||
|
||||
TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||
|
@ -18,16 +18,9 @@
|
||||
#include <test/Common.h>
|
||||
#include <test/TestCase.h>
|
||||
|
||||
#include <libsolutil/StringUtils.h>
|
||||
|
||||
#include <boost/algorithm/cxx11/none_of.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
@ -37,11 +30,12 @@ using namespace solidity::frontend::test;
|
||||
|
||||
void TestCase::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool)
|
||||
{
|
||||
if (m_validatedSettings.empty())
|
||||
auto& settings = m_reader.settings();
|
||||
if (settings.empty())
|
||||
return;
|
||||
|
||||
_stream << _linePrefix << "// ====" << endl;
|
||||
for (auto const& setting: m_validatedSettings)
|
||||
for (auto const& setting: settings)
|
||||
_stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl;
|
||||
}
|
||||
|
||||
@ -53,108 +47,12 @@ bool TestCase::isTestFilename(boost::filesystem::path const& _filename)
|
||||
!boost::starts_with(_filename.string(), ".");
|
||||
}
|
||||
|
||||
void TestCase::validateSettings()
|
||||
{
|
||||
if (!m_settings.empty())
|
||||
throw runtime_error(
|
||||
"Unknown setting(s): " +
|
||||
util::joinHumanReadable(m_settings | boost::adaptors::map_keys)
|
||||
);
|
||||
}
|
||||
|
||||
bool TestCase::shouldRun()
|
||||
{
|
||||
m_reader.ensureAllSettingsRead();
|
||||
return m_shouldRun;
|
||||
}
|
||||
|
||||
pair<map<string, string>, size_t> TestCase::parseSourcesAndSettingsWithLineNumbers(istream& _stream)
|
||||
{
|
||||
map<string, string> sources;
|
||||
string currentSourceName;
|
||||
string currentSource;
|
||||
string line;
|
||||
size_t lineNumber = 1;
|
||||
static string const sourceDelimiterStart("==== Source:");
|
||||
static string const sourceDelimiterEnd("====");
|
||||
static string const comment("// ");
|
||||
static string const settingsDelimiter("// ====");
|
||||
static string const delimiter("// ----");
|
||||
bool sourcePart = true;
|
||||
while (getline(_stream, line))
|
||||
{
|
||||
lineNumber++;
|
||||
|
||||
if (boost::algorithm::starts_with(line, delimiter))
|
||||
break;
|
||||
else if (boost::algorithm::starts_with(line, settingsDelimiter))
|
||||
sourcePart = false;
|
||||
else if (sourcePart)
|
||||
{
|
||||
if (boost::algorithm::starts_with(line, sourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd))
|
||||
{
|
||||
if (!(currentSourceName.empty() && currentSource.empty()))
|
||||
sources[currentSourceName] = std::move(currentSource);
|
||||
currentSource = {};
|
||||
currentSourceName = boost::trim_copy(line.substr(
|
||||
sourceDelimiterStart.size(),
|
||||
line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size()
|
||||
));
|
||||
if (sources.count(currentSourceName))
|
||||
throw runtime_error("Multiple definitions of test source \"" + currentSourceName + "\".");
|
||||
}
|
||||
else
|
||||
currentSource += line + "\n";
|
||||
}
|
||||
else if (boost::algorithm::starts_with(line, comment))
|
||||
{
|
||||
size_t colon = line.find(':');
|
||||
if (colon == string::npos)
|
||||
throw runtime_error(string("Expected \":\" inside setting."));
|
||||
string key = line.substr(comment.size(), colon - comment.size());
|
||||
string value = line.substr(colon + 1);
|
||||
boost::algorithm::trim(key);
|
||||
boost::algorithm::trim(value);
|
||||
m_settings[key] = value;
|
||||
}
|
||||
else
|
||||
throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source."));
|
||||
}
|
||||
sources[currentSourceName] = currentSource;
|
||||
return {sources, lineNumber};
|
||||
}
|
||||
|
||||
map<string, string> TestCase::parseSourcesAndSettings(istream& _stream)
|
||||
{
|
||||
return get<0>(parseSourcesAndSettingsWithLineNumbers(_stream));
|
||||
}
|
||||
|
||||
pair<string, size_t> TestCase::parseSourceAndSettingsWithLineNumbers(istream& _stream)
|
||||
{
|
||||
auto [sourceMap, lineOffset] = parseSourcesAndSettingsWithLineNumbers(_stream);
|
||||
if (sourceMap.size() != 1)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources."));
|
||||
return {std::move(sourceMap.begin()->second), lineOffset};
|
||||
}
|
||||
|
||||
string TestCase::parseSourceAndSettings(istream& _stream)
|
||||
{
|
||||
return parseSourceAndSettingsWithLineNumbers(_stream).first;
|
||||
}
|
||||
|
||||
string TestCase::parseSimpleExpectations(std::istream& _file)
|
||||
{
|
||||
string result;
|
||||
string line;
|
||||
while (getline(_file, line))
|
||||
if (boost::algorithm::starts_with(line, "// "))
|
||||
result += line.substr(3) + "\n";
|
||||
else if (line == "//")
|
||||
result += "\n";
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Test expectations must start with \"// \"."));
|
||||
return result;
|
||||
}
|
||||
|
||||
void TestCase::expect(string::iterator& _it, string::iterator _end, string::value_type _c)
|
||||
{
|
||||
if (_it == _end || *_it != _c)
|
||||
@ -162,19 +60,13 @@ void TestCase::expect(string::iterator& _it, string::iterator _end, string::valu
|
||||
++_it;
|
||||
}
|
||||
|
||||
void EVMVersionRestrictedTestCase::validateSettings()
|
||||
EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filename):
|
||||
TestCase(_filename)
|
||||
{
|
||||
if (!m_settings.count("EVMVersion"))
|
||||
if (!m_reader.hasSetting("EVMVersion"))
|
||||
return;
|
||||
|
||||
string versionString = m_settings["EVMVersion"];
|
||||
m_validatedSettings["EVMVersion"] = versionString;
|
||||
m_settings.erase("EVMVersion");
|
||||
|
||||
TestCase::validateSettings();
|
||||
|
||||
if (versionString.empty())
|
||||
return;
|
||||
string versionString = m_reader.stringSetting("EVMVersion", "");
|
||||
|
||||
string comparator;
|
||||
size_t versionBegin = 0;
|
||||
|
@ -17,16 +17,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <test/TestCaseReader.h>
|
||||
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace solidity::frontend::test
|
||||
{
|
||||
@ -68,23 +65,19 @@ public:
|
||||
|
||||
static bool isTestFilename(boost::filesystem::path const& _filename);
|
||||
|
||||
/// Validates the settings, i.e. moves them from m_settings to m_validatedSettings.
|
||||
/// Throws a runtime exception if any setting is left at this class (i.e. unknown setting).
|
||||
virtual void validateSettings();
|
||||
|
||||
/// Returns true, if the test case is supported in the current environment and false
|
||||
/// otherwise which causes this test to be skipped.
|
||||
/// This might check e.g. for restrictions on the EVM version.
|
||||
/// The function throws an exception if there are unread settings.
|
||||
bool shouldRun();
|
||||
|
||||
protected:
|
||||
std::pair<std::map<std::string, std::string>, std::size_t> parseSourcesAndSettingsWithLineNumbers(std::istream& _file);
|
||||
std::map<std::string, std::string> parseSourcesAndSettings(std::istream& _file);
|
||||
std::pair<std::string, std::size_t> parseSourceAndSettingsWithLineNumbers(std::istream& _file);
|
||||
std::string parseSourceAndSettings(std::istream& _file);
|
||||
static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c);
|
||||
// Used by ASTJSONTest, the only TestCase class with a custom parser of the test files.
|
||||
TestCase() = default;
|
||||
|
||||
static std::string parseSimpleExpectations(std::istream& _file);
|
||||
TestCase(std::string const& _filename): m_reader(_filename) {}
|
||||
|
||||
static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c);
|
||||
|
||||
template<typename IteratorType>
|
||||
static void skipWhitespace(IteratorType& _it, IteratorType _end)
|
||||
@ -100,18 +93,14 @@ protected:
|
||||
++_it;
|
||||
}
|
||||
|
||||
/// Parsed settings.
|
||||
std::map<std::string, std::string> m_settings;
|
||||
/// Updated settings after validation.
|
||||
std::map<std::string, std::string> m_validatedSettings;
|
||||
|
||||
TestCaseReader m_reader;
|
||||
bool m_shouldRun = true;
|
||||
};
|
||||
|
||||
class EVMVersionRestrictedTestCase: public TestCase
|
||||
{
|
||||
public:
|
||||
void validateSettings() override;
|
||||
protected:
|
||||
EVMVersionRestrictedTestCase(std::string const& _filename);
|
||||
};
|
||||
|
||||
}
|
||||
|
174
test/TestCaseReader.cpp
Normal file
174
test/TestCaseReader.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <test/TestCaseReader.h>
|
||||
|
||||
#include <libsolutil/StringUtils.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::frontend::test;
|
||||
|
||||
TestCaseReader::TestCaseReader(string const& _filename):
|
||||
m_file(_filename)
|
||||
{
|
||||
if (!m_file)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open file: \"" + _filename + "\"."));
|
||||
m_file.exceptions(ios::badbit);
|
||||
|
||||
tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber(m_file);
|
||||
m_unreadSettings = m_settings;
|
||||
}
|
||||
|
||||
string const& TestCaseReader::source()
|
||||
{
|
||||
if (m_sources.size() != 1)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources."));
|
||||
return m_sources.begin()->second;
|
||||
}
|
||||
|
||||
string TestCaseReader::simpleExpectations()
|
||||
{
|
||||
return parseSimpleExpectations(m_file);
|
||||
}
|
||||
|
||||
bool TestCaseReader::hasSetting(std::string const& _name) const
|
||||
{
|
||||
return m_settings.count(_name) != 0;
|
||||
}
|
||||
|
||||
bool TestCaseReader::boolSetting(std::string const& _name, bool _defaultValue)
|
||||
{
|
||||
if (!hasSetting(_name))
|
||||
return _defaultValue;
|
||||
|
||||
m_unreadSettings.erase(_name);
|
||||
string value = m_settings.at(_name);
|
||||
if (value == "false")
|
||||
return false;
|
||||
if (value == "true")
|
||||
return true;
|
||||
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Invalid Boolean value: " + value + "."));
|
||||
}
|
||||
|
||||
size_t TestCaseReader::sizetSetting(std::string const& _name, size_t _defaultValue)
|
||||
{
|
||||
if (!hasSetting(_name))
|
||||
return _defaultValue;
|
||||
|
||||
m_unreadSettings.erase(_name);
|
||||
|
||||
static_assert(sizeof(unsigned long) <= sizeof(size_t));
|
||||
return stoul(m_settings.at(_name));
|
||||
}
|
||||
|
||||
string TestCaseReader::stringSetting(string const& _name, string const& _defaultValue)
|
||||
{
|
||||
if (!hasSetting(_name))
|
||||
return _defaultValue;
|
||||
|
||||
m_unreadSettings.erase(_name);
|
||||
return m_settings.at(_name);
|
||||
}
|
||||
|
||||
void TestCaseReader::setSetting(std::string const& _name, std::string const& _value)
|
||||
{
|
||||
m_settings[_name] = _value;
|
||||
}
|
||||
|
||||
void TestCaseReader::ensureAllSettingsRead() const
|
||||
{
|
||||
if (!m_unreadSettings.empty())
|
||||
throw runtime_error(
|
||||
"Unknown setting(s): " +
|
||||
util::joinHumanReadable(m_unreadSettings | boost::adaptors::map_keys)
|
||||
);
|
||||
}
|
||||
|
||||
pair<map<string, string>, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream)
|
||||
{
|
||||
map<string, string> sources;
|
||||
string currentSourceName;
|
||||
string currentSource;
|
||||
string line;
|
||||
size_t lineNumber = 1;
|
||||
static string const sourceDelimiterStart("==== Source:");
|
||||
static string const sourceDelimiterEnd("====");
|
||||
static string const comment("// ");
|
||||
static string const settingsDelimiter("// ====");
|
||||
static string const delimiter("// ----");
|
||||
bool sourcePart = true;
|
||||
while (getline(_stream, line))
|
||||
{
|
||||
lineNumber++;
|
||||
|
||||
if (boost::algorithm::starts_with(line, delimiter))
|
||||
break;
|
||||
else if (boost::algorithm::starts_with(line, settingsDelimiter))
|
||||
sourcePart = false;
|
||||
else if (sourcePart)
|
||||
{
|
||||
if (boost::algorithm::starts_with(line, sourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd))
|
||||
{
|
||||
if (!(currentSourceName.empty() && currentSource.empty()))
|
||||
sources[currentSourceName] = std::move(currentSource);
|
||||
currentSource = {};
|
||||
currentSourceName = boost::trim_copy(line.substr(
|
||||
sourceDelimiterStart.size(),
|
||||
line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size()
|
||||
));
|
||||
if (sources.count(currentSourceName))
|
||||
throw runtime_error("Multiple definitions of test source \"" + currentSourceName + "\".");
|
||||
}
|
||||
else
|
||||
currentSource += line + "\n";
|
||||
}
|
||||
else if (boost::algorithm::starts_with(line, comment))
|
||||
{
|
||||
size_t colon = line.find(':');
|
||||
if (colon == string::npos)
|
||||
throw runtime_error(string("Expected \":\" inside setting."));
|
||||
string key = line.substr(comment.size(), colon - comment.size());
|
||||
string value = line.substr(colon + 1);
|
||||
boost::algorithm::trim(key);
|
||||
boost::algorithm::trim(value);
|
||||
m_settings[key] = value;
|
||||
}
|
||||
else
|
||||
throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source."));
|
||||
}
|
||||
sources[currentSourceName] = currentSource;
|
||||
return { sources, lineNumber };
|
||||
}
|
||||
|
||||
string TestCaseReader::parseSimpleExpectations(istream& _file)
|
||||
{
|
||||
string result;
|
||||
string line;
|
||||
while (getline(_file, line))
|
||||
if (boost::algorithm::starts_with(line, "// "))
|
||||
result += line.substr(3) + "\n";
|
||||
else if (line == "//")
|
||||
result += "\n";
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Test expectations must start with \"// \"."));
|
||||
return result;
|
||||
}
|
61
test/TestCaseReader.h
Normal file
61
test/TestCaseReader.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace solidity::frontend::test
|
||||
{
|
||||
/**
|
||||
* A reader for test case data file, which parses source, settings and (optionally) simple expectations.
|
||||
*/
|
||||
class TestCaseReader
|
||||
{
|
||||
public:
|
||||
TestCaseReader() = default;
|
||||
explicit TestCaseReader(std::string const& _filename);
|
||||
|
||||
std::map<std::string, std::string> const& sources() { return m_sources; }
|
||||
std::string const& source();
|
||||
std::size_t lineNumber() { return m_lineNumber; }
|
||||
std::map<std::string, std::string> const& settings() { return m_settings; }
|
||||
std::ifstream& stream() { return m_file; }
|
||||
|
||||
std::string simpleExpectations();
|
||||
|
||||
bool hasSetting(std::string const& _name) const;
|
||||
bool boolSetting(std::string const& _name, bool _defaultValue);
|
||||
size_t sizetSetting(std::string const& _name, size_t _defaultValue);
|
||||
std::string stringSetting(std::string const& _name, std::string const& _defaultValue);
|
||||
void setSetting(std::string const& _name, std::string const& _value);
|
||||
|
||||
void ensureAllSettingsRead() const;
|
||||
|
||||
private:
|
||||
std::pair<std::map<std::string, std::string>, std::size_t> parseSourcesAndSettingsWithLineNumber(std::istream& _file);
|
||||
static std::string parseSimpleExpectations(std::istream& _file);
|
||||
|
||||
std::ifstream m_file;
|
||||
std::map<std::string, std::string> m_sources;
|
||||
std::size_t m_lineNumber = 0;
|
||||
std::map<std::string, std::string> m_settings;
|
||||
std::map<std::string, std::string> m_unreadSettings; ///< tracks which settings are left unread
|
||||
};
|
||||
}
|
@ -94,7 +94,6 @@ int registerTests(
|
||||
{
|
||||
stringstream errorStream;
|
||||
auto testCase = _testCaseCreator(config);
|
||||
testCase->validateSettings();
|
||||
if (testCase->shouldRun())
|
||||
switch (testCase->run(errorStream))
|
||||
{
|
||||
|
@ -36,15 +36,11 @@ using namespace solidity::util;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::test;
|
||||
|
||||
ABIJsonTest::ABIJsonTest(string const& _filename)
|
||||
ABIJsonTest::ABIJsonTest(string const& _filename):
|
||||
TestCase(_filename)
|
||||
{
|
||||
ifstream file(_filename);
|
||||
if (!file)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
|
||||
file.exceptions(ios::badbit);
|
||||
|
||||
m_source = parseSourceAndSettings(file);
|
||||
m_expectation = parseSimpleExpectations(file);
|
||||
m_source = m_reader.source();
|
||||
m_expectation = m_reader.simpleExpectations();
|
||||
}
|
||||
|
||||
TestCase::TestResult ABIJsonTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||
|
@ -36,35 +36,14 @@ using namespace std;
|
||||
namespace fs = boost::filesystem;
|
||||
using namespace boost::unit_test;
|
||||
|
||||
GasTest::GasTest(string const& _filename)
|
||||
GasTest::GasTest(string const& _filename):
|
||||
TestCase(_filename)
|
||||
{
|
||||
ifstream file(_filename);
|
||||
if (!file)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
|
||||
file.exceptions(ios::badbit);
|
||||
|
||||
m_source = parseSourceAndSettings(file);
|
||||
|
||||
if (m_settings.count("optimize"))
|
||||
{
|
||||
m_optimise = true;
|
||||
m_validatedSettings["optimize"] = "true";
|
||||
m_settings.erase("optimize");
|
||||
}
|
||||
if (m_settings.count("optimize-yul"))
|
||||
{
|
||||
m_optimiseYul = true;
|
||||
m_validatedSettings["optimize-yul"] = "true";
|
||||
m_settings.erase("optimize-yul");
|
||||
}
|
||||
if (m_settings.count("optimize-runs"))
|
||||
{
|
||||
m_optimiseRuns = stoul(m_settings["optimize-runs"]);
|
||||
m_validatedSettings["optimize-runs"] = m_settings["optimize-runs"];
|
||||
m_settings.erase("optimize-runs");
|
||||
}
|
||||
|
||||
parseExpectations(file);
|
||||
m_source = m_reader.source();
|
||||
m_optimise = m_reader.boolSetting("optimize", false);
|
||||
m_optimiseYul = m_reader.boolSetting("optimize-yul", false);
|
||||
m_optimiseRuns = m_reader.sizetSetting("optimize-runs", 200);
|
||||
parseExpectations(m_reader.stream());
|
||||
}
|
||||
|
||||
void GasTest::parseExpectations(std::istream& _stream)
|
||||
|
@ -28,22 +28,17 @@ using namespace solidity::frontend::test;
|
||||
|
||||
SMTCheckerTest::SMTCheckerTest(string const& _filename, langutil::EVMVersion _evmVersion): SyntaxTest(_filename, _evmVersion)
|
||||
{
|
||||
if (m_settings.count("SMTSolvers"))
|
||||
{
|
||||
auto const& choice = m_settings.at("SMTSolvers");
|
||||
if (choice == "any")
|
||||
m_enabledSolvers = smt::SMTSolverChoice::All();
|
||||
else if (choice == "z3")
|
||||
m_enabledSolvers = smt::SMTSolverChoice::Z3();
|
||||
else if (choice == "cvc4")
|
||||
m_enabledSolvers = smt::SMTSolverChoice::CVC4();
|
||||
else if (choice == "none")
|
||||
m_enabledSolvers = smt::SMTSolverChoice::None();
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT solver choice."));
|
||||
}
|
||||
else
|
||||
auto const& choice = m_reader.stringSetting("SMTSolvers", "any");
|
||||
if (choice == "any")
|
||||
m_enabledSolvers = smt::SMTSolverChoice::All();
|
||||
else if (choice == "z3")
|
||||
m_enabledSolvers = smt::SMTSolverChoice::Z3();
|
||||
else if (choice == "cvc4")
|
||||
m_enabledSolvers = smt::SMTSolverChoice::CVC4();
|
||||
else if (choice == "none")
|
||||
m_enabledSolvers = smt::SMTSolverChoice::None();
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT solver choice."));
|
||||
|
||||
auto available = ModelChecker::availableSolvers();
|
||||
if (!available.z3)
|
||||
|
@ -37,59 +37,39 @@ namespace fs = boost::filesystem;
|
||||
|
||||
|
||||
SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion):
|
||||
SolidityExecutionFramework(_evmVersion)
|
||||
SolidityExecutionFramework(_evmVersion),
|
||||
EVMVersionRestrictedTestCase(_filename)
|
||||
{
|
||||
ifstream file(_filename);
|
||||
soltestAssert(file, "Cannot open test contract: \"" + _filename + "\".");
|
||||
file.exceptions(ios::badbit);
|
||||
m_source = m_reader.source();
|
||||
m_lineOffset = m_reader.lineNumber();
|
||||
|
||||
std::tie(m_source, m_lineOffset) = parseSourceAndSettingsWithLineNumbers(file);
|
||||
|
||||
if (m_settings.count("compileViaYul"))
|
||||
if (m_reader.hasSetting("compileViaYul"))
|
||||
{
|
||||
if (m_settings["compileViaYul"] == "also")
|
||||
string choice = m_reader.stringSetting("compileViaYul", "");
|
||||
if (choice == "also")
|
||||
{
|
||||
m_validatedSettings["compileViaYul"] = m_settings["compileViaYul"];
|
||||
m_runWithYul = true;
|
||||
m_runWithoutYul = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_validatedSettings["compileViaYul"] = "only";
|
||||
m_reader.setSetting("compileViaYul", "only");
|
||||
m_runWithYul = true;
|
||||
m_runWithoutYul = false;
|
||||
}
|
||||
m_settings.erase("compileViaYul");
|
||||
}
|
||||
if (m_settings.count("ABIEncoderV1Only"))
|
||||
{
|
||||
if (m_settings["ABIEncoderV1Only"] == "true")
|
||||
{
|
||||
m_validatedSettings["ABIEncoderV1Only"] = "true";
|
||||
m_runWithABIEncoderV1Only = true;
|
||||
}
|
||||
m_settings.erase("ABIEncoderV1Only");
|
||||
}
|
||||
|
||||
m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false);
|
||||
if (m_runWithABIEncoderV1Only && solidity::test::CommonOptions::get().useABIEncoderV2)
|
||||
m_shouldRun = false;
|
||||
|
||||
if (m_settings.count("revertStrings"))
|
||||
{
|
||||
auto revertStrings = revertStringsFromString(m_settings["revertStrings"]);
|
||||
if (revertStrings)
|
||||
m_revertStrings = *revertStrings;
|
||||
m_validatedSettings["revertStrings"] = revertStringsToString(m_revertStrings);
|
||||
m_settings.erase("revertStrings");
|
||||
}
|
||||
auto revertStrings = revertStringsFromString(m_reader.stringSetting("revertStrings", "default"));
|
||||
soltestAssert(revertStrings, "Invalid revertStrings setting.");
|
||||
m_revertStrings = revertStrings.value();
|
||||
|
||||
if (m_settings.count("allowNonExistingFunctions"))
|
||||
{
|
||||
m_validatedSettings["allowNonExistingFunctions"] = true;
|
||||
m_settings.erase("allowNonExistingFunctions");
|
||||
}
|
||||
m_allowNonExistingFunctions = m_reader.boolSetting("allowNonExistingFunctions", false);
|
||||
|
||||
parseExpectations(file);
|
||||
parseExpectations(m_reader.stream());
|
||||
soltestAssert(!m_tests.empty(), "No tests specified in " + _filename);
|
||||
}
|
||||
|
||||
@ -152,7 +132,7 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref
|
||||
else
|
||||
{
|
||||
soltestAssert(
|
||||
m_validatedSettings.count("allowNonExistingFunctions") || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature),
|
||||
m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature),
|
||||
"The function " + test.call().signature + " is not known to the compiler"
|
||||
);
|
||||
|
||||
|
@ -65,6 +65,7 @@ private:
|
||||
bool m_runWithYul = false;
|
||||
bool m_runWithoutYul = true;
|
||||
bool m_runWithABIEncoderV1Only = false;
|
||||
bool m_allowNonExistingFunctions = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -37,20 +37,7 @@ namespace fs = boost::filesystem;
|
||||
|
||||
SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion, bool _parserErrorRecovery): CommonSyntaxTest(_filename, _evmVersion)
|
||||
{
|
||||
if (m_settings.count("optimize-yul"))
|
||||
{
|
||||
if (m_settings["optimize-yul"] == "true")
|
||||
{
|
||||
m_validatedSettings["optimize-yul"] = "true";
|
||||
m_settings.erase("optimize-yul");
|
||||
}
|
||||
else if (m_settings["optimize-yul"] == "false")
|
||||
{
|
||||
m_validatedSettings["optimize-yul"] = "false";
|
||||
m_settings.erase("optimize-yul");
|
||||
m_optimiseYul = false;
|
||||
}
|
||||
}
|
||||
m_optimiseYul = m_reader.boolSetting("optimize-yul", true);
|
||||
m_parserErrorRecovery = _parserErrorRecovery;
|
||||
}
|
||||
|
||||
|
@ -48,17 +48,11 @@ using namespace solidity::frontend::test;
|
||||
using namespace std;
|
||||
|
||||
|
||||
EwasmTranslationTest::EwasmTranslationTest(string const& _filename)
|
||||
EwasmTranslationTest::EwasmTranslationTest(string const& _filename):
|
||||
EVMVersionRestrictedTestCase(_filename)
|
||||
{
|
||||
boost::filesystem::path path(_filename);
|
||||
|
||||
ifstream file(_filename);
|
||||
if (!file)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\"."));
|
||||
file.exceptions(ios::badbit);
|
||||
|
||||
m_source = parseSourceAndSettings(file);
|
||||
m_expectation = parseSimpleExpectations(file);
|
||||
m_source = m_reader.source();
|
||||
m_expectation = m_reader.simpleExpectations();
|
||||
}
|
||||
|
||||
TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||
|
@ -60,15 +60,11 @@ string toString(SideEffects const& _sideEffects)
|
||||
}
|
||||
}
|
||||
|
||||
FunctionSideEffects::FunctionSideEffects(string const& _filename)
|
||||
FunctionSideEffects::FunctionSideEffects(string const& _filename):
|
||||
TestCase(_filename)
|
||||
{
|
||||
ifstream file(_filename);
|
||||
if (!file)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test input: \"" + _filename + "\"."));
|
||||
file.exceptions(ios::badbit);
|
||||
|
||||
m_source = parseSourceAndSettings(file);
|
||||
m_expectation = parseSimpleExpectations(file);
|
||||
m_source = m_reader.source();
|
||||
m_expectation = m_reader.simpleExpectations();
|
||||
}
|
||||
|
||||
TestCase::TestResult FunctionSideEffects::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||
|
@ -38,23 +38,12 @@ using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::test;
|
||||
using namespace std;
|
||||
|
||||
ObjectCompilerTest::ObjectCompilerTest(string const& _filename)
|
||||
ObjectCompilerTest::ObjectCompilerTest(string const& _filename):
|
||||
TestCase(_filename)
|
||||
{
|
||||
boost::filesystem::path path(_filename);
|
||||
|
||||
ifstream file(_filename);
|
||||
if (!file)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\"."));
|
||||
file.exceptions(ios::badbit);
|
||||
|
||||
m_source = parseSourceAndSettings(file);
|
||||
if (m_settings.count("optimize"))
|
||||
{
|
||||
m_optimize = true;
|
||||
m_validatedSettings["optimize"] = "true";
|
||||
m_settings.erase("optimize");
|
||||
}
|
||||
m_expectation = parseSimpleExpectations(file);
|
||||
m_source = m_reader.source();
|
||||
m_optimize = m_reader.boolSetting("optimize", false);
|
||||
m_expectation = m_reader.simpleExpectations();
|
||||
}
|
||||
|
||||
TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||
|
@ -70,9 +70,7 @@ vector<string> validDialectNames()
|
||||
|
||||
void SyntaxTest::parseAndAnalyze()
|
||||
{
|
||||
string dialectName = m_validatedSettings.count("dialect") ? m_validatedSettings["dialect"] : "evmTyped";
|
||||
|
||||
yul::Dialect const& dialect = validDialects.at(dialectName)(m_evmVersion);
|
||||
yul::Dialect const& dialect = validDialects.at(m_dialectName)(m_evmVersion);
|
||||
|
||||
if (m_sources.size() != 1)
|
||||
BOOST_THROW_EXCEPTION(runtime_error{"Expected only one source for yul test."});
|
||||
@ -114,21 +112,15 @@ void SyntaxTest::parseAndAnalyze()
|
||||
|
||||
}
|
||||
|
||||
void SyntaxTest::validateSettings()
|
||||
SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion):
|
||||
CommonSyntaxTest(_filename, _evmVersion)
|
||||
{
|
||||
CommonSyntaxTest::validateSettings();
|
||||
m_dialectName = m_reader.stringSetting("dialect", "evmTyped");
|
||||
|
||||
if (!m_settings.count("dialect"))
|
||||
return;
|
||||
|
||||
string const dialect = m_settings["dialect"];
|
||||
m_validatedSettings["dialect"] = dialect;
|
||||
m_settings.erase("dialect");
|
||||
|
||||
if (!validDialects.count(dialect))
|
||||
if (!validDialects.count(m_dialectName))
|
||||
BOOST_THROW_EXCEPTION(runtime_error{
|
||||
"Invalid Dialect \"" +
|
||||
dialect +
|
||||
m_dialectName +
|
||||
"\". Valid dialects are " +
|
||||
joinHumanReadable(validDialectNames(), ", ", " and ") +
|
||||
"."
|
||||
|
@ -36,15 +36,13 @@ public:
|
||||
{
|
||||
return std::make_unique<SyntaxTest>(_config.filename, _config.evmVersion);
|
||||
}
|
||||
SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion):
|
||||
CommonSyntaxTest(_filename, _evmVersion) {}
|
||||
SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion);
|
||||
virtual ~SyntaxTest() {}
|
||||
|
||||
/// Validates the settings, i.e. moves them from m_settings to m_validatedSettings.
|
||||
/// Throws a runtime exception if any setting is left at this class (i.e. unknown setting).
|
||||
void validateSettings() override;
|
||||
protected:
|
||||
void parseAndAnalyze() override;
|
||||
|
||||
private:
|
||||
std::string m_dialectName;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -45,17 +45,11 @@ using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::test;
|
||||
using namespace std;
|
||||
|
||||
YulInterpreterTest::YulInterpreterTest(string const& _filename)
|
||||
YulInterpreterTest::YulInterpreterTest(string const& _filename):
|
||||
EVMVersionRestrictedTestCase(_filename)
|
||||
{
|
||||
boost::filesystem::path path(_filename);
|
||||
|
||||
ifstream file(_filename);
|
||||
if (!file)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\"."));
|
||||
file.exceptions(ios::badbit);
|
||||
|
||||
m_source = parseSourceAndSettings(file);
|
||||
m_expectation = parseSimpleExpectations(file);
|
||||
m_source = m_reader.source();
|
||||
m_expectation = m_reader.simpleExpectations();
|
||||
}
|
||||
|
||||
TestCase::TestResult YulInterpreterTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||
|
@ -89,7 +89,8 @@ using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::test;
|
||||
using namespace std;
|
||||
|
||||
YulOptimizerTest::YulOptimizerTest(string const& _filename)
|
||||
YulOptimizerTest::YulOptimizerTest(string const& _filename):
|
||||
EVMVersionRestrictedTestCase(_filename)
|
||||
{
|
||||
boost::filesystem::path path(_filename);
|
||||
|
||||
@ -97,38 +98,23 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Filename path has to contain a directory: \"" + _filename + "\"."));
|
||||
m_optimizerStep = std::prev(std::prev(path.end()))->string();
|
||||
|
||||
ifstream file(_filename);
|
||||
soltestAssert(file, "Cannot open test contract: \"" + _filename + "\".");
|
||||
file.exceptions(ios::badbit);
|
||||
m_source = m_reader.source();
|
||||
|
||||
m_source = parseSourceAndSettings(file);
|
||||
if (m_settings.count("dialect"))
|
||||
{
|
||||
auto dialectName = m_settings["dialect"];
|
||||
if (dialectName == "yul")
|
||||
m_dialect = &Dialect::yulDeprecated();
|
||||
else if (dialectName == "ewasm")
|
||||
m_dialect = &WasmDialect::instance();
|
||||
else if (dialectName == "evm")
|
||||
m_dialect = &EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion());
|
||||
else if (dialectName == "evmTyped")
|
||||
m_dialect = &EVMDialectTyped::instance(solidity::test::CommonOptions::get().evmVersion());
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Invalid dialect " + dialectName));
|
||||
|
||||
m_validatedSettings["dialect"] = dialectName;
|
||||
m_settings.erase("dialect");
|
||||
}
|
||||
else
|
||||
auto dialectName = m_reader.stringSetting("dialect", "evm");
|
||||
if (dialectName == "yul")
|
||||
m_dialect = &Dialect::yulDeprecated();
|
||||
else if (dialectName == "ewasm")
|
||||
m_dialect = &WasmDialect::instance();
|
||||
else if (dialectName == "evm")
|
||||
m_dialect = &EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion());
|
||||
else if (dialectName == "evmTyped")
|
||||
m_dialect = &EVMDialectTyped::instance(solidity::test::CommonOptions::get().evmVersion());
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Invalid dialect " + dialectName));
|
||||
|
||||
if (m_settings.count("step"))
|
||||
{
|
||||
m_validatedSettings["step"] = m_settings["step"];
|
||||
m_settings.erase("step");
|
||||
}
|
||||
m_step = m_reader.stringSetting("step", "");
|
||||
|
||||
m_expectation = parseSimpleExpectations(file);
|
||||
m_expectation = m_reader.simpleExpectations();
|
||||
}
|
||||
|
||||
TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||
@ -377,13 +363,13 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
||||
|
||||
m_obtainedResult = AsmPrinter{*m_dialect}(*m_ast) + "\n";
|
||||
|
||||
if (m_optimizerStep != m_validatedSettings["step"])
|
||||
if (m_optimizerStep != m_step)
|
||||
{
|
||||
string nextIndentLevel = _linePrefix + " ";
|
||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) <<
|
||||
_linePrefix <<
|
||||
"Invalid optimizer step. Given: \"" <<
|
||||
m_validatedSettings["step"] <<
|
||||
m_step <<
|
||||
"\", should be: \"" <<
|
||||
m_optimizerStep <<
|
||||
"\"." <<
|
||||
@ -410,7 +396,8 @@ void YulOptimizerTest::printSource(ostream& _stream, string const& _linePrefix,
|
||||
|
||||
void YulOptimizerTest::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool _formatted)
|
||||
{
|
||||
m_validatedSettings["step"] = m_optimizerStep;
|
||||
m_step = m_optimizerStep;
|
||||
m_reader.setSetting("step", m_step);
|
||||
EVMVersionRestrictedTestCase::printUpdatedSettings(_stream, _linePrefix, _formatted);
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@ private:
|
||||
std::string m_expectation;
|
||||
|
||||
Dialect const* m_dialect = nullptr;
|
||||
std::string m_step;
|
||||
std::set<YulString> m_reservedIdentifiers;
|
||||
std::unique_ptr<NameDispenser> m_nameDispenser;
|
||||
std::unique_ptr<OptimiserStepContext> m_context;
|
||||
|
@ -17,6 +17,7 @@ add_executable(isoltest
|
||||
../CommonSyntaxTest.cpp
|
||||
../EVMHost.cpp
|
||||
../TestCase.cpp
|
||||
../TestCaseReader.cpp
|
||||
../libsolidity/util/BytesUtils.cpp
|
||||
../libsolidity/util/ContractABIUtils.cpp
|
||||
../libsolidity/util/TestFileParser.cpp
|
||||
|
@ -161,7 +161,6 @@ TestTool::Result TestTool::process()
|
||||
(AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush();
|
||||
|
||||
m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.evmVersion()});
|
||||
m_test->validateSettings();
|
||||
if (m_test->shouldRun())
|
||||
switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted))
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user