Skip to content

Commit d6b9b41

Browse files
aarltchriseth
authored andcommitted
[isoltest] Add support for fixed point types.
1 parent fe0d027 commit d6b9b41

File tree

9 files changed

+175
-21
lines changed

9 files changed

+175
-21
lines changed

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ detect_stray_source_files("${libsolidity_sources}" "libsolidity/")
108108

109109
set(libsolidity_util_sources
110110
libsolidity/util/BytesUtils.cpp
111+
libsolidity/util/BytesUtilsTests.cpp
111112
libsolidity/util/BytesUtils.h
112113
libsolidity/util/ContractABIUtils.cpp
113114
libsolidity/util/ContractABIUtils.h

test/libsolidity/util/BytesUtils.cpp

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,13 @@
1717
// SPDX-License-Identifier: GPL-3.0
1818

1919
#include <test/libsolidity/util/BytesUtils.h>
20-
2120
#include <test/libsolidity/util/ContractABIUtils.h>
2221
#include <test/libsolidity/util/SoltestErrors.h>
2322

24-
#include <liblangutil/Common.h>
25-
2623
#include <libsolutil/CommonData.h>
27-
#include <libsolutil/StringUtils.h>
2824

2925
#include <boost/algorithm/string.hpp>
3026

31-
#include <fstream>
3227
#include <iomanip>
3328
#include <memory>
3429
#include <regex>
@@ -96,6 +91,22 @@ bytes BytesUtils::convertNumber(string const& _literal)
9691
}
9792
}
9893

94+
bytes BytesUtils::convertFixedPoint(string const& _literal, size_t& o_fractionalDigits)
95+
{
96+
size_t dotPos = _literal.find('.');
97+
string valueInteger = _literal.substr(0, dotPos);
98+
string valueFraction = _literal.substr(dotPos + 1);
99+
o_fractionalDigits = valueFraction.length();
100+
try
101+
{
102+
return util::toBigEndian(u256(valueInteger + valueFraction));
103+
}
104+
catch (std::exception const&)
105+
{
106+
BOOST_THROW_EXCEPTION(TestParserError("Number encoding invalid."));
107+
}
108+
}
109+
99110
bytes BytesUtils::convertHexNumber(string const& _literal)
100111
{
101112
try
@@ -206,6 +217,28 @@ string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff)
206217
return os.str();
207218
}
208219

220+
std::string BytesUtils::formatFixedPoint(bytes const& _bytes, bool _signed, size_t _fractionalDigits)
221+
{
222+
string decimal;
223+
bool negative = false;
224+
if (_signed)
225+
{
226+
s256 signedValue{u2s(fromBigEndian<u256>(_bytes))};
227+
negative = (signedValue < 0);
228+
decimal = signedValue.str();
229+
}
230+
else
231+
decimal = fromBigEndian<u256>(_bytes).str();
232+
if (_fractionalDigits > 0)
233+
{
234+
size_t numDigits = decimal.length() - (negative ? 1 : 0);
235+
if (_fractionalDigits > numDigits)
236+
decimal.insert(negative ? 1 : 0, string(_fractionalDigits - numDigits, '0'));
237+
decimal.insert(decimal.length() - _fractionalDigits, ".");
238+
}
239+
return decimal;
240+
}
241+
209242
string BytesUtils::formatRawBytes(
210243
bytes const& _bytes,
211244
solidity::frontend::test::ParameterList const& _parameters,
@@ -296,8 +329,11 @@ string BytesUtils::formatBytes(
296329
case ABIType::String:
297330
os << formatString(_bytes, _bytes.size() - countRightPaddedZeros(_bytes));
298331
break;
299-
case ABIType::Failure:
332+
case ABIType::UnsignedFixedPoint:
333+
case ABIType::SignedFixedPoint:
334+
os << formatFixedPoint(_bytes, _abiType.type == ABIType::SignedFixedPoint, _abiType.fractionalDigits);
300335
break;
336+
case ABIType::Failure:
301337
case ABIType::None:
302338
break;
303339
}

test/libsolidity/util/BytesUtils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ class BytesUtils
5454
/// representation of the decimal number literal. Throws if conversion fails.
5555
static bytes convertNumber(std::string const& _literal);
5656

57+
/// Tries to convert \param _literal to an unpadded `bytes`
58+
/// representation of the decimal number literal. Throws if conversion fails.
59+
static bytes convertFixedPoint(std::string const& _literal, size_t& o_fractionalDigits);
60+
5761
/// Tries to convert \param _literal to an unpadded `bytes`
5862
/// representation of the hex literal. Throws if conversion fails.
5963
static bytes convertHexNumber(std::string const& _literal);
@@ -98,6 +102,10 @@ class BytesUtils
98102
return formatString(_bytes, _bytes.size());
99103
}
100104

