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})
|
for (auto i: {RevertStrings::Default, RevertStrings::Strip, RevertStrings::Debug, RevertStrings::VerboseDebug})
|
||||||
if (revertStringsToString(i) == _str)
|
if (revertStringsToString(i) == _str)
|
||||||
return i;
|
return i;
|
||||||
return {};
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ set(sources
|
|||||||
Metadata.h
|
Metadata.h
|
||||||
TestCase.cpp
|
TestCase.cpp
|
||||||
TestCase.h
|
TestCase.h
|
||||||
|
TestCaseReader.cpp
|
||||||
|
TestCaseReader.h
|
||||||
)
|
)
|
||||||
detect_stray_source_files("${sources}" ".")
|
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);
|
m_sources = m_reader.sources();
|
||||||
if (!file)
|
m_expectations = parseExpectations(m_reader.stream());
|
||||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
|
|
||||||
file.exceptions(ios::badbit);
|
|
||||||
|
|
||||||
m_sources = parseSourcesAndSettings(file);
|
|
||||||
|
|
||||||
m_expectations = parseExpectations(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||||
|
@ -18,16 +18,9 @@
|
|||||||
#include <test/Common.h>
|
#include <test/Common.h>
|
||||||
#include <test/TestCase.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/predicate.hpp>
|
||||||
#include <boost/algorithm/string/trim.hpp>
|
|
||||||
#include <boost/range/adaptor/map.hpp>
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -37,11 +30,12 @@ using namespace solidity::frontend::test;
|
|||||||
|
|
||||||
void TestCase::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool)
|
void TestCase::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool)
|
||||||
{
|
{
|
||||||
if (m_validatedSettings.empty())
|
auto& settings = m_reader.settings();
|
||||||
|
if (settings.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_stream << _linePrefix << "// ====" << endl;
|
_stream << _linePrefix << "// ====" << endl;
|
||||||
for (auto const& setting: m_validatedSettings)
|
for (auto const& setting: settings)
|
||||||
_stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl;
|
_stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,108 +47,12 @@ bool TestCase::isTestFilename(boost::filesystem::path const& _filename)
|
|||||||
!boost::starts_with(_filename.string(), ".");
|
!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()
|
bool TestCase::shouldRun()
|
||||||
{
|
{
|
||||||
|
m_reader.ensureAllSettingsRead();
|
||||||
return m_shouldRun;
|
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)
|
void TestCase::expect(string::iterator& _it, string::iterator _end, string::value_type _c)
|
||||||
{
|
{
|
||||||
if (_it == _end || *_it != _c)
|
if (_it == _end || *_it != _c)
|
||||||
@ -162,19 +60,13 @@ void TestCase::expect(string::iterator& _it, string::iterator _end, string::valu
|
|||||||
++_it;
|
++_it;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EVMVersionRestrictedTestCase::validateSettings()
|
EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filename):
|
||||||
|
TestCase(_filename)
|
||||||
{
|
{
|
||||||
if (!m_settings.count("EVMVersion"))
|
if (!m_reader.hasSetting("EVMVersion"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string versionString = m_settings["EVMVersion"];
|
string versionString = m_reader.stringSetting("EVMVersion", "");
|
||||||
m_validatedSettings["EVMVersion"] = versionString;
|
|
||||||
m_settings.erase("EVMVersion");
|
|
||||||
|
|
||||||
TestCase::validateSettings();
|
|
||||||
|
|
||||||
if (versionString.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
string comparator;
|
string comparator;
|
||||||
size_t versionBegin = 0;
|
size_t versionBegin = 0;
|
||||||
|
@ -17,16 +17,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <test/TestCaseReader.h>
|
||||||
|
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace solidity::frontend::test
|
namespace solidity::frontend::test
|
||||||
{
|
{
|
||||||
@ -68,23 +65,19 @@ public:
|
|||||||
|
|
||||||
static bool isTestFilename(boost::filesystem::path const& _filename);
|
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
|
/// Returns true, if the test case is supported in the current environment and false
|
||||||
/// otherwise which causes this test to be skipped.
|
/// otherwise which causes this test to be skipped.
|
||||||
/// This might check e.g. for restrictions on the EVM version.
|
/// This might check e.g. for restrictions on the EVM version.
|
||||||
|
/// The function throws an exception if there are unread settings.
|
||||||
bool shouldRun();
|
bool shouldRun();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::pair<std::map<std::string, std::string>, std::size_t> parseSourcesAndSettingsWithLineNumbers(std::istream& _file);
|
// Used by ASTJSONTest, the only TestCase class with a custom parser of the test files.
|
||||||
std::map<std::string, std::string> parseSourcesAndSettings(std::istream& _file);
|
TestCase() = default;
|
||||||
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);
|
|
||||||
|
|
||||||
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>
|
template<typename IteratorType>
|
||||||
static void skipWhitespace(IteratorType& _it, IteratorType _end)
|
static void skipWhitespace(IteratorType& _it, IteratorType _end)
|
||||||
@ -100,18 +93,14 @@ protected:
|
|||||||
++_it;
|
++_it;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parsed settings.
|
TestCaseReader m_reader;
|
||||||
std::map<std::string, std::string> m_settings;
|
|
||||||
/// Updated settings after validation.
|
|
||||||
std::map<std::string, std::string> m_validatedSettings;
|
|
||||||
|
|
||||||
bool m_shouldRun = true;
|
bool m_shouldRun = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EVMVersionRestrictedTestCase: public TestCase
|
class EVMVersionRestrictedTestCase: public TestCase
|
||||||
{
|
{
|
||||||
public:
|
protected:
|
||||||
void validateSettings() override;
|
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;
|
stringstream errorStream;
|
||||||
auto testCase = _testCaseCreator(config);
|
auto testCase = _testCaseCreator(config);
|
||||||
testCase->validateSettings();
|
|
||||||
if (testCase->shouldRun())
|
if (testCase->shouldRun())
|
||||||
switch (testCase->run(errorStream))
|
switch (testCase->run(errorStream))
|
||||||
{
|
{
|
||||||
|
@ -36,15 +36,11 @@ using namespace solidity::util;
|
|||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
using namespace solidity::frontend::test;
|
using namespace solidity::frontend::test;
|
||||||
|
|
||||||
ABIJsonTest::ABIJsonTest(string const& _filename)
|
ABIJsonTest::ABIJsonTest(string const& _filename):
|
||||||
|
TestCase(_filename)
|
||||||
{
|
{
|
||||||
ifstream file(_filename);
|
m_source = m_reader.source();
|
||||||
if (!file)
|
m_expectation = m_reader.simpleExpectations();
|
||||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
|
|
||||||
file.exceptions(ios::badbit);
|
|
||||||
|
|
||||||
m_source = parseSourceAndSettings(file);
|
|
||||||
m_expectation = parseSimpleExpectations(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult ABIJsonTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
TestCase::TestResult ABIJsonTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||||
|
@ -36,35 +36,14 @@ using namespace std;
|
|||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
using namespace boost::unit_test;
|
using namespace boost::unit_test;
|
||||||
|
|
||||||
GasTest::GasTest(string const& _filename)
|
GasTest::GasTest(string const& _filename):
|
||||||
|
TestCase(_filename)
|
||||||
{
|
{
|
||||||
ifstream file(_filename);
|
m_source = m_reader.source();
|
||||||
if (!file)
|
m_optimise = m_reader.boolSetting("optimize", false);
|
||||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
|
m_optimiseYul = m_reader.boolSetting("optimize-yul", false);
|
||||||
file.exceptions(ios::badbit);
|
m_optimiseRuns = m_reader.sizetSetting("optimize-runs", 200);
|
||||||
|
parseExpectations(m_reader.stream());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GasTest::parseExpectations(std::istream& _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)
|
SMTCheckerTest::SMTCheckerTest(string const& _filename, langutil::EVMVersion _evmVersion): SyntaxTest(_filename, _evmVersion)
|
||||||
{
|
{
|
||||||
if (m_settings.count("SMTSolvers"))
|
auto const& choice = m_reader.stringSetting("SMTSolvers", "any");
|
||||||
{
|
if (choice == "any")
|
||||||
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
|
|
||||||
m_enabledSolvers = smt::SMTSolverChoice::All();
|
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();
|
auto available = ModelChecker::availableSolvers();
|
||||||
if (!available.z3)
|
if (!available.z3)
|
||||||
|
@ -37,59 +37,39 @@ namespace fs = boost::filesystem;
|
|||||||
|
|
||||||
|
|
||||||
SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion):
|
SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion):
|
||||||
SolidityExecutionFramework(_evmVersion)
|
SolidityExecutionFramework(_evmVersion),
|
||||||
|
EVMVersionRestrictedTestCase(_filename)
|
||||||
{
|
{
|
||||||
ifstream file(_filename);
|
m_source = m_reader.source();
|
||||||
soltestAssert(file, "Cannot open test contract: \"" + _filename + "\".");
|
m_lineOffset = m_reader.lineNumber();
|
||||||
file.exceptions(ios::badbit);
|
|
||||||
|
|
||||||
std::tie(m_source, m_lineOffset) = parseSourceAndSettingsWithLineNumbers(file);
|
if (m_reader.hasSetting("compileViaYul"))
|
||||||
|
|
||||||
if (m_settings.count("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_runWithYul = true;
|
||||||
m_runWithoutYul = true;
|
m_runWithoutYul = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_validatedSettings["compileViaYul"] = "only";
|
m_reader.setSetting("compileViaYul", "only");
|
||||||
m_runWithYul = true;
|
m_runWithYul = true;
|
||||||
m_runWithoutYul = false;
|
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)
|
if (m_runWithABIEncoderV1Only && solidity::test::CommonOptions::get().useABIEncoderV2)
|
||||||
m_shouldRun = false;
|
m_shouldRun = false;
|
||||||
|
|
||||||
if (m_settings.count("revertStrings"))
|
auto revertStrings = revertStringsFromString(m_reader.stringSetting("revertStrings", "default"));
|
||||||
{
|
soltestAssert(revertStrings, "Invalid revertStrings setting.");
|
||||||
auto revertStrings = revertStringsFromString(m_settings["revertStrings"]);
|
m_revertStrings = revertStrings.value();
|
||||||
if (revertStrings)
|
|
||||||
m_revertStrings = *revertStrings;
|
|
||||||
m_validatedSettings["revertStrings"] = revertStringsToString(m_revertStrings);
|
|
||||||
m_settings.erase("revertStrings");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_settings.count("allowNonExistingFunctions"))
|
m_allowNonExistingFunctions = m_reader.boolSetting("allowNonExistingFunctions", false);
|
||||||
{
|
|
||||||
m_validatedSettings["allowNonExistingFunctions"] = true;
|
|
||||||
m_settings.erase("allowNonExistingFunctions");
|
|
||||||
}
|
|
||||||
|
|
||||||
parseExpectations(file);
|
parseExpectations(m_reader.stream());
|
||||||
soltestAssert(!m_tests.empty(), "No tests specified in " + _filename);
|
soltestAssert(!m_tests.empty(), "No tests specified in " + _filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +132,7 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
soltestAssert(
|
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"
|
"The function " + test.call().signature + " is not known to the compiler"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ private:
|
|||||||
bool m_runWithYul = false;
|
bool m_runWithYul = false;
|
||||||
bool m_runWithoutYul = true;
|
bool m_runWithoutYul = true;
|
||||||
bool m_runWithABIEncoderV1Only = false;
|
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)
|
SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion, bool _parserErrorRecovery): CommonSyntaxTest(_filename, _evmVersion)
|
||||||
{
|
{
|
||||||
if (m_settings.count("optimize-yul"))
|
m_optimiseYul = m_reader.boolSetting("optimize-yul", true);
|
||||||
{
|
|
||||||
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_parserErrorRecovery = _parserErrorRecovery;
|
m_parserErrorRecovery = _parserErrorRecovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,17 +48,11 @@ using namespace solidity::frontend::test;
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
EwasmTranslationTest::EwasmTranslationTest(string const& _filename)
|
EwasmTranslationTest::EwasmTranslationTest(string const& _filename):
|
||||||
|
EVMVersionRestrictedTestCase(_filename)
|
||||||
{
|
{
|
||||||
boost::filesystem::path path(_filename);
|
m_source = m_reader.source();
|
||||||
|
m_expectation = m_reader.simpleExpectations();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
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);
|
m_source = m_reader.source();
|
||||||
if (!file)
|
m_expectation = m_reader.simpleExpectations();
|
||||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test input: \"" + _filename + "\"."));
|
|
||||||
file.exceptions(ios::badbit);
|
|
||||||
|
|
||||||
m_source = parseSourceAndSettings(file);
|
|
||||||
m_expectation = parseSimpleExpectations(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult FunctionSideEffects::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
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 solidity::frontend::test;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
ObjectCompilerTest::ObjectCompilerTest(string const& _filename)
|
ObjectCompilerTest::ObjectCompilerTest(string const& _filename):
|
||||||
|
TestCase(_filename)
|
||||||
{
|
{
|
||||||
boost::filesystem::path path(_filename);
|
m_source = m_reader.source();
|
||||||
|
m_optimize = m_reader.boolSetting("optimize", false);
|
||||||
ifstream file(_filename);
|
m_expectation = m_reader.simpleExpectations();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||||
|
@ -70,9 +70,7 @@ vector<string> validDialectNames()
|
|||||||
|
|
||||||
void SyntaxTest::parseAndAnalyze()
|
void SyntaxTest::parseAndAnalyze()
|
||||||
{
|
{
|
||||||
string dialectName = m_validatedSettings.count("dialect") ? m_validatedSettings["dialect"] : "evmTyped";
|
yul::Dialect const& dialect = validDialects.at(m_dialectName)(m_evmVersion);
|
||||||
|
|
||||||
yul::Dialect const& dialect = validDialects.at(dialectName)(m_evmVersion);
|
|
||||||
|
|
||||||
if (m_sources.size() != 1)
|
if (m_sources.size() != 1)
|
||||||
BOOST_THROW_EXCEPTION(runtime_error{"Expected only one source for yul test."});
|
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"))
|
if (!validDialects.count(m_dialectName))
|
||||||
return;
|
|
||||||
|
|
||||||
string const dialect = m_settings["dialect"];
|
|
||||||
m_validatedSettings["dialect"] = dialect;
|
|
||||||
m_settings.erase("dialect");
|
|
||||||
|
|
||||||
if (!validDialects.count(dialect))
|
|
||||||
BOOST_THROW_EXCEPTION(runtime_error{
|
BOOST_THROW_EXCEPTION(runtime_error{
|
||||||
"Invalid Dialect \"" +
|
"Invalid Dialect \"" +
|
||||||
dialect +
|
m_dialectName +
|
||||||
"\". Valid dialects are " +
|
"\". Valid dialects are " +
|
||||||
joinHumanReadable(validDialectNames(), ", ", " and ") +
|
joinHumanReadable(validDialectNames(), ", ", " and ") +
|
||||||
"."
|
"."
|
||||||
|
@ -36,15 +36,13 @@ public:
|
|||||||
{
|
{
|
||||||
return std::make_unique<SyntaxTest>(_config.filename, _config.evmVersion);
|
return std::make_unique<SyntaxTest>(_config.filename, _config.evmVersion);
|
||||||
}
|
}
|
||||||
SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion):
|
SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion);
|
||||||
CommonSyntaxTest(_filename, _evmVersion) {}
|
|
||||||
virtual ~SyntaxTest() {}
|
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:
|
protected:
|
||||||
void parseAndAnalyze() override;
|
void parseAndAnalyze() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_dialectName;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,17 +45,11 @@ using namespace solidity::frontend;
|
|||||||
using namespace solidity::frontend::test;
|
using namespace solidity::frontend::test;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
YulInterpreterTest::YulInterpreterTest(string const& _filename)
|
YulInterpreterTest::YulInterpreterTest(string const& _filename):
|
||||||
|
EVMVersionRestrictedTestCase(_filename)
|
||||||
{
|
{
|
||||||
boost::filesystem::path path(_filename);
|
m_source = m_reader.source();
|
||||||
|
m_expectation = m_reader.simpleExpectations();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult YulInterpreterTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
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 solidity::frontend::test;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
YulOptimizerTest::YulOptimizerTest(string const& _filename)
|
YulOptimizerTest::YulOptimizerTest(string const& _filename):
|
||||||
|
EVMVersionRestrictedTestCase(_filename)
|
||||||
{
|
{
|
||||||
boost::filesystem::path path(_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 + "\"."));
|
BOOST_THROW_EXCEPTION(runtime_error("Filename path has to contain a directory: \"" + _filename + "\"."));
|
||||||
m_optimizerStep = std::prev(std::prev(path.end()))->string();
|
m_optimizerStep = std::prev(std::prev(path.end()))->string();
|
||||||
|
|
||||||
ifstream file(_filename);
|
m_source = m_reader.source();
|
||||||
soltestAssert(file, "Cannot open test contract: \"" + _filename + "\".");
|
|
||||||
file.exceptions(ios::badbit);
|
|
||||||
|
|
||||||
m_source = parseSourceAndSettings(file);
|
auto dialectName = m_reader.stringSetting("dialect", "evm");
|
||||||
if (m_settings.count("dialect"))
|
if (dialectName == "yul")
|
||||||
{
|
m_dialect = &Dialect::yulDeprecated();
|
||||||
auto dialectName = m_settings["dialect"];
|
else if (dialectName == "ewasm")
|
||||||
if (dialectName == "yul")
|
m_dialect = &WasmDialect::instance();
|
||||||
m_dialect = &Dialect::yulDeprecated();
|
else if (dialectName == "evm")
|
||||||
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
|
|
||||||
m_dialect = &EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion());
|
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_step = m_reader.stringSetting("step", "");
|
||||||
{
|
|
||||||
m_validatedSettings["step"] = m_settings["step"];
|
|
||||||
m_settings.erase("step");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_expectation = parseSimpleExpectations(file);
|
m_expectation = m_reader.simpleExpectations();
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
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";
|
m_obtainedResult = AsmPrinter{*m_dialect}(*m_ast) + "\n";
|
||||||
|
|
||||||
if (m_optimizerStep != m_validatedSettings["step"])
|
if (m_optimizerStep != m_step)
|
||||||
{
|
{
|
||||||
string nextIndentLevel = _linePrefix + " ";
|
string nextIndentLevel = _linePrefix + " ";
|
||||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) <<
|
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) <<
|
||||||
_linePrefix <<
|
_linePrefix <<
|
||||||
"Invalid optimizer step. Given: \"" <<
|
"Invalid optimizer step. Given: \"" <<
|
||||||
m_validatedSettings["step"] <<
|
m_step <<
|
||||||
"\", should be: \"" <<
|
"\", should be: \"" <<
|
||||||
m_optimizerStep <<
|
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)
|
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);
|
EVMVersionRestrictedTestCase::printUpdatedSettings(_stream, _linePrefix, _formatted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ private:
|
|||||||
std::string m_expectation;
|
std::string m_expectation;
|
||||||
|
|
||||||
Dialect const* m_dialect = nullptr;
|
Dialect const* m_dialect = nullptr;
|
||||||
|
std::string m_step;
|
||||||
std::set<YulString> m_reservedIdentifiers;
|
std::set<YulString> m_reservedIdentifiers;
|
||||||
std::unique_ptr<NameDispenser> m_nameDispenser;
|
std::unique_ptr<NameDispenser> m_nameDispenser;
|
||||||
std::unique_ptr<OptimiserStepContext> m_context;
|
std::unique_ptr<OptimiserStepContext> m_context;
|
||||||
|
@ -17,6 +17,7 @@ add_executable(isoltest
|
|||||||
../CommonSyntaxTest.cpp
|
../CommonSyntaxTest.cpp
|
||||||
../EVMHost.cpp
|
../EVMHost.cpp
|
||||||
../TestCase.cpp
|
../TestCase.cpp
|
||||||
|
../TestCaseReader.cpp
|
||||||
../libsolidity/util/BytesUtils.cpp
|
../libsolidity/util/BytesUtils.cpp
|
||||||
../libsolidity/util/ContractABIUtils.cpp
|
../libsolidity/util/ContractABIUtils.cpp
|
||||||
../libsolidity/util/TestFileParser.cpp
|
../libsolidity/util/TestFileParser.cpp
|
||||||
|
@ -161,7 +161,6 @@ TestTool::Result TestTool::process()
|
|||||||
(AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush();
|
(AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush();
|
||||||
|
|
||||||
m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.evmVersion()});
|
m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.evmVersion()});
|
||||||
m_test->validateSettings();
|
|
||||||
if (m_test->shouldRun())
|
if (m_test->shouldRun())
|
||||||
switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted))
|
switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted))
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user