mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7048 from ethereum/soltest-refactoring
[isoltest] Types and formatting refactoring
This commit is contained in:
commit
479b843067
198
test/libsolidity/util/BytesUtils.cpp
Normal file
198
test/libsolidity/util/BytesUtils.cpp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
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/libsolidity/util/BytesUtils.h>
|
||||||
|
|
||||||
|
#include <liblangutil/Common.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <regex>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
using namespace dev;
|
||||||
|
using namespace langutil;
|
||||||
|
using namespace solidity;
|
||||||
|
using namespace dev::solidity::test;
|
||||||
|
using namespace std;
|
||||||
|
using namespace soltest;
|
||||||
|
|
||||||
|
bytes BytesUtils::convertBoolean(string const& _literal)
|
||||||
|
{
|
||||||
|
if (_literal == "true")
|
||||||
|
return bytes{true};
|
||||||
|
else if (_literal == "false")
|
||||||
|
return bytes{false};
|
||||||
|
else
|
||||||
|
throw Error(Error::Type::ParserError, "Boolean literal invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes BytesUtils::convertNumber(string const& _literal)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return toCompactBigEndian(u256{_literal});
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
throw Error(Error::Type::ParserError, "Number encoding invalid.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes BytesUtils::convertHexNumber(string const& _literal)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_literal.size() % 2)
|
||||||
|
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
|
||||||
|
else
|
||||||
|
return fromHex(_literal);
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes BytesUtils::convertString(string const& _literal)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return asBytes(_literal);
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
throw Error(Error::Type::ParserError, "String encoding invalid.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string BytesUtils::formatUnsigned(bytes const& _bytes) const
|
||||||
|
{
|
||||||
|
stringstream os;
|
||||||
|
|
||||||
|
if (*_bytes.begin() & 0x80)
|
||||||
|
os << u2s(fromBigEndian<u256>(_bytes));
|
||||||
|
else
|
||||||
|
os << fromBigEndian<u256>(_bytes);
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string BytesUtils::formatSigned(bytes const& _bytes) const
|
||||||
|
{
|
||||||
|
stringstream os;
|
||||||
|
|
||||||
|
if (*_bytes.begin() & 0x80)
|
||||||
|
os << u2s(fromBigEndian<u256>(_bytes));
|
||||||
|
else
|
||||||
|
os << fromBigEndian<u256>(_bytes);
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string BytesUtils::formatBoolean(bytes const& _bytes) const
|
||||||
|
{
|
||||||
|
stringstream os;
|
||||||
|
u256 result = fromBigEndian<u256>(_bytes);
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
os << "false";
|
||||||
|
else if (result == 1)
|
||||||
|
os << "true";
|
||||||
|
else
|
||||||
|
os << result;
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string BytesUtils::formatHex(bytes const& _bytes) const
|
||||||
|
{
|
||||||
|
stringstream os;
|
||||||
|
|
||||||
|
string hex{toHex(_bytes, HexPrefix::Add)};
|
||||||
|
boost::algorithm::replace_all(hex, "00", "");
|
||||||
|
os << hex;
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string BytesUtils::formatHexString(bytes const& _bytes) const
|
||||||
|
{
|
||||||
|
stringstream os;
|
||||||
|
|
||||||
|
os << "hex\"" << toHex(_bytes) << "\"";
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string BytesUtils::formatString(bytes const& _bytes) const
|
||||||
|
{
|
||||||
|
stringstream os;
|
||||||
|
|
||||||
|
os << "\"";
|
||||||
|
bool expectZeros = false;
|
||||||
|
for (auto const& v: _bytes)
|
||||||
|
{
|
||||||
|
if (expectZeros && v != 0)
|
||||||
|
return {};
|
||||||
|
if (v == 0) expectZeros = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!isprint(v) || v == '"')
|
||||||
|
return {};
|
||||||
|
os << v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "\"";
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes BytesUtils::alignLeft(bytes _bytes) const
|
||||||
|
{
|
||||||
|
return std::move(_bytes) + bytes(32 - _bytes.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes BytesUtils::alignRight(bytes _bytes) const
|
||||||
|
{
|
||||||
|
return bytes(32 - _bytes.size(), 0) + std::move(_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes BytesUtils::applyAlign(
|
||||||
|
Parameter::Alignment _alignment,
|
||||||
|
ABIType& _abiType,
|
||||||
|
bytes _bytes
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
if (_alignment != Parameter::Alignment::None)
|
||||||
|
_abiType.alignDeclared = true;
|
||||||
|
|
||||||
|
switch (_alignment)
|
||||||
|
{
|
||||||
|
case Parameter::Alignment::Left:
|
||||||
|
_abiType.align = ABIType::AlignLeft;
|
||||||
|
return alignLeft(std::move(_bytes));
|
||||||
|
case Parameter::Alignment::Right:
|
||||||
|
_abiType.align = ABIType::AlignRight;
|
||||||
|
return alignRight(std::move(_bytes));
|
||||||
|
default:
|
||||||
|
_abiType.align = ABIType::AlignRight;
|
||||||
|
return alignRight(std::move(_bytes));
|
||||||
|
}
|
||||||
|
}
|
100
test/libsolidity/util/BytesUtils.h
Normal file
100
test/libsolidity/util/BytesUtils.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <test/libsolidity/util/SoltestTypes.h>
|
||||||
|
|
||||||
|
#include <libdevcore/CommonData.h>
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace solidity
|
||||||
|
{
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class that aids conversions from parsed strings to an
|
||||||
|
* isoltest-internal, ABI-based bytes representation and vice-versa.
|
||||||
|
*/
|
||||||
|
class BytesUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
|
/// representation of the boolean number literal. Throws if conversion fails.
|
||||||
|
bytes convertBoolean(std::string const& _literal);
|
||||||
|
|
||||||
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
|
/// representation of the decimal number literal. Throws if conversion fails.
|
||||||
|
bytes convertNumber(std::string const& _literal);
|
||||||
|
|
||||||
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
|
/// representation of the hex literal. Throws if conversion fails.
|
||||||
|
bytes convertHexNumber(std::string const& _literal);
|
||||||
|
|
||||||
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
|
/// representation of the string literal. Throws if conversion fails.
|
||||||
|
bytes convertString(std::string const& _literal);
|
||||||
|
|
||||||
|
/// Converts \param _bytes to a soltest-compliant and human-readable
|
||||||
|
/// string representation of a byte array which is assumed to hold
|
||||||
|
/// an unsigned value.
|
||||||
|
std::string formatUnsigned(bytes const& _bytes) const;
|
||||||
|
|
||||||
|
/// Converts \param _bytes to a soltest-compliant and human-readable
|
||||||
|
/// string representation of a byte array which is assumed to hold
|
||||||
|
/// a signed value.
|
||||||
|
std::string formatSigned(bytes const& _bytes) const;
|
||||||
|
|
||||||
|
/// Converts \param _bytes to a soltest-compliant and human-readable
|
||||||
|
/// string representation of a byte array which is assumed to hold
|
||||||
|
/// a boolean value.
|
||||||
|
std::string formatBoolean(bytes const& _bytes) const;
|
||||||
|
|
||||||
|
/// Converts \param _bytes to a soltest-compliant and human-readable
|
||||||
|
/// string representation of a byte array which is assumed to hold
|
||||||
|
/// a hex value.
|
||||||
|
std::string formatHex(bytes const& _bytes) const;
|
||||||
|
|
||||||
|
/// Converts \param _bytes to a soltest-compliant and human-readable
|
||||||
|
/// string representation of a byte array which is assumed to hold
|
||||||
|
/// a hexString value.
|
||||||
|
std::string formatHexString(bytes const& _bytes) const;
|
||||||
|
|
||||||
|
/// Converts \param _bytes to a soltest-compliant and human-readable
|
||||||
|
/// string representation of a byte array which is assumed to hold
|
||||||
|
/// a string value.
|
||||||
|
std::string formatString(bytes const& _bytes) const;
|
||||||
|
|
||||||
|
/// Left-aligns and pads given _bytes and returns a new
|
||||||
|
/// bytes array.
|
||||||
|
bytes alignLeft(bytes _bytes) const;
|
||||||
|
|
||||||
|
/// Right-aligns and pads given _bytes and returns a new
|
||||||
|
/// bytes array.
|
||||||
|
bytes alignRight(bytes _bytes) const;
|
||||||
|
|
||||||
|
/// Applies given _alignment to _bytes and returns a new
|
||||||
|
/// bytes array.
|
||||||
|
bytes applyAlign(
|
||||||
|
Parameter::Alignment _alignment,
|
||||||
|
ABIType& _abiType,
|
||||||
|
bytes _bytes
|
||||||
|
) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
test/libsolidity/util/ContractABIUtils.cpp
Normal file
87
test/libsolidity/util/ContractABIUtils.cpp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
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/libsolidity/util/ContractABIUtils.h>
|
||||||
|
|
||||||
|
#include <liblangutil/Common.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <regex>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
using namespace dev;
|
||||||
|
using namespace langutil;
|
||||||
|
using namespace solidity;
|
||||||
|
using namespace dev::solidity::test;
|
||||||
|
using namespace std;
|
||||||
|
using namespace soltest;
|
||||||
|
|
||||||
|
dev::solidity::test::ParameterList ContractABIUtils::parametersFromJson(
|
||||||
|
Json::Value const& _contractABI,
|
||||||
|
string const& _functionName
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
ParameterList abiParams;
|
||||||
|
for (auto const& function: _contractABI)
|
||||||
|
if (function["name"] == _functionName)
|
||||||
|
for (auto const& output: function["outputs"])
|
||||||
|
{
|
||||||
|
auto types = fromTypeName(output["type"].asString());
|
||||||
|
for (auto const& type: types)
|
||||||
|
abiParams.push_back(Parameter{bytes(), "", type, FormatInfo{}});
|
||||||
|
}
|
||||||
|
|
||||||
|
return abiParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ABIType> ContractABIUtils::fromTypeName(string const& _type) const
|
||||||
|
{
|
||||||
|
static regex s_boolType{"(bool)"};
|
||||||
|
static regex s_uintType{"(uint\\d*)"};
|
||||||
|
static regex s_intType{"(int\\d*)"};
|
||||||
|
static regex s_bytesType{"(bytes\\d+)"};
|
||||||
|
static regex s_dynBytesType{"(\\bbytes\\b)"};
|
||||||
|
static regex s_stringType{"(string)"};
|
||||||
|
|
||||||
|
vector<ABIType> abiTypes;
|
||||||
|
if (regex_match(_type, s_boolType))
|
||||||
|
abiTypes.push_back(ABIType{ABIType::Boolean, ABIType::AlignRight, 32});
|
||||||
|
else if (regex_match(_type, s_uintType))
|
||||||
|
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
||||||
|
else if (regex_match(_type, s_intType))
|
||||||
|
abiTypes.push_back(ABIType{ABIType::SignedDec, ABIType::AlignRight, 32});
|
||||||
|
else if (regex_match(_type, s_bytesType))
|
||||||
|
abiTypes.push_back(ABIType{ABIType::Hex, ABIType::AlignRight, 32});
|
||||||
|
else if (regex_match(_type, s_dynBytesType))
|
||||||
|
{
|
||||||
|
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
||||||
|
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
||||||
|
abiTypes.push_back(ABIType{ABIType::HexString, ABIType::AlignLeft, 32});
|
||||||
|
}
|
||||||
|
else if (regex_match(_type, s_stringType))
|
||||||
|
{
|
||||||
|
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
||||||
|
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
||||||
|
abiTypes.push_back(ABIType{ABIType::String, ABIType::AlignLeft, 32});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
abiTypes.push_back(ABIType{ABIType::None, ABIType::AlignRight, 0});
|
||||||
|
return abiTypes;
|
||||||
|
}
|
59
test/libsolidity/util/ContractABIUtils.h
Normal file
59
test/libsolidity/util/ContractABIUtils.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <test/libsolidity/util/SoltestTypes.h>
|
||||||
|
|
||||||
|
#include <libdevcore/CommonData.h>
|
||||||
|
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace solidity
|
||||||
|
{
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class that aids conversions from contract ABI types stored in a
|
||||||
|
* Json value to the internal ABIType representation of isoltest.
|
||||||
|
*/
|
||||||
|
class ContractABIUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Parses and translates Solidity's ABI types as Json string into
|
||||||
|
/// a list of internal type representations of isoltest.
|
||||||
|
ParameterList parametersFromJson(
|
||||||
|
Json::Value const& _contractABI,
|
||||||
|
std::string const& _functionName
|
||||||
|
) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Parses and translates a single type and returns a list of
|
||||||
|
/// internal type representations of isoltest.
|
||||||
|
/// Types defined by the ABI will translate to ABITypes
|
||||||
|
/// as follows:
|
||||||
|
/// `bool` -> [`Boolean`]
|
||||||
|
/// `uint` -> [`Unsigned`]
|
||||||
|
/// `string` -> [`Unsigned`, `Unsigned`, `String`]
|
||||||
|
/// `bytes` -> [`Unsigned`, `Unsigned`, `HexString`]
|
||||||
|
/// ...
|
||||||
|
std::vector<ABIType> fromTypeName(std::string const& _type) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
256
test/libsolidity/util/SoltestTypes.h
Normal file
256
test/libsolidity/util/SoltestTypes.h
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libdevcore/CommonData.h>
|
||||||
|
#include <libsolidity/ast/Types.h>
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace solidity
|
||||||
|
{
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All soltest tokens.
|
||||||
|
*/
|
||||||
|
#define SOLT_TOKEN_LIST(T, K) \
|
||||||
|
T(Unknown, "unknown", 0) \
|
||||||
|
T(Invalid, "invalid", 0) \
|
||||||
|
T(EOS, "EOS", 0) \
|
||||||
|
T(Whitespace, "_", 0) \
|
||||||
|
/* punctuations */ \
|
||||||
|
T(LParen, "(", 0) \
|
||||||
|
T(RParen, ")", 0) \
|
||||||
|
T(LBrack, "[", 0) \
|
||||||
|
T(RBrack, "]", 0) \
|
||||||
|
T(LBrace, "{", 0) \
|
||||||
|
T(RBrace, "}", 0) \
|
||||||
|
T(Sub, "-", 0) \
|
||||||
|
T(Colon, ":", 0) \
|
||||||
|
T(Comma, ",", 0) \
|
||||||
|
T(Period, ".", 0) \
|
||||||
|
T(Arrow, "->", 0) \
|
||||||
|
T(Newline, "//", 0) \
|
||||||
|
/* Literals & identifier */ \
|
||||||
|
T(Comment, "#", 0) \
|
||||||
|
T(Number, "number", 0) \
|
||||||
|
T(HexNumber, "hex_number", 0) \
|
||||||
|
T(String, "string", 0) \
|
||||||
|
T(Identifier, "identifier", 0) \
|
||||||
|
/* type keywords */ \
|
||||||
|
K(Ether, "ether", 0) \
|
||||||
|
K(Hex, "hex", 0) \
|
||||||
|
K(Boolean, "boolean", 0) \
|
||||||
|
/* special keywords */ \
|
||||||
|
K(Left, "left", 0) \
|
||||||
|
K(Right, "right", 0) \
|
||||||
|
K(Failure, "FAILURE", 0) \
|
||||||
|
|
||||||
|
namespace soltest
|
||||||
|
{
|
||||||
|
enum class Token : unsigned int {
|
||||||
|
#define T(name, string, precedence) name,
|
||||||
|
SOLT_TOKEN_LIST(T, T)
|
||||||
|
NUM_TOKENS
|
||||||
|
#undef T
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Prints a friendly string representation of \param _token.
|
||||||
|
inline std::string formatToken(Token _token)
|
||||||
|
{
|
||||||
|
switch (_token)
|
||||||
|
{
|
||||||
|
#define T(name, string, precedence) case Token::name: return string;
|
||||||
|
SOLT_TOKEN_LIST(T, T)
|
||||||
|
#undef T
|
||||||
|
default: // Token::NUM_TOKENS:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The purpose of the ABI type is the storage of type information
|
||||||
|
* retrieved while parsing a test. This information is used
|
||||||
|
* for the conversion of human-readable function arguments and
|
||||||
|
* return values to `bytes` and vice-versa.
|
||||||
|
* Defaults to None, a 0-byte representation. 0-bytes
|
||||||
|
* can also be interpreted as Failure, which means
|
||||||
|
* either a REVERT or another EVM failure.
|
||||||
|
*/
|
||||||
|
struct ABIType
|
||||||
|
{
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Failure,
|
||||||
|
Boolean,
|
||||||
|
UnsignedDec,
|
||||||
|
SignedDec,
|
||||||
|
Hex,
|
||||||
|
HexString,
|
||||||
|
String
|
||||||
|
};
|
||||||
|
enum Align
|
||||||
|
{
|
||||||
|
AlignLeft,
|
||||||
|
AlignRight,
|
||||||
|
AlignNone,
|
||||||
|
};
|
||||||
|
Type type = ABIType::None;
|
||||||
|
Align align = ABIType::AlignRight;
|
||||||
|
size_t size = 0;
|
||||||
|
bool alignDeclared = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper that can hold format information retrieved
|
||||||
|
* while scanning through a parameter list in soltest.
|
||||||
|
*/
|
||||||
|
struct FormatInfo
|
||||||
|
{
|
||||||
|
bool newline = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter abstraction used for the encoding and decoding of
|
||||||
|
* function parameter and expectation / return value lists.
|
||||||
|
* A parameter list is usually a comma-separated list of literals.
|
||||||
|
* It should not be possible to call create a parameter holding
|
||||||
|
* an identifier, but if so, the ABI type would be invalid.
|
||||||
|
*/
|
||||||
|
struct Parameter
|
||||||
|
{
|
||||||
|
enum Alignment
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
None,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ABI encoded / decoded `bytes` of values.
|
||||||
|
/// These `bytes` are used to pass values to function calls
|
||||||
|
/// and also to store expected return vales. These are
|
||||||
|
/// compared to the actual result of a function call
|
||||||
|
/// and used for validating it.
|
||||||
|
bytes rawBytes;
|
||||||
|
/// Stores the raw string representation of this parameter.
|
||||||
|
/// Used to print the unformatted arguments of a function call.
|
||||||
|
std::string rawString;
|
||||||
|
/// Types that were used to encode `rawBytes`. Expectations
|
||||||
|
/// are usually comma separated literals. Their type is auto-
|
||||||
|
/// detected and retained in order to format them later on.
|
||||||
|
ABIType abiType;
|
||||||
|
/// Format info attached to the parameter. It handles newlines given
|
||||||
|
/// in the declaration of it.
|
||||||
|
FormatInfo format;
|
||||||
|
/// Stores the parsed alignment, which can be either left(...) or right(...).
|
||||||
|
Alignment alignment = Alignment::None;
|
||||||
|
};
|
||||||
|
using ParameterList = std::vector<Parameter>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the expected result of a function call after it has been executed. This may be a single
|
||||||
|
* return value or a comma-separated list of return values. It also contains the detected input
|
||||||
|
* formats used to convert the values to `bytes` needed for the comparison with the actual result
|
||||||
|
* of a call. In addition to that, it also stores the expected transaction status.
|
||||||
|
* An optional comment can be assigned.
|
||||||
|
*/
|
||||||
|
struct FunctionCallExpectations
|
||||||
|
{
|
||||||
|
/// Representation of the comma-separated (or empty) list of expected result values
|
||||||
|
/// attached to the function call object. It is checked against the actual result of
|
||||||
|
/// a function call when used in test framework.
|
||||||
|
ParameterList result;
|
||||||
|
/// Expected status of the transaction. It can be either
|
||||||
|
/// a REVERT or a different EVM failure (e.g. out-of-gas).
|
||||||
|
bool failure = true;
|
||||||
|
/// A Comment that can be attached to the expectations,
|
||||||
|
/// that is retained and can be displayed.
|
||||||
|
std::string comment;
|
||||||
|
/// ABI encoded `bytes` of parsed expected return values. It is checked
|
||||||
|
/// against the actual result of a function call when used in test framework.
|
||||||
|
bytes rawBytes() const
|
||||||
|
{
|
||||||
|
bytes raw;
|
||||||
|
for (auto const& param: result)
|
||||||
|
raw += param.rawBytes;
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the arguments passed to a function call. This can be a single
|
||||||
|
* argument or a comma-separated list of arguments. It also contains the detected input
|
||||||
|
* formats used to convert the arguments to `bytes` needed for the call.
|
||||||
|
* An optional comment can be assigned.
|
||||||
|
*/
|
||||||
|
struct FunctionCallArgs
|
||||||
|
{
|
||||||
|
/// Types that were used to encode `rawBytes`. Parameters
|
||||||
|
/// are usually comma separated literals. Their type is auto-
|
||||||
|
/// detected and retained in order to format them later on.
|
||||||
|
ParameterList parameters;
|
||||||
|
/// A Comment that can be attached to the expectations,
|
||||||
|
/// that is retained and can be displayed.
|
||||||
|
std::string comment;
|
||||||
|
/// ABI encoded `bytes` of parsed parameters. These `bytes`
|
||||||
|
/// passed to the function call.
|
||||||
|
bytes rawBytes() const
|
||||||
|
{
|
||||||
|
bytes raw;
|
||||||
|
for (auto const& param: parameters)
|
||||||
|
raw += param.rawBytes;
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a function call read from an input stream. It contains the signature, the
|
||||||
|
* arguments, an optional ether value and an expected execution result.
|
||||||
|
*/
|
||||||
|
struct FunctionCall
|
||||||
|
{
|
||||||
|
/// Signature of the function call, e.g. `f(uint256, uint256)`.
|
||||||
|
std::string signature;
|
||||||
|
/// Optional `ether` value that can be send with the call.
|
||||||
|
u256 value;
|
||||||
|
/// Object that holds all function parameters in their `bytes`
|
||||||
|
/// representations given by the contract ABI.
|
||||||
|
FunctionCallArgs arguments;
|
||||||
|
/// Object that holds all function call expectation in
|
||||||
|
/// their `bytes` representations given by the contract ABI.
|
||||||
|
/// They are checked against the actual results and their
|
||||||
|
/// `bytes` representation, as well as the transaction status.
|
||||||
|
FunctionCallExpectations expectations;
|
||||||
|
/// single / multi-line mode will be detected as follows:
|
||||||
|
/// every newline (//) in source results in a function call
|
||||||
|
/// that has its display mode set to multi-mode. Function and
|
||||||
|
/// result parameter lists are an exception: a single parameter
|
||||||
|
/// stores a format information that contains a newline definition.
|
||||||
|
enum DisplayMode {
|
||||||
|
SingleLine,
|
||||||
|
MultiLine
|
||||||
|
};
|
||||||
|
DisplayMode displayMode = DisplayMode::SingleLine;
|
||||||
|
/// Marks this function call as the constructor.
|
||||||
|
bool isConstructor = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,12 +16,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test/libsolidity/util/TestFileParser.h>
|
#include <test/libsolidity/util/TestFileParser.h>
|
||||||
|
|
||||||
|
#include <test/libsolidity/util/BytesUtils.h>
|
||||||
#include <test/Options.h>
|
#include <test/Options.h>
|
||||||
|
|
||||||
#include <liblangutil/Common.h>
|
#include <liblangutil/Common.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <boost/throw_exception.hpp>
|
#include <boost/throw_exception.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@ -33,45 +38,6 @@ using namespace dev::solidity::test;
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace soltest;
|
using namespace soltest;
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
enum class DeclaredAlignment
|
|
||||||
{
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
None,
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bytes alignLeft(bytes _bytes)
|
|
||||||
{
|
|
||||||
return std::move(_bytes) + bytes(32 - _bytes.size(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bytes alignRight(bytes _bytes)
|
|
||||||
{
|
|
||||||
return bytes(32 - _bytes.size(), 0) + std::move(_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bytes applyAlign(DeclaredAlignment _alignment, ABIType& _abiType, bytes _converted)
|
|
||||||
{
|
|
||||||
if (_alignment != DeclaredAlignment::None)
|
|
||||||
_abiType.alignDeclared = true;
|
|
||||||
|
|
||||||
switch (_alignment)
|
|
||||||
{
|
|
||||||
case DeclaredAlignment::Left:
|
|
||||||
_abiType.align = ABIType::AlignLeft;
|
|
||||||
return alignLeft(std::move(_converted));
|
|
||||||
case DeclaredAlignment::Right:
|
|
||||||
_abiType.align = ABIType::AlignRight;
|
|
||||||
return alignRight(std::move(_converted));
|
|
||||||
default:
|
|
||||||
_abiType.align = ABIType::AlignRight;
|
|
||||||
return alignRight(std::move(_converted));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char TestFileParser::Scanner::peek() const noexcept
|
char TestFileParser::Scanner::peek() const noexcept
|
||||||
{
|
{
|
||||||
if (std::distance(m_char, m_line.end()) < 2)
|
if (std::distance(m_char, m_line.end()) < 2)
|
||||||
@ -242,111 +208,125 @@ Parameter TestFileParser::parseParameter()
|
|||||||
Parameter parameter;
|
Parameter parameter;
|
||||||
if (accept(Token::Newline, true))
|
if (accept(Token::Newline, true))
|
||||||
parameter.format.newline = true;
|
parameter.format.newline = true;
|
||||||
auto literal = parseABITypeLiteral();
|
|
||||||
parameter.rawBytes = get<0>(literal);
|
|
||||||
parameter.abiType = get<1>(literal);
|
|
||||||
parameter.rawString = get<2>(literal);
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple<bytes, ABIType, string> TestFileParser::parseABITypeLiteral()
|
|
||||||
{
|
|
||||||
ABIType abiType{ABIType::None, ABIType::AlignNone, 0};
|
|
||||||
DeclaredAlignment alignment{DeclaredAlignment::None};
|
|
||||||
bytes result{toBigEndian(u256{0})};
|
|
||||||
string rawString;
|
|
||||||
bool isSigned = false;
|
bool isSigned = false;
|
||||||
|
|
||||||
if (accept(Token::Left, true))
|
if (accept(Token::Left, true))
|
||||||
{
|
{
|
||||||
rawString += formatToken(Token::Left);
|
parameter.rawString += formatToken(Token::Left);
|
||||||
expect(Token::LParen);
|
expect(Token::LParen);
|
||||||
rawString += formatToken(Token::LParen);
|
parameter.rawString += formatToken(Token::LParen);
|
||||||
alignment = DeclaredAlignment::Left;
|
parameter.alignment = Parameter::Alignment::Left;
|
||||||
}
|
}
|
||||||
if (accept(Token::Right, true))
|
if (accept(Token::Right, true))
|
||||||
{
|
{
|
||||||
rawString += formatToken(Token::Right);
|
parameter.rawString += formatToken(Token::Right);
|
||||||
expect(Token::LParen);
|
expect(Token::LParen);
|
||||||
rawString += formatToken(Token::LParen);
|
parameter.rawString += formatToken(Token::LParen);
|
||||||
alignment = DeclaredAlignment::Right;
|
parameter.alignment = Parameter::Alignment::Right;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (accept(Token::Sub, true))
|
if (accept(Token::Sub, true))
|
||||||
{
|
{
|
||||||
rawString += formatToken(Token::Sub);
|
parameter.rawString += formatToken(Token::Sub);
|
||||||
isSigned = true;
|
isSigned = true;
|
||||||
}
|
}
|
||||||
if (accept(Token::Boolean))
|
if (accept(Token::Boolean))
|
||||||
{
|
{
|
||||||
if (isSigned)
|
if (isSigned)
|
||||||
throw Error(Error::Type::ParserError, "Invalid boolean literal.");
|
throw Error(Error::Type::ParserError, "Invalid boolean literal.");
|
||||||
abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
|
|
||||||
|
parameter.abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
|
||||||
string parsed = parseBoolean();
|
string parsed = parseBoolean();
|
||||||
rawString += parsed;
|
parameter.rawString += parsed;
|
||||||
result = applyAlign(alignment, abiType, convertBoolean(parsed));
|
parameter.rawBytes = BytesUtils().applyAlign(
|
||||||
|
parameter.alignment,
|
||||||
|
parameter.abiType,
|
||||||
|
BytesUtils().convertBoolean(parsed)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (accept(Token::HexNumber))
|
else if (accept(Token::HexNumber))
|
||||||
{
|
{
|
||||||
if (isSigned)
|
if (isSigned)
|
||||||
throw Error(Error::Type::ParserError, "Invalid hex number literal.");
|
throw Error(Error::Type::ParserError, "Invalid hex number literal.");
|
||||||
abiType = ABIType{ABIType::Hex, ABIType::AlignRight, 32};
|
|
||||||
|
parameter.abiType = ABIType{ABIType::Hex, ABIType::AlignRight, 32};
|
||||||
string parsed = parseHexNumber();
|
string parsed = parseHexNumber();
|
||||||
rawString += parsed;
|
parameter.rawString += parsed;
|
||||||
result = applyAlign(alignment, abiType, convertHexNumber(parsed));
|
parameter.rawBytes = BytesUtils().applyAlign(
|
||||||
|
parameter.alignment,
|
||||||
|
parameter.abiType,
|
||||||
|
BytesUtils().convertHexNumber(parsed)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (accept(Token::Hex, true))
|
else if (accept(Token::Hex, true))
|
||||||
{
|
{
|
||||||
if (isSigned)
|
if (isSigned)
|
||||||
throw Error(Error::Type::ParserError, "Invalid hex string literal.");
|
throw Error(Error::Type::ParserError, "Invalid hex string literal.");
|
||||||
if (alignment != DeclaredAlignment::None)
|
if (parameter.alignment != Parameter::Alignment::None)
|
||||||
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
|
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
|
||||||
|
|
||||||
string parsed = parseString();
|
string parsed = parseString();
|
||||||
rawString += "hex\"" + parsed + "\"";
|
parameter.rawString += "hex\"" + parsed + "\"";
|
||||||
result = convertHexNumber(parsed);
|
parameter.rawBytes = BytesUtils().convertHexNumber(parsed);
|
||||||
abiType = ABIType{ABIType::HexString, ABIType::AlignNone, result.size()};
|
parameter.abiType = ABIType{
|
||||||
|
ABIType::HexString, ABIType::AlignNone, parameter.rawBytes.size()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else if (accept(Token::String))
|
else if (accept(Token::String))
|
||||||
{
|
{
|
||||||
if (isSigned)
|
if (isSigned)
|
||||||
throw Error(Error::Type::ParserError, "Invalid string literal.");
|
throw Error(Error::Type::ParserError, "Invalid string literal.");
|
||||||
if (alignment != DeclaredAlignment::None)
|
if (parameter.alignment != Parameter::Alignment::None)
|
||||||
throw Error(Error::Type::ParserError, "String literals cannot be aligned or padded.");
|
throw Error(Error::Type::ParserError, "String literals cannot be aligned or padded.");
|
||||||
abiType = ABIType{ABIType::String, ABIType::AlignLeft, 32};
|
|
||||||
|
parameter.abiType = ABIType{ABIType::String, ABIType::AlignLeft, 32};
|
||||||
string parsed = parseString();
|
string parsed = parseString();
|
||||||
rawString += "\"" + parsed + "\"";
|
parameter.rawString += "\"" + parsed + "\"";
|
||||||
result = applyAlign(DeclaredAlignment::Left, abiType, convertString(parsed));
|
parameter.rawBytes = BytesUtils().applyAlign(
|
||||||
|
Parameter::Alignment::Left,
|
||||||
|
parameter.abiType,
|
||||||
|
BytesUtils().convertString(parsed)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (accept(Token::Number))
|
else if (accept(Token::Number))
|
||||||
{
|
{
|
||||||
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
|
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
|
||||||
abiType = ABIType{type, ABIType::AlignRight, 32};
|
|
||||||
|
parameter.abiType = ABIType{type, ABIType::AlignRight, 32};
|
||||||
string parsed = parseDecimalNumber();
|
string parsed = parseDecimalNumber();
|
||||||
rawString += parsed;
|
parameter.rawString += parsed;
|
||||||
if (isSigned)
|
if (isSigned)
|
||||||
parsed = "-" + parsed;
|
parsed = "-" + parsed;
|
||||||
result = applyAlign(alignment, abiType, convertNumber(parsed));
|
|
||||||
|
parameter.rawBytes = BytesUtils().applyAlign(
|
||||||
|
parameter.alignment,
|
||||||
|
parameter.abiType,
|
||||||
|
BytesUtils().convertNumber(parsed)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (accept(Token::Failure, true))
|
else if (accept(Token::Failure, true))
|
||||||
{
|
{
|
||||||
if (isSigned)
|
if (isSigned)
|
||||||
throw Error(Error::Type::ParserError, "Invalid failure literal.");
|
throw Error(Error::Type::ParserError, "Invalid failure literal.");
|
||||||
abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
|
|
||||||
result = bytes{};
|
parameter.abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
|
||||||
|
parameter.rawBytes = bytes{};
|
||||||
}
|
}
|
||||||
if (alignment != DeclaredAlignment::None)
|
if (parameter.alignment != Parameter::Alignment::None)
|
||||||
{
|
{
|
||||||
expect(Token::RParen);
|
expect(Token::RParen);
|
||||||
rawString += formatToken(Token::RParen);
|
parameter.rawString += formatToken(Token::RParen);
|
||||||
}
|
}
|
||||||
return make_tuple(result, abiType, rawString);
|
|
||||||
}
|
}
|
||||||
catch (std::exception const&)
|
catch (std::exception const&)
|
||||||
{
|
{
|
||||||
throw Error(Error::Type::ParserError, "Literal encoding invalid.");
|
throw Error(Error::Type::ParserError, "Literal encoding invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return parameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
string TestFileParser::parseIdentifierOrTuple()
|
string TestFileParser::parseIdentifierOrTuple()
|
||||||
@ -426,55 +406,6 @@ string TestFileParser::parseString()
|
|||||||
return literal;
|
return literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes TestFileParser::convertBoolean(string const& _literal)
|
|
||||||
{
|
|
||||||
if (_literal == "true")
|
|
||||||
return bytes{true};
|
|
||||||
else if (_literal == "false")
|
|
||||||
return bytes{false};
|
|
||||||
else
|
|
||||||
throw Error(Error::Type::ParserError, "Boolean literal invalid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes TestFileParser::convertNumber(string const& _literal)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return toCompactBigEndian(u256{_literal});
|
|
||||||
}
|
|
||||||
catch (std::exception const&)
|
|
||||||
{
|
|
||||||
throw Error(Error::Type::ParserError, "Number encoding invalid.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes TestFileParser::convertHexNumber(string const& _literal)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_literal.size() % 2)
|
|
||||||
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
|
|
||||||
else
|
|
||||||
return fromHex(_literal);
|
|
||||||
}
|
|
||||||
catch (std::exception const&)
|
|
||||||
{
|
|
||||||
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes TestFileParser::convertString(string const& _literal)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return asBytes(_literal);
|
|
||||||
}
|
|
||||||
catch (std::exception const&)
|
|
||||||
{
|
|
||||||
throw Error(Error::Type::ParserError, "String encoding invalid.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestFileParser::Scanner::readStream(istream& _stream)
|
void TestFileParser::Scanner::readStream(istream& _stream)
|
||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <libdevcore/CommonData.h>
|
#include <libdevcore/CommonData.h>
|
||||||
#include <libsolidity/ast/Types.h>
|
#include <libsolidity/ast/Types.h>
|
||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
|
#include <test/libsolidity/util/SoltestTypes.h>
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@ -33,226 +34,6 @@ namespace solidity
|
|||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* All soltest tokens.
|
|
||||||
*/
|
|
||||||
#define SOLT_TOKEN_LIST(T, K) \
|
|
||||||
T(Unknown, "unknown", 0) \
|
|
||||||
T(Invalid, "invalid", 0) \
|
|
||||||
T(EOS, "EOS", 0) \
|
|
||||||
T(Whitespace, "_", 0) \
|
|
||||||
/* punctuations */ \
|
|
||||||
T(LParen, "(", 0) \
|
|
||||||
T(RParen, ")", 0) \
|
|
||||||
T(LBrack, "[", 0) \
|
|
||||||
T(RBrack, "]", 0) \
|
|
||||||
T(LBrace, "{", 0) \
|
|
||||||
T(RBrace, "}", 0) \
|
|
||||||
T(Sub, "-", 0) \
|
|
||||||
T(Colon, ":", 0) \
|
|
||||||
T(Comma, ",", 0) \
|
|
||||||
T(Period, ".", 0) \
|
|
||||||
T(Arrow, "->", 0) \
|
|
||||||
T(Newline, "//", 0) \
|
|
||||||
/* Literals & identifier */ \
|
|
||||||
T(Comment, "#", 0) \
|
|
||||||
T(Number, "number", 0) \
|
|
||||||
T(HexNumber, "hex_number", 0) \
|
|
||||||
T(String, "string", 0) \
|
|
||||||
T(Identifier, "identifier", 0) \
|
|
||||||
/* type keywords */ \
|
|
||||||
K(Ether, "ether", 0) \
|
|
||||||
K(Hex, "hex", 0) \
|
|
||||||
K(Boolean, "boolean", 0) \
|
|
||||||
/* special keywords */ \
|
|
||||||
K(Left, "left", 0) \
|
|
||||||
K(Right, "right", 0) \
|
|
||||||
K(Failure, "FAILURE", 0) \
|
|
||||||
|
|
||||||
namespace soltest
|
|
||||||
{
|
|
||||||
enum class Token : unsigned int {
|
|
||||||
#define T(name, string, precedence) name,
|
|
||||||
SOLT_TOKEN_LIST(T, T)
|
|
||||||
NUM_TOKENS
|
|
||||||
#undef T
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Prints a friendly string representation of \param _token.
|
|
||||||
inline std::string formatToken(Token _token)
|
|
||||||
{
|
|
||||||
switch (_token)
|
|
||||||
{
|
|
||||||
#define T(name, string, precedence) case Token::name: return string;
|
|
||||||
SOLT_TOKEN_LIST(T, T)
|
|
||||||
#undef T
|
|
||||||
default: // Token::NUM_TOKENS:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The purpose of the ABI type is the storage of type information
|
|
||||||
* retrieved while parsing a test. This information is used
|
|
||||||
* for the conversion of human-readable function arguments and
|
|
||||||
* return values to `bytes` and vice-versa.
|
|
||||||
* Defaults to None, a 0-byte representation. 0-bytes
|
|
||||||
* can also be interpreted as Failure, which means
|
|
||||||
* either a REVERT or another EVM failure.
|
|
||||||
*/
|
|
||||||
struct ABIType
|
|
||||||
{
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Failure,
|
|
||||||
Boolean,
|
|
||||||
UnsignedDec,
|
|
||||||
SignedDec,
|
|
||||||
Hex,
|
|
||||||
HexString,
|
|
||||||
String
|
|
||||||
};
|
|
||||||
enum Align
|
|
||||||
{
|
|
||||||
AlignLeft,
|
|
||||||
AlignRight,
|
|
||||||
AlignNone,
|
|
||||||
};
|
|
||||||
Type type = ABIType::None;
|
|
||||||
Align align = ABIType::AlignRight;
|
|
||||||
size_t size = 0;
|
|
||||||
bool alignDeclared = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper that can hold format information retrieved
|
|
||||||
* while scanning through a parameter list in soltest.
|
|
||||||
*/
|
|
||||||
struct FormatInfo
|
|
||||||
{
|
|
||||||
bool newline = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameter abstraction used for the encoding and decoding of
|
|
||||||
* function parameter and expectation / return value lists.
|
|
||||||
* A parameter list is usually a comma-separated list of literals.
|
|
||||||
* It should not be possible to call create a parameter holding
|
|
||||||
* an identifier, but if so, the ABI type would be invalid.
|
|
||||||
*/
|
|
||||||
struct Parameter
|
|
||||||
{
|
|
||||||
/// ABI encoded / decoded `bytes` of values.
|
|
||||||
/// These `bytes` are used to pass values to function calls
|
|
||||||
/// and also to store expected return vales. These are
|
|
||||||
/// compared to the actual result of a function call
|
|
||||||
/// and used for validating it.
|
|
||||||
bytes rawBytes;
|
|
||||||
/// Stores the raw string representation of this parameter.
|
|
||||||
/// Used to print the unformatted arguments of a function call.
|
|
||||||
std::string rawString;
|
|
||||||
/// Types that were used to encode `rawBytes`. Expectations
|
|
||||||
/// are usually comma separated literals. Their type is auto-
|
|
||||||
/// detected and retained in order to format them later on.
|
|
||||||
ABIType abiType;
|
|
||||||
/// Format info attached to the parameter. It handles newlines given
|
|
||||||
/// in the declaration of it.
|
|
||||||
FormatInfo format;
|
|
||||||
};
|
|
||||||
using ParameterList = std::vector<Parameter>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the expected result of a function call after it has been executed. This may be a single
|
|
||||||
* return value or a comma-separated list of return values. It also contains the detected input
|
|
||||||
* formats used to convert the values to `bytes` needed for the comparison with the actual result
|
|
||||||
* of a call. In addition to that, it also stores the expected transaction status.
|
|
||||||
* An optional comment can be assigned.
|
|
||||||
*/
|
|
||||||
struct FunctionCallExpectations
|
|
||||||
{
|
|
||||||
/// Representation of the comma-separated (or empty) list of expected result values
|
|
||||||
/// attached to the function call object. It is checked against the actual result of
|
|
||||||
/// a function call when used in test framework.
|
|
||||||
ParameterList result;
|
|
||||||
/// Expected status of the transaction. It can be either
|
|
||||||
/// a REVERT or a different EVM failure (e.g. out-of-gas).
|
|
||||||
bool failure = true;
|
|
||||||
/// A Comment that can be attached to the expectations,
|
|
||||||
/// that is retained and can be displayed.
|
|
||||||
std::string comment;
|
|
||||||
/// ABI encoded `bytes` of parsed expected return values. It is checked
|
|
||||||
/// against the actual result of a function call when used in test framework.
|
|
||||||
bytes rawBytes() const
|
|
||||||
{
|
|
||||||
bytes raw;
|
|
||||||
for (auto const& param: result)
|
|
||||||
raw += param.rawBytes;
|
|
||||||
return raw;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the arguments passed to a function call. This can be a single
|
|
||||||
* argument or a comma-separated list of arguments. It also contains the detected input
|
|
||||||
* formats used to convert the arguments to `bytes` needed for the call.
|
|
||||||
* An optional comment can be assigned.
|
|
||||||
*/
|
|
||||||
struct FunctionCallArgs
|
|
||||||
{
|
|
||||||
/// Types that were used to encode `rawBytes`. Parameters
|
|
||||||
/// are usually comma separated literals. Their type is auto-
|
|
||||||
/// detected and retained in order to format them later on.
|
|
||||||
ParameterList parameters;
|
|
||||||
/// A Comment that can be attached to the expectations,
|
|
||||||
/// that is retained and can be displayed.
|
|
||||||
std::string comment;
|
|
||||||
/// ABI encoded `bytes` of parsed parameters. These `bytes`
|
|
||||||
/// passed to the function call.
|
|
||||||
bytes rawBytes() const
|
|
||||||
{
|
|
||||||
bytes raw;
|
|
||||||
for (auto const& param: parameters)
|
|
||||||
raw += param.rawBytes;
|
|
||||||
return raw;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a function call read from an input stream. It contains the signature, the
|
|
||||||
* arguments, an optional ether value and an expected execution result.
|
|
||||||
*/
|
|
||||||
struct FunctionCall
|
|
||||||
{
|
|
||||||
/// Signature of the function call, e.g. `f(uint256, uint256)`.
|
|
||||||
std::string signature;
|
|
||||||
/// Optional `ether` value that can be send with the call.
|
|
||||||
u256 value;
|
|
||||||
/// Object that holds all function parameters in their `bytes`
|
|
||||||
/// representations given by the contract ABI.
|
|
||||||
FunctionCallArgs arguments;
|
|
||||||
/// Object that holds all function call expectation in
|
|
||||||
/// their `bytes` representations given by the contract ABI.
|
|
||||||
/// They are checked against the actual results and their
|
|
||||||
/// `bytes` representation, as well as the transaction status.
|
|
||||||
FunctionCallExpectations expectations;
|
|
||||||
/// single / multi-line mode will be detected as follows:
|
|
||||||
/// every newline (//) in source results in a function call
|
|
||||||
/// that has its display mode set to multi-mode. Function and
|
|
||||||
/// result parameter lists are an exception: a single parameter
|
|
||||||
/// stores a format information that contains a newline definition.
|
|
||||||
enum DisplayMode {
|
|
||||||
SingleLine,
|
|
||||||
MultiLine
|
|
||||||
};
|
|
||||||
DisplayMode displayMode = DisplayMode::SingleLine;
|
|
||||||
/// Marks this function call as the constructor.
|
|
||||||
bool isConstructor = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that is able to parse an additional and well-formed comment section in a Solidity
|
* Class that is able to parse an additional and well-formed comment section in a Solidity
|
||||||
* source file used by the file-based unit test environment. For now, it parses function
|
* source file used by the file-based unit test environment. For now, it parses function
|
||||||
@ -365,9 +146,7 @@ private:
|
|||||||
/// appends it to the internal `bytes` buffer of the parameter. It can also
|
/// appends it to the internal `bytes` buffer of the parameter. It can also
|
||||||
/// store newlines found in the source, that are needed to
|
/// store newlines found in the source, that are needed to
|
||||||
/// format input and output of the interactive update.
|
/// format input and output of the interactive update.
|
||||||
Parameter parseParameter();
|
/// Parses and converts the current literal to its byte representation and
|
||||||
|
|
||||||
/// Parses and converts the current literal to its byte representation and
|
|
||||||
/// preserves the chosen ABI type, as well as a raw, unformatted string representation
|
/// preserves the chosen ABI type, as well as a raw, unformatted string representation
|
||||||
/// of this literal.
|
/// of this literal.
|
||||||
/// Based on the type information retrieved, the driver of this parser may format arguments,
|
/// Based on the type information retrieved, the driver of this parser may format arguments,
|
||||||
@ -376,7 +155,7 @@ private:
|
|||||||
/// Returns invalid ABI type for empty literal. This is needed in order
|
/// Returns invalid ABI type for empty literal. This is needed in order
|
||||||
/// to detect empty expectations. Throws a ParserError if data is encoded incorrectly or
|
/// to detect empty expectations. Throws a ParserError if data is encoded incorrectly or
|
||||||
/// if data type is not supported.
|
/// if data type is not supported.
|
||||||
std::tuple<bytes, ABIType, std::string> parseABITypeLiteral();
|
Parameter parseParameter();
|
||||||
|
|
||||||
/// Recursively parses an identifier or a tuple definition that contains identifiers
|
/// Recursively parses an identifier or a tuple definition that contains identifiers
|
||||||
/// and / or parentheses like `((uint, uint), (uint, (uint, uint)), uint)`.
|
/// and / or parentheses like `((uint, uint), (uint, (uint, uint)), uint)`.
|
||||||
@ -398,22 +177,6 @@ private:
|
|||||||
/// Parses the current string literal.
|
/// Parses the current string literal.
|
||||||
std::string parseString();
|
std::string parseString();
|
||||||
|
|
||||||
/// Tries to convert \param _literal to an unpadded `bytes`
|
|
||||||
/// representation of the boolean number literal. Throws if conversion fails.
|
|
||||||
bytes convertBoolean(std::string const& _literal);
|
|
||||||
|
|
||||||
/// Tries to convert \param _literal to an unpadded `bytes`
|
|
||||||
/// representation of the decimal number literal. Throws if conversion fails.
|
|
||||||
bytes convertNumber(std::string const& _literal);
|
|
||||||
|
|
||||||
/// Tries to convert \param _literal to an unpadded `bytes`
|
|
||||||
/// representation of the hex literal. Throws if conversion fails.
|
|
||||||
bytes convertHexNumber(std::string const& _literal);
|
|
||||||
|
|
||||||
/// Tries to convert \param _literal to an unpadded `bytes`
|
|
||||||
/// representation of the string literal. Throws if conversion fails.
|
|
||||||
bytes convertString(std::string const& _literal);
|
|
||||||
|
|
||||||
/// A scanner instance
|
/// A scanner instance
|
||||||
Scanner m_scanner;
|
Scanner m_scanner;
|
||||||
};
|
};
|
||||||
|
@ -14,11 +14,13 @@
|
|||||||
|
|
||||||
#include <test/libsolidity/util/TestFunctionCall.h>
|
#include <test/libsolidity/util/TestFunctionCall.h>
|
||||||
|
|
||||||
|
#include <test/libsolidity/util/BytesUtils.h>
|
||||||
|
#include <test/libsolidity/util/ContractABIUtils.h>
|
||||||
|
|
||||||
#include <libdevcore/AnsiColorized.h>
|
#include <libdevcore/AnsiColorized.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
#include <regex>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -27,47 +29,6 @@ using namespace solidity;
|
|||||||
using namespace dev::solidity::test;
|
using namespace dev::solidity::test;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
static regex s_boolType{"(bool)"};
|
|
||||||
static regex s_uintType{"(uint\\d*)"};
|
|
||||||
static regex s_intType{"(int\\d*)"};
|
|
||||||
static regex s_bytesType{"(bytes\\d+)"};
|
|
||||||
static regex s_dynBytesType{"(\\bbytes\\b)"};
|
|
||||||
static regex s_stringType{"(string)"};
|
|
||||||
|
|
||||||
/// Translates Solidity's ABI types into the internal type representation of
|
|
||||||
/// soltest.
|
|
||||||
auto contractABITypes(string const& _type) -> vector<ABIType>
|
|
||||||
{
|
|
||||||
vector<ABIType> abiTypes;
|
|
||||||
if (regex_match(_type, s_boolType))
|
|
||||||
abiTypes.push_back(ABIType{ABIType::Boolean, ABIType::AlignRight, 32});
|
|
||||||
else if (regex_match(_type, s_uintType))
|
|
||||||
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
|
||||||
else if (regex_match(_type, s_intType))
|
|
||||||
abiTypes.push_back(ABIType{ABIType::SignedDec, ABIType::AlignRight, 32});
|
|
||||||
else if (regex_match(_type, s_bytesType))
|
|
||||||
abiTypes.push_back(ABIType{ABIType::Hex, ABIType::AlignRight, 32});
|
|
||||||
else if (regex_match(_type, s_dynBytesType))
|
|
||||||
{
|
|
||||||
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
|
||||||
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
|
||||||
abiTypes.push_back(ABIType{ABIType::HexString, ABIType::AlignLeft, 32});
|
|
||||||
}
|
|
||||||
else if (regex_match(_type, s_stringType))
|
|
||||||
{
|
|
||||||
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
|
||||||
abiTypes.push_back(ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32});
|
|
||||||
abiTypes.push_back(ABIType{ABIType::String, ABIType::AlignLeft, 32});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
abiTypes.push_back(ABIType{ABIType::None, ABIType::AlignRight, 0});
|
|
||||||
return abiTypes;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
string TestFunctionCall::format(
|
string TestFunctionCall::format(
|
||||||
ErrorReporter& _errorReporter,
|
ErrorReporter& _errorReporter,
|
||||||
string const& _linePrefix,
|
string const& _linePrefix,
|
||||||
@ -192,21 +153,9 @@ string TestFunctionCall::formatBytesParameters(
|
|||||||
stringstream os;
|
stringstream os;
|
||||||
string functionName{_signature.substr(0, _signature.find("("))};
|
string functionName{_signature.substr(0, _signature.find("("))};
|
||||||
|
|
||||||
auto sizeFold = [](size_t const _a, Parameter const& _b) { return _a + _b.abiType.size; };
|
/// Create parameters from Contract ABI. Used to generate values for
|
||||||
size_t encodingSize = std::accumulate(_params.begin(), _params.end(), size_t{0}, sizeFold);
|
|
||||||
|
|
||||||
/// Infer type from Contract ABI. Used to generate values for
|
|
||||||
/// auto-correction during interactive update routine.
|
/// auto-correction during interactive update routine.
|
||||||
ParameterList abiParams;
|
ParameterList abiParams = ContractABIUtils().parametersFromJson(m_contractABI, functionName);
|
||||||
for (auto const& function: m_contractABI)
|
|
||||||
if (function["name"] == functionName)
|
|
||||||
for (auto const& output: function["outputs"])
|
|
||||||
{
|
|
||||||
auto types = contractABITypes(output["type"].asString());
|
|
||||||
for (auto const& type: types)
|
|
||||||
abiParams.push_back(Parameter{bytes(), "", type, FormatInfo{}});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// If parameter count does not match, take types defined by ABI, but only
|
/// If parameter count does not match, take types defined by ABI, but only
|
||||||
/// if the contract ABI is defined (needed for format tests where the actual
|
/// if the contract ABI is defined (needed for format tests where the actual
|
||||||
@ -214,6 +163,9 @@ string TestFunctionCall::formatBytesParameters(
|
|||||||
ParameterList preferredParams;
|
ParameterList preferredParams;
|
||||||
if (m_contractABI && (_params.size() != abiParams.size()))
|
if (m_contractABI && (_params.size() != abiParams.size()))
|
||||||
{
|
{
|
||||||
|
auto sizeFold = [](size_t const _a, Parameter const& _b) { return _a + _b.abiType.size; };
|
||||||
|
size_t encodingSize = std::accumulate(_params.begin(), _params.end(), size_t{0}, sizeFold);
|
||||||
|
|
||||||
_errorReporter.warning(
|
_errorReporter.warning(
|
||||||
"Encoding does not match byte range. The call returned " +
|
"Encoding does not match byte range. The call returned " +
|
||||||
to_string(_bytes.size()) + " bytes, but " +
|
to_string(_bytes.size()) + " bytes, but " +
|
||||||
@ -294,57 +246,23 @@ string TestFunctionCall::formatBytesRange(
|
|||||||
// be signed. If an unsigned was detected in the expectations,
|
// be signed. If an unsigned was detected in the expectations,
|
||||||
// but the actual result returned a signed, it would be formatted
|
// but the actual result returned a signed, it would be formatted
|
||||||
// incorrectly.
|
// incorrectly.
|
||||||
if (*_bytes.begin() & 0x80)
|
os << BytesUtils().formatUnsigned(_bytes);
|
||||||
os << u2s(fromBigEndian<u256>(_bytes));
|
|
||||||
else
|
|
||||||
os << fromBigEndian<u256>(_bytes);
|
|
||||||
break;
|
break;
|
||||||
case ABIType::SignedDec:
|
case ABIType::SignedDec:
|
||||||
if (*_bytes.begin() & 0x80)
|
os << BytesUtils().formatSigned(_bytes);
|
||||||
os << u2s(fromBigEndian<u256>(_bytes));
|
|
||||||
else
|
|
||||||
os << fromBigEndian<u256>(_bytes);
|
|
||||||
break;
|
break;
|
||||||
case ABIType::Boolean:
|
case ABIType::Boolean:
|
||||||
{
|
os << BytesUtils().formatBoolean(_bytes);
|
||||||
u256 result = fromBigEndian<u256>(_bytes);
|
|
||||||
if (result == 0)
|
|
||||||
os << "false";
|
|
||||||
else if (result == 1)
|
|
||||||
os << "true";
|
|
||||||
else
|
|
||||||
os << result;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case ABIType::Hex:
|
case ABIType::Hex:
|
||||||
{
|
os << BytesUtils().formatHex(_bytes);
|
||||||
string hex{toHex(_bytes, HexPrefix::Add)};
|
|
||||||
boost::algorithm::replace_all(hex, "00", "");
|
|
||||||
os << hex;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case ABIType::HexString:
|
case ABIType::HexString:
|
||||||
os << "hex\"" << toHex(_bytes) << "\"";
|
os << BytesUtils().formatHexString(_bytes);
|
||||||
break;
|
break;
|
||||||
case ABIType::String:
|
case ABIType::String:
|
||||||
{
|
os << BytesUtils().formatString(_bytes);
|
||||||
os << "\"";
|
|
||||||
bool expectZeros = false;
|
|
||||||
for (auto const& v: _bytes)
|
|
||||||
{
|
|
||||||
if (expectZeros && v != 0)
|
|
||||||
return {};
|
|
||||||
if (v == 0) expectZeros = true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!isprint(v) || v == '"')
|
|
||||||
return {};
|
|
||||||
os << v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
os << "\"";
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case ABIType::Failure:
|
case ABIType::Failure:
|
||||||
break;
|
break;
|
||||||
case ABIType::None:
|
case ABIType::None:
|
||||||
|
@ -16,6 +16,8 @@ add_executable(isoltest
|
|||||||
../Options.cpp
|
../Options.cpp
|
||||||
../Common.cpp
|
../Common.cpp
|
||||||
../TestCase.cpp
|
../TestCase.cpp
|
||||||
|
../libsolidity/util/BytesUtils.cpp
|
||||||
|
../libsolidity/util/ContractABIUtils.cpp
|
||||||
../libsolidity/util/TestFileParser.cpp
|
../libsolidity/util/TestFileParser.cpp
|
||||||
../libsolidity/util/TestFunctionCall.cpp
|
../libsolidity/util/TestFunctionCall.cpp
|
||||||
../libsolidity/GasTest.cpp
|
../libsolidity/GasTest.cpp
|
||||||
|
Loading…
Reference in New Issue
Block a user