105+
/// Converts \param _bytes to a soltest-compliant and human-readable
106+
/// decimal string representation of a byte array. Format of \param _bytes is binary.
107+
static std::string formatFixedPoint(bytes const& _bytes, bool _signed, size_t _fractionalDigits);
108+
101109
/// Used to print returned bytes from function calls to the commandline.
102110
/// Returns a string representation of given _bytes in ranges of 32 bytes.
103111
/// If _withSignature is true, the first 4 bytes will be formatted separately.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
// SPDX-License-Identifier: GPL-3.0
18+
19+
#include <boost/test/unit_test.hpp>
20+
21+
#include <test/libsolidity/util/BytesUtils.h>
22+
23+
#include <libsolutil/CommonData.h>
24+
25+
using namespace std;
26+
using namespace solidity::util;
27+
using namespace solidity::test;
28+
29+
namespace solidity::frontend::test
30+
{
31+
32+
BOOST_AUTO_TEST_SUITE(BytesUtilsTest)
33+
34+
BOOST_AUTO_TEST_CASE(format_fixed)
35+
{
36+
BOOST_CHECK_EQUAL(
37+
BytesUtils::formatFixedPoint(toBigEndian(u256{0}), true, 2),
38+
".00"
39+
);
40+
BOOST_CHECK_EQUAL(
41+
BytesUtils::formatFixedPoint(toBigEndian(u256{1}), true, 2),
42+
".01"
43+
);
44+
BOOST_CHECK_EQUAL(
45+
BytesUtils::formatFixedPoint(toBigEndian(u256{123}), true, 2),
46+
"1.23"
47+
);
48+
BOOST_CHECK_EQUAL(
49+
BytesUtils::formatFixedPoint(toBigEndian(u256{-1}), true, 2),
50+
"-.01"
51+
);
52+
BOOST_CHECK_EQUAL(
53+
BytesUtils::formatFixedPoint(toBigEndian(u256{-12}), true, 2),
54+
"-.12"
55+
);
56+
BOOST_CHECK_EQUAL(
57+
BytesUtils::formatFixedPoint(toBigEndian(u256{-123}), true, 2),
58+
"-1.23"
59+
);
60+
BOOST_CHECK_EQUAL(
61+
BytesUtils::formatFixedPoint(toBigEndian(u256{-1234}), true, 2),
62+
"-12.34"
63+
);
64+
BOOST_CHECK_EQUAL(
65+
BytesUtils::formatFixedPoint(toBigEndian(u256{-12345}), true, 2),
66+
"-123.45"
67+
);
68+
BOOST_CHECK_EQUAL(
69+
BytesUtils::formatFixedPoint(toBigEndian(u256{-123456}), true, 2),
70+
"-1234.56"
71+
);
72+
BOOST_CHECK_EQUAL(
73+
BytesUtils::formatFixedPoint(toBigEndian(u256{-1234567}), true, 2),
74+
"-12345.67"
75+
);
76+
}
77+
78+
79+
80+
BOOST_AUTO_TEST_SUITE_END()
81+
82+
}

test/libsolidity/util/ContractABIUtils.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#include <test/libsolidity/util/SoltestErrors.h>
2222

23+
#include <libsolidity/ast/Types.h>
24+
#include <libsolidity/ast/TypeProvider.h>
2325
#include <libsolutil/FunctionSelector.h>
2426
#include <libsolutil/CommonData.h>
2527

@@ -124,6 +126,21 @@ bool isFixedTupleArray(string const& _type)
124126
return regex_match(_type, regex{"tuple\\[\\d+\\]"});
125127
}
126128

