Merge pull request #11110 from ethereum/issue_10475_isoltest_external_sources

[isoltest] Add support for external sources.
This commit is contained in:
chriseth
2021-04-27 10:54:39 +02:00
committed by GitHub
48 changed files with 328 additions and 68 deletions
+52 -32
View File
@@ -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 = {}
);
+3 -3
View File
@@ -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 @@
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()
@@ -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()