diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index a48796612..f29f5f137 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -697,15 +697,15 @@ vector CompilerStack::contractNames() const return contractNames; } -string const CompilerStack::lastContractName() const +string const CompilerStack::lastContractName(optional 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 const& node: it.second.ast->nodes()) - if (auto contract = dynamic_cast(node.get())) + if (_sourceName.value_or(it.first) == it.first) + for (auto const* contract: ASTNode::filteredNodes(it.second.ast->nodes())) contractName = contract->fullyQualifiedName(); return contractName; } diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index ed3245505..1a02fb226 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -261,8 +261,8 @@ public: /// @returns a list of the contract names in the sources. std::vector 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 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; diff --git a/test/Common.cpp b/test/Common.cpp index 8406727d3..a020312a8 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -222,4 +223,19 @@ void CommonOptions::setSingleton(std::unique_ptr&& _instanc std::unique_ptr 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; +} + } diff --git a/test/Common.h b/test/Common.h index 2434e49ce..0cc78c121 100644 --- a/test/Common.h +++ b/test/Common.h @@ -86,4 +86,9 @@ private: static std::unique_ptr 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); + } diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 1756e25af..11f654281 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -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()) diff --git a/test/CommonSyntaxTest.h b/test/CommonSyntaxTest.h index db3a6e50c..169824252 100644 --- a/test/CommonSyntaxTest.h +++ b/test/CommonSyntaxTest.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -81,7 +82,7 @@ protected: static std::vector parseExpectations(std::istream& _stream); - std::map m_sources; + frontend::test::SourceMap m_sources; std::vector m_expectations; std::vector m_errorList; langutil::EVMVersion const m_evmVersion; diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index 1b320776e..c1d82856a 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -60,7 +60,8 @@ public: u256 const& _value = 0, std::string const& _contractName = "", bytes const& _arguments = {}, - std::map const& _libraryAddresses = {} + std::map const& _libraryAddresses = {}, + std::optional const& _sourceName = std::nullopt ) = 0; bytes const& compileAndRun( diff --git a/test/TestCaseReader.cpp b/test/TestCaseReader.cpp index 12dbedf6d..26b625734 100644 --- a/test/TestCaseReader.cpp +++ b/test/TestCaseReader.cpp @@ -18,24 +18,29 @@ #include +#include #include +#include #include #include +#include #include 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 TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream) { map sources; + map 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 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 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) diff --git a/test/TestCaseReader.h b/test/TestCaseReader.h index 620565aee..2d0ffe3b0 100644 --- a/test/TestCaseReader.h +++ b/test/TestCaseReader.h @@ -16,6 +16,7 @@ */ // SPDX-License-Identifier: GPL-3.0 +#include #include #include #include @@ -31,6 +32,7 @@ namespace solidity::frontend::test struct SourceMap { std::map sources; + std::map externalSources; std::string mainSourceFile; }; @@ -48,7 +50,7 @@ public: std::string const& source() const; std::size_t lineNumber() const { return m_lineNumber; } std::map 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 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 m_settings; diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 0162cd593..adb608da7 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -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(), diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 7a06f0ba1..10c5742e2 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -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 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 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 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 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; } diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index ab0bba27d..6ec949c68 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -36,10 +36,13 @@ using namespace std; bytes SolidityExecutionFramework::multiSourceCompileContract( map const& _sourceCode, + optional const& _mainSourceName, string const& _contractName, map const& _libraryAddresses ) { + if (_mainSourceName.has_value()) + solAssert(_sourceCode.find(_mainSourceName.value()) != _sourceCode.end(), ""); map 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 ); diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h index f616b2419..e0e02cf95 100644 --- a/test/libsolidity/SolidityExecutionFramework.h +++ b/test/libsolidity/SolidityExecutionFramework.h @@ -49,10 +49,11 @@ public: u256 const& _value = 0, std::string const& _contractName = "", bytes const& _arguments = {}, - std::map const& _libraryAddresses = {} + std::map const& _libraryAddresses = {}, + std::optional 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 const& _sources, + std::optional const& _mainSourceName = std::nullopt, std::string const& _contractName = "", std::map const& _libraryAddresses = {} ); diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 009b3613b..ed23bc609 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -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(location->source->source().size()) - static_cast(m_sources[sourceName].size()); + solAssert(m_sources.sources.count(sourceName) == 1, ""); + int preambleSize = static_cast(location->source->source().size()) - static_cast(m_sources.sources[sourceName].size()); solAssert(preambleSize >= 0, ""); // ignore the version & license pragma inserted by the testing tool when calculating locations. diff --git a/test/libsolidity/semanticTests/externalSource/_external/external.sol b/test/libsolidity/semanticTests/externalSource/_external/external.sol new file mode 100644 index 000000000..3289e6ec9 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_external/external.sol @@ -0,0 +1,2 @@ +contract External { +} diff --git a/test/libsolidity/semanticTests/externalSource/_external/external.sol=sol b/test/libsolidity/semanticTests/externalSource/_external/external.sol=sol new file mode 100644 index 000000000..3289e6ec9 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_external/external.sol=sol @@ -0,0 +1,2 @@ +contract External { +} diff --git a/test/libsolidity/semanticTests/externalSource/_external/import.sol b/test/libsolidity/semanticTests/externalSource/_external/import.sol new file mode 100644 index 000000000..30915351e --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_external/import.sol @@ -0,0 +1,2 @@ +import "external.sol"; +import "other_external.sol"; diff --git a/test/libsolidity/semanticTests/externalSource/_external/import_with_subdir.sol b/test/libsolidity/semanticTests/externalSource/_external/import_with_subdir.sol new file mode 100644 index 000000000..a8e23be56 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_external/import_with_subdir.sol @@ -0,0 +1 @@ +import "subdir/import.sol"; diff --git a/test/libsolidity/semanticTests/externalSource/_external/other_external.sol b/test/libsolidity/semanticTests/externalSource/_external/other_external.sol new file mode 100644 index 000000000..7a686b3dc --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_external/other_external.sol @@ -0,0 +1,2 @@ +contract OtherExternal { +} diff --git a/test/libsolidity/semanticTests/externalSource/_external/subdir/import.sol b/test/libsolidity/semanticTests/externalSource/_external/subdir/import.sol new file mode 100644 index 000000000..bf0ef42ce --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_external/subdir/import.sol @@ -0,0 +1 @@ +import "sub_external.sol"; diff --git a/test/libsolidity/semanticTests/externalSource/_external/subdir/sub_external.sol b/test/libsolidity/semanticTests/externalSource/_external/subdir/sub_external.sol new file mode 100644 index 000000000..63a3bd180 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_external/subdir/sub_external.sol @@ -0,0 +1,2 @@ +contract SubExternal { +} diff --git a/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/a.sol b/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/a.sol new file mode 100644 index 000000000..4e829399a --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/a.sol @@ -0,0 +1,2 @@ +contract A { +} diff --git a/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/c.sol b/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/c.sol new file mode 100644 index 000000000..41a6d5677 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/c.sol @@ -0,0 +1,2 @@ +contract C { +} diff --git a/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/d.sol b/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/d.sol new file mode 100644 index 000000000..0c9cba07d --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_non_normalized_paths/d.sol @@ -0,0 +1,2 @@ +contract D { +} diff --git a/test/libsolidity/semanticTests/externalSource/_relative_imports/D/d.sol b/test/libsolidity/semanticTests/externalSource/_relative_imports/D/d.sol new file mode 100644 index 000000000..0c9cba07d --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_relative_imports/D/d.sol @@ -0,0 +1,2 @@ +contract D { +} diff --git a/test/libsolidity/semanticTests/externalSource/_relative_imports/c.sol b/test/libsolidity/semanticTests/externalSource/_relative_imports/c.sol new file mode 100644 index 000000000..41a6d5677 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_relative_imports/c.sol @@ -0,0 +1,2 @@ +contract C { +} diff --git a/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/B/b.sol b/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/B/b.sol new file mode 100644 index 000000000..5611e6fa3 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/B/b.sol @@ -0,0 +1,3 @@ +import {C} from "../../c.sol"; +contract B { +} diff --git a/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/G/g.sol b/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/G/g.sol new file mode 100644 index 000000000..1d2096de2 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/G/g.sol @@ -0,0 +1,3 @@ +import {B} from "../B/b.sol"; +contract G { +} diff --git a/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/a.sol b/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/a.sol new file mode 100644 index 000000000..4e829399a --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/a.sol @@ -0,0 +1,2 @@ +contract A { +} diff --git a/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/contract.sol b/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/contract.sol new file mode 100644 index 000000000..aab81b975 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_relative_imports/dir/contract.sol @@ -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 { +} diff --git a/test/libsolidity/semanticTests/externalSource/_relative_imports/h.sol b/test/libsolidity/semanticTests/externalSource/_relative_imports/h.sol new file mode 100644 index 000000000..2d969980e --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_relative_imports/h.sol @@ -0,0 +1,2 @@ +contract H { +} diff --git a/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/b.sol b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/b.sol new file mode 100644 index 000000000..8b4d63952 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/b.sol @@ -0,0 +1,2 @@ +contract B { +} diff --git a/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dir/a.sol b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dir/a.sol new file mode 100644 index 000000000..4e829399a --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dir/a.sol @@ -0,0 +1,2 @@ +contract A { +} diff --git a/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dir/contract.sol b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dir/contract.sol new file mode 100644 index 000000000..f67d97026 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dir/contract.sol @@ -0,0 +1,2 @@ +import {A} from "./a.sol"; +import {B} from "../b.sol"; diff --git a/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dot_a.sol b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dot_a.sol new file mode 100644 index 000000000..3f1554224 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dot_a.sol @@ -0,0 +1,2 @@ +contract Dot_A { +} diff --git a/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dot_dot_b.sol b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dot_dot_b.sol new file mode 100644 index 000000000..037c81216 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/_source_name_starting_with_dots/dot_dot_b.sol @@ -0,0 +1,2 @@ +contract Dot_Dot_B { +} diff --git a/test/libsolidity/semanticTests/externalSource/multiple_equals_signs.sol b/test/libsolidity/semanticTests/externalSource/multiple_equals_signs.sol new file mode 100644 index 000000000..d6bd1e27c --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/multiple_equals_signs.sol @@ -0,0 +1,8 @@ +==== ExternalSource: a=_external/external.sol=sol ==== +import {External} from "a"; +contract C { +} +// ==== +// compileViaYul: also +// ---- +// constructor() diff --git a/test/libsolidity/semanticTests/externalSource/multiple_external_source.sol b/test/libsolidity/semanticTests/externalSource/multiple_external_source.sol new file mode 100644 index 000000000..4b4c3d9bb --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/multiple_external_source.sol @@ -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() diff --git a/test/libsolidity/semanticTests/externalSource/multisource.sol b/test/libsolidity/semanticTests/externalSource/multisource.sol new file mode 100644 index 000000000..8291f66ae --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/multisource.sol @@ -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() + diff --git a/test/libsolidity/semanticTests/externalSource/non_normalized_paths.sol b/test/libsolidity/semanticTests/externalSource/non_normalized_paths.sol new file mode 100644 index 000000000..4d1854e96 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/non_normalized_paths.sol @@ -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() diff --git a/test/libsolidity/semanticTests/externalSource/relative_imports.sol b/test/libsolidity/semanticTests/externalSource/relative_imports.sol new file mode 100644 index 000000000..744684f4f --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/relative_imports.sol @@ -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() diff --git a/test/libsolidity/semanticTests/externalSource/source.sol b/test/libsolidity/semanticTests/externalSource/source.sol new file mode 100644 index 000000000..5fc5a3b89 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/source.sol @@ -0,0 +1,8 @@ +==== ExternalSource: _external/external.sol ==== +import {External} from "_external/external.sol"; +contract C { +} +// ==== +// compileViaYul: also +// ---- +// constructor() diff --git a/test/libsolidity/semanticTests/externalSource/source_import.sol b/test/libsolidity/semanticTests/externalSource/source_import.sol new file mode 100644 index 000000000..4b4c3d9bb --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/source_import.sol @@ -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() diff --git a/test/libsolidity/semanticTests/externalSource/source_import_subdir.sol b/test/libsolidity/semanticTests/externalSource/source_import_subdir.sol new file mode 100644 index 000000000..f3fa73085 --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/source_import_subdir.sol @@ -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() diff --git a/test/libsolidity/semanticTests/externalSource/source_name_starting_with_dots.sol b/test/libsolidity/semanticTests/externalSource/source_name_starting_with_dots.sol new file mode 100644 index 000000000..829485e6d --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/source_name_starting_with_dots.sol @@ -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() diff --git a/test/libsolidity/semanticTests/externalSource/source_remapping.sol b/test/libsolidity/semanticTests/externalSource/source_remapping.sol new file mode 100644 index 000000000..4edb2200f --- /dev/null +++ b/test/libsolidity/semanticTests/externalSource/source_remapping.sol @@ -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() diff --git a/test/libyul/SyntaxTest.cpp b/test/libyul/SyntaxTest.cpp index f01728571..21d295058 100644 --- a/test/libyul/SyntaxTest.cpp +++ b/test/libyul/SyntaxTest.cpp @@ -25,6 +25,7 @@ #include #include +#include #include @@ -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, ""); diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index b05cbe84a..31f674876 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -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();