129+
optional<ABIType> isFixedPoint(string const& type)
130+
{
131+
optional<ABIType> fixedPointType;
132+
smatch matches;
133+
if (regex_match(type, matches, regex{"(u?)fixed(\\d+)x(\\d+)"}))
134+
{
135+
ABIType abiType(ABIType::SignedFixedPoint);
136+
if (matches[1].str() == "u")
137+
abiType.type = ABIType::UnsignedFixedPoint;
138+
abiType.fractionalDigits = static_cast<unsigned>(std::stoi(matches[3].str()));
139+
fixedPointType = abiType;
140+
}
141+
return fixedPointType;
142+
}
143+
127144
string functionSignatureFromABI(Json::Value const& _functionABI)
128145
{
129146
auto inputs = _functionABI["inputs"];
@@ -245,6 +262,8 @@ bool ContractABIUtils::appendTypesFromName(
245262
_dynamicTypes.push_back(ABIType{ABIType::String, ABIType::AlignLeft});
246263
}
247264
}
265+
else if (optional<ABIType> fixedPointType = isFixedPoint(type))
266+
_inplaceTypes.push_back(*fixedPointType);
248267
else if (isBytes(type))
249268
return false;
250269
else if (isFixedTupleArray(type))
@@ -270,7 +289,8 @@ void ContractABIUtils::overwriteParameters(
270289
{
271290
if (
272291
_a.abiType.size != _b.abiType.size ||
273-
_a.abiType.type != _b.abiType.type
292+
_a.abiType.type != _b.abiType.type ||
293+
_a.abiType.fractionalDigits != _b.abiType.fractionalDigits
274294
)
275295
{
276296
_errorReporter.warning("Type or size of parameter(s) does not match.");

test/libsolidity/util/SoltestTypes.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ struct ABIType
107107
SignedDec,
108108
Hex,
109109
HexString,
110-
String
110+
String,
111+
UnsignedFixedPoint,
112+
SignedFixedPoint
111113
};
112114
enum Align
113115
{
@@ -125,6 +127,9 @@ struct ABIType
125127
Type type = ABIType::None;
126128
Align align = ABIType::AlignRight;
127129
size_t size = 32;
130+
131+
size_t fractionalDigits = 0;
132+
128133
bool alignDeclared = false;
129134
};
130135

test/libsolidity/util/TestFileParser.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -407,11 +407,17 @@ Parameter TestFileParser::parseParameter()
407407
if (isSigned)
408408
parsed = "-" + parsed;
409409

410-
parameter.rawBytes = BytesUtils::applyAlign(
411-
parameter.alignment,
412-
parameter.abiType,
413-
BytesUtils::convertNumber(parsed)
414-
);
410+
if (parsed.find('.') == string::npos)
411+
parameter.rawBytes = BytesUtils::applyAlign(
412+
parameter.alignment,
413+
parameter.abiType,
414+
BytesUtils::convertNumber(parsed)
415+
);
416+
else
417+
{
418+
parameter.abiType.type = isSigned ? ABIType::SignedFixedPoint : ABIType::UnsignedFixedPoint;
419+
parameter.rawBytes = BytesUtils::convertFixedPoint(parsed, parameter.abiType.fractionalDigits);
420+
}
415421
}
416422
else if (accept(Token::Failure, true))
417423
{
@@ -667,7 +673,7 @@ string TestFileParser::Scanner::scanDecimalNumber()
667673
{
668674
string number;
669675
number += current();
670-
while (langutil::isDecimalDigit(peek()))
676+
while (langutil::isDecimalDigit(peek()) || '.' == peek())
671677
{
672678
advance();
673679
number += current();

test/libsolidity/util/TestFunctionCall.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
#include <libsolutil/AnsiColorized.h>
2121

22-
#include <boost/algorithm/string/replace.hpp>
22+
#include <boost/algorithm/string.hpp>
2323

2424
#include <optional>
2525
#include <stdexcept>

test/libsolidity/util/TestFunctionCall.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
#include <test/libsolidity/util/TestFileParser.h>
1818
#include <test/libsolidity/util/SoltestErrors.h>
19+
#include <test/libsolidity/util/ContractABIUtils.h>
1920

2021
#include <liblangutil/Exceptions.h>
2122
#include <libsolutil/AnsiColorized.h>
2223
#include <libsolutil/CommonData.h>
24+
#include <libsolutil/JSON.h>
2325

2426
#include <json/json.h>
2527

@@ -109,12 +111,6 @@ class TestFunctionCall
109111
bool failure = false
110112
) const;
111113

112-
/// Formats a given _bytes applying the _abiType.
113-
std::string formatBytesRange(
114-
bytes const& _bytes,
115-
ABIType const& _abiType
116-
) const;
117-
118114
/// Formats a FAILURE plus additional parameters, if e.g. a revert message was returned.
119115
std::string formatFailure(
120116
ErrorReporter& _errorReporter,

0 commit comments

Comments
 (0)