diff --git a/test/libsolidity/semanticTests/smoke_test.sol b/test/libsolidity/semanticTests/smoke_test.sol index 46b44fbb8..07cd79d0f 100644 --- a/test/libsolidity/semanticTests/smoke_test.sol +++ b/test/libsolidity/semanticTests/smoke_test.sol @@ -1,5 +1,17 @@ +pragma experimental ABIEncoderV2; + contract C { + struct S { + uint a; + uint b; + } + struct T { + uint a; + uint b; + string s; + } uint public state = 0; + bool[2][] flags; constructor(uint _state) public payable { state = _state; } @@ -12,6 +24,9 @@ contract C { function f() payable public returns (uint) { return 2; } + function f(uint a) public returns (uint, uint) { + return (a, a); + } function g() public returns (uint, uint) { return (2, 3); } @@ -42,6 +57,36 @@ contract C { function q(uint a) public returns (uint d) { return a * 7; } + function r() public returns (bool[3] memory) { + return [true, false, true]; + } + function s() public returns (uint[2] memory, uint) { + return ([uint(123), 456], 789); + } + function t1() public returns (S memory) { + return S(23, 42); + } + function t2() public returns (T memory) { + return T(23, 42, "any"); + } + function u() public returns (T[2] memory) { + return [T(23, 42, "any"), T(555, 666, "any")]; + } + function v() public returns (bool[2][] memory) { + return flags; + } + function w1() public returns (string[1] memory) { + return ["any"]; + } + function w2() public returns (string[2] memory) { + return ["any", "any"]; + } + function w3() public returns (string[3] memory) { + return ["any", "any", "any"]; + } + function x() public returns (string[2] memory, string[3] memory) { + return (["any", "any"], ["any", "any", "any"]); + } } // ---- // constructor(), 2 ether: 3 -> @@ -50,17 +95,27 @@ contract C { // _() -> FAILURE // e(uint256): 4 // f() -> 2 +// f(uint256): 3 -> 3, 3 // f(), 1 ether -> 2 // g() -> 2, 3 +// g1() -> FAILURE // h(uint256,uint256): 1, -2 -> 3 // j(bool): true -> false // k(bytes32): 0x10 -> 0x10, 0x10 -// l(): hex"4200ef" -> 7 +// l(): hex"4200efef" -> 8 // m(bytes): 32, 32, 0x20 -> 32, 32, 0x20 // m(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB) // m(bytes): 32, 3, hex"AB33FF" -> 32, 3, hex"ab33ff0000000000000000000000000000000000000000000000000000000000" // n() -> 0x20, 3, "any" // o() -> 0x40, 0x80, 3, "any", 3, "any" // p() -> 0x60, 0x2a, 0xa0, 3, "any", 3, "any" -// q(uint256): 0 -> 0 // q(uint256): 99 -> 693 +// r() -> true, false, true +// s() -> 123, 456, 789 +// t1() -> 23, 42 +// t2() -> 0x20, 23, 42, 0x60, 3, "any" +// v() -> 32, 0 +// w1() -> 0x20, 0x20, 3, "any" +// w2() -> 0x20, 0x40, 0x80, 3, "any", 3, "any" +// w3() -> 0x20, 0x60, 0xa0, 0xe0, 3, "any", 3, "any", 3, "any" +// x() -> 0x40, 0x0100, 0x40, 0x80, 3, "any", 3, "any", 0x60, 0xa0, 0xe0, 3, "any", 3, "any", 3, "any" diff --git a/test/libsolidity/util/BytesUtils.cpp b/test/libsolidity/util/BytesUtils.cpp index b1ce6f8e2..dd2a5166b 100644 --- a/test/libsolidity/util/BytesUtils.cpp +++ b/test/libsolidity/util/BytesUtils.cpp @@ -177,7 +177,7 @@ string BytesUtils::formatHexString(bytes const& _bytes) return os.str(); } -string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff) const +string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff) { stringstream os; @@ -226,3 +226,76 @@ string BytesUtils::formatRawBytes(bytes const& _bytes) return os.str(); } + +string BytesUtils::formatBytes( + bytes const& _bytes, + ABIType const& _abiType +) +{ + stringstream os; + + switch (_abiType.type) + { + case ABIType::UnsignedDec: + // Check if the detected type was wrong and if this could + // be signed. If an unsigned was detected in the expectations, + // but the actual result returned a signed, it would be formatted + // incorrectly. + if (*_bytes.begin() & 0x80) + os << formatSigned(_bytes); + else + os << formatUnsigned(_bytes); + break; + case ABIType::SignedDec: + os << formatSigned(_bytes); + break; + case ABIType::Boolean: + os << formatBoolean(_bytes); + break; + case ABIType::Hex: + os << formatHex(_bytes); + break; + case ABIType::HexString: + os << formatHexString(_bytes); + break; + case ABIType::String: + os << formatString(_bytes); + break; + case ABIType::Failure: + break; + case ABIType::None: + break; + } + return os.str(); +} + +string BytesUtils::formatBytesRange( + bytes _bytes, + dev::solidity::test::ParameterList const& _parameters, + bool _highlight +) +{ + stringstream os; + auto it = _bytes.begin(); + + for (auto const& parameter: _parameters) + { + bytes byteRange{it, it + static_cast(parameter.abiType.size)}; + + if (!parameter.matchesBytes(byteRange)) + AnsiColorized( + os, + _highlight, + {dev::formatting::RED_BACKGROUND} + ) << formatBytes(byteRange, parameter.abiType); + else + os << parameter.rawString; + + + it += static_cast(parameter.abiType.size); + if (¶meter != &_parameters.back()) + os << ", "; + } + return os.str(); +} + diff --git a/test/libsolidity/util/BytesUtils.h b/test/libsolidity/util/BytesUtils.h index fc77442cf..93ba06cd6 100644 --- a/test/libsolidity/util/BytesUtils.h +++ b/test/libsolidity/util/BytesUtils.h @@ -91,20 +91,33 @@ public: /// a hexString value. static std::string formatHexString(bytes const& _bytes); + /// Converts \param _bytes to a soltest-compliant and human-readable + /// string representation of a byte array which is assumed to hold + /// a string value. + static std::string formatString(bytes const& _bytes, size_t _cutOff); + + static std::string formatString(bytes const& _bytes) + { + return formatString(_bytes, _bytes.size()); + } + /// Returns a string representation of given _bytes. Adds a newline /// every 32 bytes to increase readability. /// Used to print returned bytes from function calls to the commandline. static std::string formatRawBytes(bytes const& _bytes); - /// 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, size_t _cutOff) const; + /// Formats given _bytes with type information passed in _abiType. + static std::string formatBytes(bytes const& _bytes, ABIType const& _abiType); - std::string formatString(bytes const& _bytes) const - { - return formatString(_bytes, _bytes.size()); - } + /// Formats given _bytes with type information passed in _abiTypes. + /// Prints obtained result if it does not match the expectation + /// and prints the expected result otherwise. + /// Highlights parameter only if it does not match. + static std::string formatBytesRange( + bytes _bytes, + ParameterList const& _parameters, + bool _highlight + ); }; } diff --git a/test/libsolidity/util/ContractABIUtils.cpp b/test/libsolidity/util/ContractABIUtils.cpp index ec9cbcba0..eb40f31dd 100644 --- a/test/libsolidity/util/ContractABIUtils.cpp +++ b/test/libsolidity/util/ContractABIUtils.cpp @@ -17,12 +17,18 @@ #include +#include + #include #include +#include +#include +#include #include #include +#include #include #include @@ -33,55 +39,266 @@ 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 +namespace { - ParameterList abiParams; + +using ParameterList = dev::solidity::test::ParameterList; + +size_t arraySize(string const& _arrayType) +{ + auto leftBrack = _arrayType.find("["); + auto rightBrack = _arrayType.rfind("]"); + + soltestAssert( + leftBrack != string::npos && + rightBrack != string::npos && + rightBrack == _arrayType.size() - 1 && + leftBrack < rightBrack, + "" + ); + + string size = _arrayType.substr(leftBrack + 1, rightBrack - leftBrack - 1); + + return static_cast(stoi(size)); +} + +bool isBool(string const& _type) +{ + return _type == "bool"; +} + +bool isUint(string const& _type) +{ + return regex_match(_type, regex{"uint\\d*"}); +} + +bool isInt(string const& _type) +{ + return regex_match(_type, regex{"int\\d*"}); +} + +bool isFixedBytes(string const& _type) +{ + return regex_match(_type, regex{"bytes\\d+"}); +} + +bool isBytes(string const& _type) +{ + return regex_match(_type, regex{"\\bbytes\\b"}); +} + +bool isString(string const& _type) +{ + return _type == "string"; +} + +bool isFixedBoolArray(string const& _type) +{ + return regex_match(_type, regex{"bool\\[\\d+\\]"}); +} + +bool isFixedUintArray(string const& _type) +{ + return regex_match(_type, regex{"uint\\d*\\[\\d+\\]"}); +} + +bool isFixedIntArray(string const& _type) +{ + return regex_match(_type, regex{"int\\d*\\[\\d+\\]"}); +} + +bool isFixedStringArray(string const& _type) +{ + return regex_match(_type, regex{"string\\[\\d+\\]"}); +} + +bool isTuple(string const& _type) +{ + return _type == "tuple"; +} + +bool isFixedTupleArray(string const& _type) +{ + return regex_match(_type, regex{"tuple\\[\\d+\\]"}); +} + +string functionSignatureFromABI(Json::Value const& _functionABI) +{ + auto inputs = _functionABI["inputs"]; + string signature = {_functionABI["name"].asString() + "("}; + size_t parameterCount = 0; + + for (auto const& input: inputs) + { + parameterCount++; + signature += input["type"].asString(); + if (parameterCount < inputs.size()) + signature += ","; + } + + return signature + ")"; +} + +} + +boost::optional ContractABIUtils::parametersFromJsonOutputs( + ErrorReporter& _errorReporter, + Json::Value const& _contractABI, + string const& _functionSignature +) +{ + if (!_contractABI) + return boost::none; + for (auto const& function: _contractABI) - if (function["name"] == _functionName) + if (_functionSignature == functionSignatureFromABI(function)) + { + ParameterList inplaceTypeParams; + ParameterList dynamicTypeParams; + ParameterList finalParams; + for (auto const& output: function["outputs"]) { - auto types = fromTypeName(output["type"].asString()); - for (auto const& type: types) - abiParams.push_back(Parameter{bytes(), "", type, FormatInfo{}}); - } + string type = output["type"].asString(); - return abiParams; + ABITypes inplaceTypes; + ABITypes dynamicTypes; + + if (appendTypesFromName(output, inplaceTypes, dynamicTypes)) + { + for (auto const& type: inplaceTypes) + inplaceTypeParams.push_back(Parameter{bytes(), "", type, FormatInfo{}}); + for (auto const& type: dynamicTypes) + dynamicTypeParams.push_back(Parameter{bytes(), "", type, FormatInfo{}}); + } + else + { + _errorReporter.warning( + "Could not convert \"" + type + + "\" to internal ABI type representation. Falling back to default encoding." + ); + return boost::none; + } + + finalParams += inplaceTypeParams; + + inplaceTypeParams.clear(); + } + return boost::optional(finalParams + dynamicTypeParams); + } + + return boost::none; } -std::vector ContractABIUtils::fromTypeName(string const& _type) const +bool ContractABIUtils::appendTypesFromName( + Json::Value const& _functionOutput, + ABITypes& _inplaceTypes, + ABITypes& _dynamicTypes, + bool _isCompoundType +) { - 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)"}; + string type = _functionOutput["type"].asString(); + if (isBool(type)) + _inplaceTypes.push_back(ABIType{ABIType::Boolean}); + else if (isUint(type)) + _inplaceTypes.push_back(ABIType{ABIType::UnsignedDec}); + else if (isInt(type)) + _inplaceTypes.push_back(ABIType{ABIType::SignedDec}); + else if (isFixedBytes(type)) + _inplaceTypes.push_back(ABIType{ABIType::Hex}); + else if (isString(type)) + { + _inplaceTypes.push_back(ABIType{ABIType::Hex}); - vector 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}); + if (_isCompoundType) + _dynamicTypes.push_back(ABIType{ABIType::Hex}); + + _dynamicTypes.push_back(ABIType{ABIType::UnsignedDec}); + _dynamicTypes.push_back(ABIType{ABIType::String, ABIType::AlignLeft}); } - else if (regex_match(_type, s_stringType)) + else if (isTuple(type)) { - 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}); + ABITypes inplaceTypes; + ABITypes dynamicTypes; + + for (auto const& component: _functionOutput["components"]) + appendTypesFromName(component, inplaceTypes, dynamicTypes, true); + _dynamicTypes += inplaceTypes + dynamicTypes; + } + else if (isFixedBoolArray(type)) + _inplaceTypes += vector(arraySize(type), ABIType{ABIType::Boolean}); + else if (isFixedUintArray(type)) + _inplaceTypes += vector(arraySize(type), ABIType{ABIType::UnsignedDec}); + else if (isFixedIntArray(type)) + _inplaceTypes += vector(arraySize(type), ABIType{ABIType::SignedDec}); + else if (isFixedStringArray(type)) + { + _inplaceTypes.push_back(ABIType{ABIType::Hex}); + + _dynamicTypes += vector(arraySize(type), ABIType{ABIType::Hex}); + + for (size_t i = 0; i < arraySize(type); i++) + { + _dynamicTypes.push_back(ABIType{ABIType::UnsignedDec}); + _dynamicTypes.push_back(ABIType{ABIType::String, ABIType::AlignLeft}); + } + } + else if (isBytes(type)) + return false; + else if (isFixedTupleArray(type)) + return false; + else + return false; + + return true; +} + +void ContractABIUtils::overwriteParameters( + ErrorReporter& _errorReporter, + dev::solidity::test::ParameterList& _targetParameters, + dev::solidity::test::ParameterList const& _sourceParameters +) +{ + boost::for_each( + _sourceParameters, + _targetParameters, + boost::bind( + [&](Parameter _a, Parameter& _b) -> void + { + if ( + _a.abiType.size != _b.abiType.size || + _a.abiType.type != _b.abiType.type + ) + { + _errorReporter.warning("Type or size of parameter(s) does not match."); + _b = _a; + } + }, + _1, + _2 + ) + ); +} + +dev::solidity::test::ParameterList ContractABIUtils::preferredParameters( + ErrorReporter& _errorReporter, + dev::solidity::test::ParameterList const& _targetParameters, + dev::solidity::test::ParameterList const& _sourceParameters, + bytes const& _bytes +) +{ + if (_targetParameters.size() != _sourceParameters.size()) + { + auto sizeFold = [](size_t const _a, Parameter const& _b) { return _a + _b.abiType.size; }; + size_t encodingSize = accumulate(_targetParameters.begin(), _targetParameters.end(), size_t{0}, sizeFold); + + _errorReporter.warning( + "Encoding does not match byte range. The call returned " + + to_string(_bytes.size()) + " bytes, but " + + to_string(encodingSize) + " bytes were expected." + ); + return _sourceParameters; } else - abiTypes.push_back(ABIType{ABIType::None, ABIType::AlignRight, 0}); - return abiTypes; + return _targetParameters; } diff --git a/test/libsolidity/util/ContractABIUtils.h b/test/libsolidity/util/ContractABIUtils.h index cafd63bac..13b58699b 100644 --- a/test/libsolidity/util/ContractABIUtils.h +++ b/test/libsolidity/util/ContractABIUtils.h @@ -16,6 +16,8 @@ #include +#include + #include #include @@ -27,6 +29,8 @@ namespace solidity namespace test { +using ABITypes = std::vector; + /** * Utility class that aids conversions from contract ABI types stored in a * Json value to the internal ABIType representation of isoltest. @@ -36,10 +40,30 @@ class ContractABIUtils public: /// Parses and translates Solidity's ABI types as Json string into /// a list of internal type representations of isoltest. - ParameterList parametersFromJson( + /// Creates parameters from Contract ABI and is used to generate values for + /// auto-correction during interactive update routine. + static boost::optional parametersFromJsonOutputs( + ErrorReporter& _errorReporter, Json::Value const& _contractABI, - std::string const& _functionName - ) const; + std::string const& _functionSignature + ); + + /// Overwrites _targetParameters if ABI types or sizes given + /// by _sourceParameters do not match. + static void overwriteParameters( + ErrorReporter& _errorReporter, + ParameterList& _targetParameters, + ParameterList const& _sourceParameters + ); + + /// If parameter count does not match, take types defined _sourceParameters + /// and create a warning if so. + static ParameterList preferredParameters( + ErrorReporter& _errorReporter, + ParameterList const& _targetParameters, + ParameterList const& _sourceParameters, + bytes const& _bytes + ); private: /// Parses and translates a single type and returns a list of @@ -51,7 +75,12 @@ private: /// `string` -> [`Unsigned`, `Unsigned`, `String`] /// `bytes` -> [`Unsigned`, `Unsigned`, `HexString`] /// ... - std::vector fromTypeName(std::string const& _type) const; + static bool appendTypesFromName( + Json::Value const& _functionOutput, + ABITypes& _inplaceTypes, + ABITypes& _dynamicTypes, + bool _isCompoundType = false + ); }; } diff --git a/test/libsolidity/util/TestFileParser.cpp b/test/libsolidity/util/TestFileParser.cpp index 64f4bc135..bd283960e 100644 --- a/test/libsolidity/util/TestFileParser.cpp +++ b/test/libsolidity/util/TestFileParser.cpp @@ -309,7 +309,7 @@ Parameter TestFileParser::parseParameter() throw Error(Error::Type::ParserError, "String literals cannot be aligned or padded."); string parsed = parseString(); - parameter.abiType = {ABIType::String, ABIType::AlignLeft, parsed.size()}; + parameter.abiType = ABIType{ABIType::String, ABIType::AlignLeft, parsed.size()}; parameter.rawString += "\"" + parsed + "\""; parameter.rawBytes = BytesUtils::applyAlign( Parameter::Alignment::Left, diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index 4f401bf1f..d22c3b3f0 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -98,7 +99,6 @@ string TestFunctionCall::format( string result; if (!_renderResult) { - bytes output = m_call.expectations.rawBytes(); bool const isFailure = m_call.expectations.failure; result = isFailure ? failure : @@ -154,130 +154,49 @@ string TestFunctionCall::formatBytesParameters( ErrorReporter& _errorReporter, bytes const& _bytes, string const& _signature, - dev::solidity::test::ParameterList const& _params, + dev::solidity::test::ParameterList const& _parameters, bool _highlight ) const { using ParameterList = dev::solidity::test::ParameterList; stringstream os; - string functionName{_signature.substr(0, _signature.find("("))}; - - /// Create parameters from Contract ABI. Used to generate values for - /// auto-correction during interactive update routine. - ParameterList abiParams = ContractABIUtils().parametersFromJson(m_contractABI, functionName); - - /// 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 - /// result does not matter). - ParameterList preferredParams; - 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( - "Encoding does not match byte range. The call returned " + - to_string(_bytes.size()) + " bytes, but " + - to_string(encodingSize) + " bytes were expected." - ); - preferredParams = abiParams; - } - else - preferredParams = _params; - - /// If output is empty, do not format anything. if (_bytes.empty()) return {}; - /// Format output bytes with the given parameters. ABI type takes precedence if: - /// - size of ABI type is greater - /// - given expected type does not match and needs to be overridden in order - /// to generate a valid output of the parameter - auto it = _bytes.begin(); - auto abiParam = abiParams.begin(); - size_t paramIndex = 1; - for (auto const& param: preferredParams) - { - size_t size = param.abiType.size; - if (m_contractABI) - size = std::max((*abiParam).abiType.size, param.abiType.size); - - long offset = static_cast(size); - auto offsetIter = it + offset; - bytes byteRange{it, offsetIter}; - - /// Override type with ABI type if given one does not match. - auto type = param.abiType; - if (m_contractABI) - if ((*abiParam).abiType.type > param.abiType.type) - { - type = (*abiParam).abiType; - _errorReporter.warning( - "Type of parameter " + to_string(paramIndex) + - " does not match the one inferred from ABI." - ); - } _errorReporter.warning("The call to \"" + _signature + "\" returned \n" + BytesUtils::formatRawBytes(_bytes)); - /// Prints obtained result if it does not match the expectation - /// and prints the expected result otherwise. - /// Highlights parameter only if it does not match. - if (byteRange != param.rawBytes) - AnsiColorized( - os, - _highlight, - {dev::formatting::RED_BACKGROUND} - ) << formatBytesRange(byteRange, type); - else - os << param.rawString; + boost::optional abiParams = ContractABIUtils::parametersFromJsonOutputs( + _errorReporter, + m_contractABI, + _signature + ); - if (abiParam != abiParams.end()) - abiParam++; - - it += offset; - paramIndex++; - if (¶m != &preferredParams.back()) - os << ", "; - } - return os.str(); -} - -string TestFunctionCall::formatBytesRange( - bytes const& _bytes, - ABIType const& _abiType -) const -{ - stringstream os; - - switch (_abiType.type) + if (abiParams) { - case ABIType::UnsignedDec: - // Check if the detected type was wrong and if this could - // be signed. If an unsigned was detected in the expectations, - // but the actual result returned a signed, it would be formatted - // incorrectly. - os << BytesUtils().formatUnsigned(_bytes); - break; - case ABIType::SignedDec: - os << BytesUtils().formatSigned(_bytes); - break; - case ABIType::Boolean: - os << BytesUtils().formatBoolean(_bytes); - break; - case ABIType::Hex: - os << BytesUtils().formatHex(_bytes); - break; - case ABIType::HexString: - os << BytesUtils().formatHexString(_bytes); - break; - case ABIType::String: - os << BytesUtils().formatString(_bytes, _abiType.size); - break; - case ABIType::Failure: - break; - case ABIType::None: - break; + boost::optional preferredParams = ContractABIUtils::preferredParameters( + _errorReporter, + _parameters, + abiParams.get(), + _bytes + ); + + if (preferredParams) + { + ContractABIUtils::overwriteParameters(_errorReporter, preferredParams.get(), abiParams.get()); + os << BytesUtils::formatBytesRange(_bytes, preferredParams.get(), _highlight); + } + } + else + { + ParameterList defaultParameters; + fill_n( + back_inserter(defaultParameters), + ceil(_bytes.size() / 32), + Parameter{bytes(), "", ABIType{ABIType::UnsignedDec}, FormatInfo{}} + ); + ContractABIUtils::overwriteParameters(_errorReporter, defaultParameters, _parameters); + os << BytesUtils::formatBytesRange(_bytes, defaultParameters, _highlight); } return os.str(); } @@ -289,7 +208,6 @@ string TestFunctionCall::formatRawParameters( { stringstream os; for (auto const& param: _params) - { if (!param.rawString.empty()) { if (param.format.newline) @@ -298,7 +216,6 @@ string TestFunctionCall::formatRawParameters( if (¶m != &_params.back()) os << ", "; } - } return os.str(); }