mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11110 from ethereum/issue_10475_isoltest_external_sources
[isoltest] Add support for external sources.
This commit is contained in:
commit
f72592549b
@ -697,15 +697,15 @@ vector<string> CompilerStack::contractNames() const
|
||||
return contractNames;
|
||||
}
|
||||
|
||||
string const CompilerStack::lastContractName() const
|
||||
string const CompilerStack::lastContractName(optional<string> const& _sourceName) const
|
||||
{
|
||||
if (m_stackState < AnalysisPerformed)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||
// try to find some user-supplied contract
|
||||
string contractName;
|
||||
for (auto const& it: m_sources)
|
||||
for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
|
||||
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
|
||||
if (_sourceName.value_or(it.first) == it.first)
|
||||
for (auto const* contract: ASTNode::filteredNodes<ContractDefinition>(it.second.ast->nodes()))
|
||||
contractName = contract->fullyQualifiedName();
|
||||
return contractName;
|
||||
}
|
||||
|
@ -261,8 +261,8 @@ public:
|
||||
/// @returns a list of the contract names in the sources.
|
||||
std::vector<std::string> contractNames() const;
|
||||
|
||||
/// @returns the name of the last contract.
|
||||
std::string const lastContractName() const;
|
||||
/// @returns the name of the last contract. If _sourceName is defined the last contract of that source will be returned.
|
||||
std::string const lastContractName(std::optional<std::string> const& _sourceName = std::nullopt) const;
|
||||
|
||||
/// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use
|
||||
std::string const filesystemFriendlyName(std::string const& _contractName) const;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <test/Common.h>
|
||||
|
||||
#include <libsolutil/Assertions.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
@ -222,4 +223,19 @@ void CommonOptions::setSingleton(std::unique_ptr<CommonOptions const>&& _instanc
|
||||
|
||||
std::unique_ptr<CommonOptions const> CommonOptions::m_singleton = nullptr;
|
||||
|
||||
bool isValidSemanticTestPath(boost::filesystem::path const& _testPath)
|
||||
{
|
||||
bool insideSemanticTests = false;
|
||||
fs::path testPathPrefix;
|
||||
for (auto const& element: _testPath)
|
||||
{
|
||||
testPathPrefix /= element;
|
||||
if (boost::ends_with(canonical(testPathPrefix).generic_string(), "/test/libsolidity/semanticTests"))
|
||||
insideSemanticTests = true;
|
||||
if (insideSemanticTests && boost::starts_with(element.string(), "_"))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -86,4 +86,9 @@ private:
|
||||
static std::unique_ptr<CommonOptions const> m_singleton;
|
||||
};
|
||||
|
||||
/// @return true if it is ok to treat the file located under the specified path as a semantic test.
|
||||
/// I.e. if the test is located in the semantic test directory and is not excluded due to being a part of external sources.
|
||||
/// Note: @p _testPath can be relative but must include at least the `/test/libsolidity/semanticTests/` part
|
||||
bool isValidSemanticTestPath(boost::filesystem::path const& _testPath);
|
||||
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ int parseUnsignedInteger(string::iterator& _it, string::iterator _end)
|
||||
|
||||
CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion):
|
||||
EVMVersionRestrictedTestCase(_filename),
|
||||
m_sources(m_reader.sources().sources),
|
||||
m_sources(m_reader.sources()),
|
||||
m_expectations(parseExpectations(m_reader.stream())),
|
||||
m_evmVersion(_evmVersion)
|
||||
{
|
||||
@ -92,12 +92,13 @@ void CommonSyntaxTest::printExpectationAndError(ostream& _stream, string const&
|
||||
|
||||
void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const
|
||||
{
|
||||
if (m_sources.empty())
|
||||
if (m_sources.sources.empty())
|
||||
return;
|
||||
|
||||
bool outputSourceNames = (m_sources.size() != 1 || !m_sources.begin()->first.empty());
|
||||
assert(m_sources.externalSources.empty());
|
||||
bool outputSourceNames = (m_sources.sources.size() != 1 || !m_sources.sources.begin()->first.empty());
|
||||
|
||||
for (auto const& [name, source]: m_sources)
|
||||
for (auto const& [name, source]: m_sources.sources)
|
||||
if (_formatted)
|
||||
{
|
||||
if (source.empty())
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <test/libsolidity/AnalysisFramework.h>
|
||||
#include <test/TestCase.h>
|
||||
#include <test/TestCaseReader.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
|
||||
@ -81,7 +82,7 @@ protected:
|
||||
|
||||
static std::vector<SyntaxTestError> parseExpectations(std::istream& _stream);
|
||||
|
||||
std::map<std::string, std::string> m_sources;
|
||||
frontend::test::SourceMap m_sources;
|
||||
std::vector<SyntaxTestError> m_expectations;
|
||||
std::vector<SyntaxTestError> m_errorList;
|
||||
langutil::EVMVersion const m_evmVersion;
|
||||
|
@ -60,7 +60,8 @@ public:
|
||||
u256 const& _value = 0,
|
||||
std::string const& _contractName = "",
|
||||
bytes const& _arguments = {},
|
||||
std::map<std::string, util::h160> const& _libraryAddresses = {}
|
||||
std::map<std::string, util::h160> const& _libraryAddresses = {},
|
||||
std::optional<std::string> const& _sourceName = std::nullopt
|
||||
) = 0;
|
||||
|
||||
bytes const& compileAndRun(
|
||||
|
@ -18,24 +18,29 @@
|
||||
|
||||
#include <test/TestCaseReader.h>
|
||||
|
||||
#include <libsolidity/parsing/Parser.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <libsolutil/CommonIO.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <range/v3/view/map.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::langutil;
|
||||
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);
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber(m_file);
|
||||
TestCaseReader::TestCaseReader(string const& _filename): m_fileStream(_filename), m_fileName(_filename)
|
||||
{
|
||||
if (!m_fileStream)
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Cannot open file: \"" + _filename + "\"."));
|
||||
m_fileStream.exceptions(ios::badbit);
|
||||
|
||||
tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber(m_fileStream);
|
||||
m_unreadSettings = m_settings;
|
||||
}
|
||||
|
||||
@ -55,7 +60,7 @@ string const& TestCaseReader::source() const
|
||||
|
||||
string TestCaseReader::simpleExpectations()
|
||||
{
|
||||
return parseSimpleExpectations(m_file);
|
||||
return parseSimpleExpectations(m_fileStream);
|
||||
}
|
||||
|
||||
bool TestCaseReader::boolSetting(std::string const& _name, bool _defaultValue)
|
||||
@ -105,10 +110,12 @@ void TestCaseReader::ensureAllSettingsRead() const
|
||||
pair<SourceMap, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream)
|
||||
{
|
||||
map<string, string> sources;
|
||||
map<string, boost::filesystem::path> externalSources;
|
||||
string currentSourceName;
|
||||
string currentSource;
|
||||
string line;
|
||||
size_t lineNumber = 1;
|
||||
static string const externalSourceDelimiterStart("==== ExternalSource:");
|
||||
static string const sourceDelimiterStart("==== Source:");
|
||||
static string const sourceDelimiterEnd("====");
|
||||
static string const comment("// ");
|
||||
@ -137,6 +144,41 @@ pair<SourceMap, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(is
|
||||
if (sources.count(currentSourceName))
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Multiple definitions of test source \"" + currentSourceName + "\"."));
|
||||
}
|
||||
else if (boost::algorithm::starts_with(line, externalSourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd))
|
||||
{
|
||||
string externalSourceString = boost::trim_copy(line.substr(
|
||||
externalSourceDelimiterStart.size(),
|
||||
line.size() - sourceDelimiterEnd.size() - externalSourceDelimiterStart.size()
|
||||
));
|
||||
|
||||
string externalSourceName;
|
||||
size_t remappingPos = externalSourceString.find('=');
|
||||
// Does the external source define a remapping?
|
||||
if (remappingPos != string::npos)
|
||||
{
|
||||
externalSourceName = boost::trim_copy(externalSourceString.substr(0, remappingPos));
|
||||
externalSourceString = boost::trim_copy(externalSourceString.substr(remappingPos + 1));
|
||||
}
|
||||
else
|
||||
externalSourceName = externalSourceString;
|
||||
|
||||
solAssert(!externalSourceName.empty(), "");
|
||||
fs::path externalSourceTarget(externalSourceString);
|
||||
fs::path testCaseParentDir = m_fileName.parent_path();
|
||||
if (!externalSourceTarget.is_relative())
|
||||
BOOST_THROW_EXCEPTION(runtime_error("External Source paths need to be relative to the location of the test case."));
|
||||
fs::path externalSourceFullPath = testCaseParentDir / externalSourceTarget;
|
||||
string externalSourceContent;
|
||||
if (!fs::exists(externalSourceFullPath))
|
||||
BOOST_THROW_EXCEPTION(runtime_error("External Source '" + externalSourceTarget.string() + "' not found."));
|
||||
else
|
||||
externalSourceContent = util::readFileAsString(externalSourceFullPath.string());
|
||||
|
||||
if (sources.count(externalSourceName))
|
||||
BOOST_THROW_EXCEPTION(runtime_error("Multiple definitions of test source \"" + externalSourceName + "\"."));
|
||||
sources[externalSourceName] = externalSourceContent;
|
||||
externalSources[externalSourceName] = externalSourceTarget;
|
||||
}
|
||||
else
|
||||
currentSource += line + "\n";
|
||||
}
|
||||
@ -156,7 +198,7 @@ pair<SourceMap, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(is
|
||||
}
|
||||
// Register the last source as the main one
|
||||
sources[currentSourceName] = currentSource;
|
||||
return {{move(sources), move(currentSourceName)}, lineNumber};
|
||||
return {{move(sources), move(externalSources), move(currentSourceName)}, lineNumber};
|
||||
}
|
||||
|
||||
string TestCaseReader::parseSimpleExpectations(istream& _file)
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
@ -31,6 +32,7 @@ namespace solidity::frontend::test
|
||||
struct SourceMap
|
||||
{
|
||||
std::map<std::string, std::string> sources;
|
||||
std::map<std::string, boost::filesystem::path> externalSources;
|
||||
std::string mainSourceFile;
|
||||
};
|
||||
|
||||
@ -48,7 +50,7 @@ public:
|
||||
std::string const& source() const;
|
||||
std::size_t lineNumber() const { return m_lineNumber; }
|
||||
std::map<std::string, std::string> const& settings() const { return m_settings; }
|
||||
std::ifstream& stream() { return m_file; }
|
||||
std::ifstream& stream() { return m_fileStream; }
|
||||
|
||||
std::string simpleExpectations();
|
||||
|
||||
@ -62,7 +64,8 @@ private:
|
||||
std::pair<SourceMap, std::size_t> parseSourcesAndSettingsWithLineNumber(std::istream& _file);
|
||||
static std::string parseSimpleExpectations(std::istream& _file);
|
||||
|
||||
std::ifstream m_file;
|
||||
std::ifstream m_fileStream;
|
||||
boost::filesystem::path m_fileName;
|
||||
SourceMap m_sources;
|
||||
std::size_t m_lineNumber = 0;
|
||||
std::map<std::string, std::string> m_settings;
|
||||
|
@ -86,7 +86,10 @@ int registerTests(
|
||||
fs::directory_iterator(fullpath),
|
||||
fs::directory_iterator()
|
||||
))
|
||||
if (fs::is_directory(entry.path()) || TestCase::isTestFilename(entry.path().filename()))
|
||||
if (
|
||||
solidity::test::isValidSemanticTestPath(entry) &&
|
||||
(fs::is_directory(entry.path()) || TestCase::isTestFilename(entry.path().filename()))
|
||||
)
|
||||
numTestsAdded += registerTests(
|
||||
*sub_suite,
|
||||
_basepath, _path / entry.path().filename(),
|
||||
|
@ -256,7 +256,7 @@ TestCase::TestResult SemanticTest::runTest(
|
||||
{
|
||||
soltestAssert(
|
||||
m_allowNonExistingFunctions ||
|
||||
m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature),
|
||||
m_compiler.methodIdentifiers(m_compiler.lastContractName(m_sources.mainSourceFile)).isMember(test.call().signature),
|
||||
"The function " + test.call().signature + " is not known to the compiler"
|
||||
);
|
||||
|
||||
@ -283,7 +283,7 @@ TestCase::TestResult SemanticTest::runTest(
|
||||
|
||||
test.setFailure(!m_transactionSuccessful);
|
||||
test.setRawBytes(std::move(output));
|
||||
test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName()));
|
||||
test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName(m_sources.mainSourceFile)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,42 +379,62 @@ void SemanticTest::printSource(ostream& _stream, string const& _linePrefix, bool
|
||||
if (m_sources.sources.empty())
|
||||
return;
|
||||
|
||||
bool outputNames = (m_sources.sources.size() != 1 || !m_sources.sources.begin()->first.empty());
|
||||
bool outputNames = (m_sources.sources.size() - m_sources.externalSources.size() != 1 || !m_sources.sources.begin()->first.empty());
|
||||
|
||||
set<string> externals;
|
||||
for (auto const& [name, path]: m_sources.externalSources)
|
||||
{
|
||||
externals.insert(name);
|
||||
string externalSource;
|
||||
if (name == path)
|
||||
externalSource = name;
|
||||
else
|
||||
externalSource = name + "=" + path.generic_string();
|
||||
|
||||
if (_formatted)
|
||||
_stream << _linePrefix << formatting::CYAN << "==== ExternalSource: " << externalSource << " ===="s << formatting::RESET << endl;
|
||||
else
|
||||
_stream << _linePrefix << "==== ExternalSource: " << externalSource << " ===="s << endl;
|
||||
}
|
||||
|
||||
for (auto const& [name, source]: m_sources.sources)
|
||||
if (_formatted)
|
||||
if (externals.find(name) == externals.end())
|
||||
{
|
||||
if (source.empty())
|
||||
continue;
|
||||
|
||||
if (outputNames)
|
||||
_stream << _linePrefix << formatting::CYAN << "==== Source: " << name << " ====" << formatting::RESET << endl;
|
||||
vector<char const*> sourceFormatting(source.length(), formatting::RESET);
|
||||
|
||||
_stream << _linePrefix << sourceFormatting.front() << source.front();
|
||||
for (size_t i = 1; i < source.length(); i++)
|
||||
if (_formatted)
|
||||
{
|
||||
if (sourceFormatting[i] != sourceFormatting[i - 1])
|
||||
_stream << sourceFormatting[i];
|
||||
if (source[i] != '\n')
|
||||
_stream << source[i];
|
||||
else
|
||||
if (source.empty())
|
||||
continue;
|
||||
|
||||
if (outputNames)
|
||||
_stream << _linePrefix << formatting::CYAN << "==== Source: " << name
|
||||
<< " ====" << formatting::RESET << endl;
|
||||
|
||||
vector<char const*> sourceFormatting(source.length(), formatting::RESET);
|
||||
_stream << _linePrefix << sourceFormatting.front() << source.front();
|
||||
for (size_t i = 1; i < source.length(); i++)
|
||||
{
|
||||
_stream << formatting::RESET << endl;
|
||||
if (i + 1 < source.length())
|
||||
_stream << _linePrefix << sourceFormatting[i];
|
||||
if (sourceFormatting[i] != sourceFormatting[i - 1])
|
||||
_stream << sourceFormatting[i];
|
||||
if (source[i] != '\n')
|
||||
_stream << source[i];
|
||||
else
|
||||
{
|
||||
_stream << formatting::RESET << endl;
|
||||
if (i + 1 < source.length())
|
||||
_stream << _linePrefix << sourceFormatting[i];
|
||||
}
|
||||
}
|
||||
_stream << formatting::RESET;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (outputNames)
|
||||
_stream << _linePrefix << "==== Source: " + name << " ====" << endl;
|
||||
stringstream stream(source);
|
||||
string line;
|
||||
while (getline(stream, line))
|
||||
_stream << _linePrefix << line << endl;
|
||||
}
|
||||
_stream << formatting::RESET;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (outputNames)
|
||||
_stream << _linePrefix << "==== Source: " + name << " ====" << endl;
|
||||
stringstream stream(source);
|
||||
string line;
|
||||
while (getline(stream, line))
|
||||
_stream << _linePrefix << line << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,6 +475,6 @@ bool SemanticTest::deploy(
|
||||
map<string, solidity::test::Address> const& _libraries
|
||||
)
|
||||
{
|
||||
auto output = compileAndRunWithoutCheck(m_sources.sources, _value, _contractName, _arguments, _libraries);
|
||||
auto output = compileAndRunWithoutCheck(m_sources.sources, _value, _contractName, _arguments, _libraries, m_sources.mainSourceFile);
|
||||
return !output.empty() && m_transactionSuccessful;
|
||||
}
|
||||
|
@ -36,10 +36,13 @@ using namespace std;
|
||||
|
||||
bytes SolidityExecutionFramework::multiSourceCompileContract(
|
||||
map<string, string> const& _sourceCode,
|
||||
optional<string> const& _mainSourceName,
|
||||
string const& _contractName,
|
||||
map<string, Address> const& _libraryAddresses
|
||||
)
|
||||
{
|
||||
if (_mainSourceName.has_value())
|
||||
solAssert(_sourceCode.find(_mainSourceName.value()) != _sourceCode.end(), "");
|
||||
map<string, string> sourcesWithPreamble = _sourceCode;
|
||||
for (auto& entry: sourcesWithPreamble)
|
||||
entry.second = addPreamble(entry.second);
|
||||
@ -68,7 +71,7 @@ bytes SolidityExecutionFramework::multiSourceCompileContract(
|
||||
formatter.printErrorInformation(*error);
|
||||
BOOST_ERROR("Compiling contract failed");
|
||||
}
|
||||
std::string contractName(_contractName.empty() ? m_compiler.lastContractName() : _contractName);
|
||||
string contractName(_contractName.empty() ? m_compiler.lastContractName(_mainSourceName) : _contractName);
|
||||
evmasm::LinkerObject obj;
|
||||
if (m_compileViaYul)
|
||||
{
|
||||
@ -98,7 +101,7 @@ bytes SolidityExecutionFramework::multiSourceCompileContract(
|
||||
try
|
||||
{
|
||||
asmStack.optimize();
|
||||
obj = std::move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode);
|
||||
obj = move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode);
|
||||
obj.link(_libraryAddresses);
|
||||
break;
|
||||
}
|
||||
@ -126,6 +129,7 @@ bytes SolidityExecutionFramework::compileContract(
|
||||
{
|
||||
return multiSourceCompileContract(
|
||||
{{"", _sourceCode}},
|
||||
nullopt,
|
||||
_contractName,
|
||||
_libraryAddresses
|
||||
);
|
||||
|
@ -49,10 +49,11 @@ public:
|
||||
u256 const& _value = 0,
|
||||
std::string const& _contractName = "",
|
||||
bytes const& _arguments = {},
|
||||
std::map<std::string, solidity::test::Address> const& _libraryAddresses = {}
|
||||
std::map<std::string, solidity::test::Address> const& _libraryAddresses = {},
|
||||
std::optional<std::string> const& _sourceName = std::nullopt
|
||||
) override
|
||||
{
|
||||
bytes bytecode = multiSourceCompileContract(_sourceCode, _contractName, _libraryAddresses);
|
||||
bytes bytecode = multiSourceCompileContract(_sourceCode, _sourceName, _contractName, _libraryAddresses);
|
||||
sendMessage(bytecode + _arguments, true, _value);
|
||||
return m_output;
|
||||
}
|
||||
@ -65,6 +66,7 @@ public:
|
||||
|
||||
bytes multiSourceCompileContract(
|
||||
std::map<std::string, std::string> const& _sources,
|
||||
std::optional<std::string> const& _mainSourceName = std::nullopt,
|
||||
std::string const& _contractName = "",
|
||||
std::map<std::string, solidity::test::Address> const& _libraryAddresses = {}
|
||||
);
|
||||
|
@ -65,7 +65,7 @@ string SyntaxTest::addPreamble(string const& _sourceCode)
|
||||
void SyntaxTest::setupCompiler()
|
||||
{
|
||||
compiler().reset();
|
||||
auto sourcesWithPragma = m_sources;
|
||||
auto sourcesWithPragma = m_sources.sources;
|
||||
for (auto& source: sourcesWithPragma)
|
||||
source.second = addPreamble(source.second);
|
||||
compiler().setSources(sourcesWithPragma);
|
||||
@ -122,8 +122,8 @@ void SyntaxTest::filterObtainedErrors()
|
||||
solAssert(location->source, "");
|
||||
sourceName = location->source->name();
|
||||
|
||||
solAssert(m_sources.count(sourceName) == 1, "");
|
||||
int preambleSize = static_cast<int>(location->source->source().size()) - static_cast<int>(m_sources[sourceName].size());
|
||||
solAssert(m_sources.sources.count(sourceName) == 1, "");
|
||||
int preambleSize = static_cast<int>(location->source->source().size()) - static_cast<int>(m_sources.sources[sourceName].size());
|
||||
solAssert(preambleSize >= 0, "");
|
||||
|
||||
// ignore the version & license pragma inserted by the testing tool when calculating locations.
|
||||
|
@ -0,0 +1,2 @@
|
||||
contract External {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract External {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
import "external.sol";
|
||||
import "other_external.sol";
|
@ -0,0 +1 @@
|
||||
import "subdir/import.sol";
|
@ -0,0 +1,2 @@
|
||||
contract OtherExternal {
|
||||
}
|
@ -0,0 +1 @@
|
||||
import "sub_external.sol";
|
@ -0,0 +1,2 @@
|
||||
contract SubExternal {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract A {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract C {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract D {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract D {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract C {
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
import {C} from "../../c.sol";
|
||||
contract B {
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
import {B} from "../B/b.sol";
|
||||
contract G {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract A {
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import {A} from "./a.sol";
|
||||
import {B} from "./B/b.sol";
|
||||
import {C} from "../c.sol";
|
||||
import {D} from "../D/d.sol";
|
||||
import {G} from "./E/../F/../G/./g.sol";
|
||||
import {H} from "../../../../_relative_imports/h.sol";
|
||||
contract Contract {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract H {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract B {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract A {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
import {A} from "./a.sol";
|
||||
import {B} from "../b.sol";
|
@ -0,0 +1,2 @@
|
||||
contract Dot_A {
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
contract Dot_Dot_B {
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
==== ExternalSource: a=_external/external.sol=sol ====
|
||||
import {External} from "a";
|
||||
contract C {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
@ -0,0 +1,10 @@
|
||||
==== ExternalSource: _external/external.sol ====
|
||||
==== ExternalSource: _external/other_external.sol ====
|
||||
import {External} from "_external/external.sol";
|
||||
import {OtherExternal} from "_external/other_external.sol";
|
||||
contract C {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
@ -0,0 +1,14 @@
|
||||
==== ExternalSource: _external/external.sol ====
|
||||
==== Source: s1.sol ====
|
||||
import {External} from "_external/external.sol";
|
||||
contract S1 {
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import {S1} from "s1.sol";
|
||||
contract C {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
||||
|
@ -0,0 +1,12 @@
|
||||
==== ExternalSource: _non_normalized_paths//a.sol ====
|
||||
==== ExternalSource: C/////c.sol=_non_normalized_paths/c.sol ====
|
||||
==== ExternalSource: C/../////D/d.sol=_non_normalized_paths///d.sol ====
|
||||
import {A} from "_non_normalized_paths//a.sol";
|
||||
import {C} from "C/////c.sol";
|
||||
import {D} from "C/../////D/d.sol";
|
||||
contract Contract {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
@ -0,0 +1,14 @@
|
||||
==== ExternalSource: _relative_imports/dir/contract.sol ====
|
||||
==== ExternalSource: _relative_imports/dir/a.sol ====
|
||||
==== ExternalSource: _relative_imports/dir/B/b.sol ====
|
||||
==== ExternalSource: _relative_imports/c.sol ====
|
||||
==== ExternalSource: _relative_imports/D/d.sol ====
|
||||
==== ExternalSource: _relative_imports/dir/G/g.sol ====
|
||||
==== ExternalSource: _relative_imports/h.sol ====
|
||||
import {A, B, C, D, G, H, Contract} from "_relative_imports/dir/contract.sol";
|
||||
contract CC {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
8
test/libsolidity/semanticTests/externalSource/source.sol
Normal file
8
test/libsolidity/semanticTests/externalSource/source.sol
Normal file
@ -0,0 +1,8 @@
|
||||
==== ExternalSource: _external/external.sol ====
|
||||
import {External} from "_external/external.sol";
|
||||
contract C {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
@ -0,0 +1,10 @@
|
||||
==== ExternalSource: _external/external.sol ====
|
||||
==== ExternalSource: _external/other_external.sol ====
|
||||
import {External} from "_external/external.sol";
|
||||
import {OtherExternal} from "_external/other_external.sol";
|
||||
contract C {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
@ -0,0 +1,10 @@
|
||||
==== ExternalSource: _external/import_with_subdir.sol ====
|
||||
==== ExternalSource: subdir/import.sol=_external/subdir/import.sol ====
|
||||
==== ExternalSource: sub_external.sol=_external/subdir/sub_external.sol ====
|
||||
import {SubExternal} from "sub_external.sol";
|
||||
contract C {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
@ -0,0 +1,12 @@
|
||||
==== ExternalSource: ./a.sol=_source_name_starting_with_dots/dot_a.sol ====
|
||||
==== ExternalSource: ../b.sol=_source_name_starting_with_dots/dot_dot_b.sol ====
|
||||
==== ExternalSource: _source_name_starting_with_dots/dir/a.sol ====
|
||||
==== ExternalSource: _source_name_starting_with_dots/b.sol ====
|
||||
==== ExternalSource: _source_name_starting_with_dots/dir/contract.sol ====
|
||||
import {A, B} from "_source_name_starting_with_dots/dir/contract.sol";
|
||||
contract Contract {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
@ -0,0 +1,12 @@
|
||||
==== ExternalSource: ExtSource.sol=_external/external.sol ====
|
||||
==== ExternalSource: /ExtSource.sol=_external/other_external.sol ====
|
||||
import "ExtSource.sol";
|
||||
import "/ExtSource.sol";
|
||||
contract C {
|
||||
External _external;
|
||||
OtherExternal _otherExternal;
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor()
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <test/libyul/Common.h>
|
||||
#include <test/libyul/SyntaxTest.h>
|
||||
#include <test/TestCaseReader.h>
|
||||
|
||||
#include <test/libsolidity/util/SoltestErrors.h>
|
||||
|
||||
@ -35,14 +36,15 @@ using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::yul::test;
|
||||
using namespace solidity::frontend::test;
|
||||
|
||||
void SyntaxTest::parseAndAnalyze()
|
||||
{
|
||||
if (m_sources.size() != 1)
|
||||
if (m_sources.sources.size() != 1)
|
||||
BOOST_THROW_EXCEPTION(runtime_error{"Expected only one source for yul test."});
|
||||
|
||||
string const& name = m_sources.begin()->first;
|
||||
string const& source = m_sources.begin()->second;
|
||||
string const& name = m_sources.sources.begin()->first;
|
||||
string const& source = m_sources.sources.begin()->second;
|
||||
|
||||
ErrorList errorList{};
|
||||
soltestAssert(m_dialect, "");
|
||||
|
@ -79,9 +79,9 @@ public:
|
||||
m_filterExpression = regex{"(" + filter + "(\\.sol|\\.yul))"};
|
||||
}
|
||||
|
||||
bool matches(string const& _name) const
|
||||
bool matches(fs::path const& _path, string const& _name) const
|
||||
{
|
||||
return regex_match(_name, m_filterExpression);
|
||||
return regex_match(_name, m_filterExpression) && solidity::test::isValidSemanticTestPath(_path);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -154,7 +154,7 @@ TestTool::Result TestTool::process()
|
||||
|
||||
try
|
||||
{
|
||||
if (m_filter.matches(m_name))
|
||||
if (m_filter.matches(m_path, m_name))
|
||||
{
|
||||
(AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user