xrpld
Loading...
Searching...
No Matches
STNumber_test.cpp
1#include <xrpl/basics/Number.h>
2#include <xrpl/beast/unit_test/suite.h>
3#include <xrpl/json/json_forwards.h>
4#include <xrpl/protocol/IOUAmount.h>
5#include <xrpl/protocol/Issue.h>
6#include <xrpl/protocol/SField.h>
7#include <xrpl/protocol/STAmount.h>
8#include <xrpl/protocol/STNumber.h>
9#include <xrpl/protocol/Serializer.h>
10
11#include <cstdint>
12#include <exception>
13#include <initializer_list>
14#include <limits>
15#include <stdexcept>
16#include <string>
17#include <type_traits>
18#include <typeinfo>
19
20namespace xrpl {
21
23{
24 void
26 {
27 STNumber const before{sfNumber, number};
28 BEAST_EXPECT(number == before);
29 Serializer s;
30 before.add(s);
31 BEAST_EXPECT(s.size() == 12);
32 SerialIter sit(s.slice());
33 STNumber const after{sit, sfNumber};
34 BEAST_EXPECT(after.isEquivalent(before));
35 BEAST_EXPECT(number == after);
36 }
37
38 void
40 {
41 {
42 STNumber const stnum{sfNumber};
43 BEAST_EXPECT(stnum.getSType() == STI_NUMBER);
44 BEAST_EXPECT(stnum.getText() == "0");
45 BEAST_EXPECT(stnum.isDefault() == true);
46 BEAST_EXPECT(stnum.value() == Number{0});
47 }
48
49 std::initializer_list<std::int64_t> const mantissas = {
51 -1,
52 0,
53 1,
55 for (std::int64_t const mantissa : mantissas)
56 testCombo(Number{mantissa});
57
58 std::initializer_list<std::int32_t> const exponents = {
60 for (std::int32_t const exponent : exponents)
61 testCombo(Number{123, exponent});
62
63 {
64 STAmount const strikePrice{noIssue(), 100};
65 STNumber const factor{sfNumber, 100};
66 auto const iouValue = strikePrice.iou();
67 IOUAmount const totalValue{iouValue * factor};
68 STAmount const totalAmount{totalValue, strikePrice.get<Issue>()};
69 BEAST_EXPECT(totalAmount == Number{10'000});
70 }
71
72 {
73 BEAST_EXPECT(numberFromJson(sfNumber, json::Value(42)) == STNumber(sfNumber, 42));
74 BEAST_EXPECT(numberFromJson(sfNumber, json::Value(-42)) == STNumber(sfNumber, -42));
75
76 BEAST_EXPECT(numberFromJson(sfNumber, json::UInt(42)) == STNumber(sfNumber, 42));
77
78 BEAST_EXPECT(numberFromJson(sfNumber, "-123") == STNumber(sfNumber, -123));
79
80 BEAST_EXPECT(numberFromJson(sfNumber, "123") == STNumber(sfNumber, 123));
81 BEAST_EXPECT(numberFromJson(sfNumber, "-123") == STNumber(sfNumber, -123));
82
83 BEAST_EXPECT(numberFromJson(sfNumber, "3.14") == STNumber(sfNumber, Number(314, -2)));
84 BEAST_EXPECT(numberFromJson(sfNumber, "-3.14") == STNumber(sfNumber, -Number(314, -2)));
85 BEAST_EXPECT(numberFromJson(sfNumber, "3.14e2") == STNumber(sfNumber, 314));
86 BEAST_EXPECT(numberFromJson(sfNumber, "-3.14e2") == STNumber(sfNumber, -314));
87
88 BEAST_EXPECT(numberFromJson(sfNumber, "1000e-2") == STNumber(sfNumber, 10));
89 BEAST_EXPECT(numberFromJson(sfNumber, "-1000e-2") == STNumber(sfNumber, -10));
90
91 BEAST_EXPECT(numberFromJson(sfNumber, "0") == STNumber(sfNumber, 0));
92 BEAST_EXPECT(numberFromJson(sfNumber, "0.0") == STNumber(sfNumber, 0));
93 BEAST_EXPECT(numberFromJson(sfNumber, "0.000") == STNumber(sfNumber, 0));
94 BEAST_EXPECT(numberFromJson(sfNumber, "-0") == STNumber(sfNumber, 0));
95 BEAST_EXPECT(numberFromJson(sfNumber, "-0.0") == STNumber(sfNumber, 0));
96 BEAST_EXPECT(numberFromJson(sfNumber, "-0.000") == STNumber(sfNumber, 0));
97 BEAST_EXPECT(numberFromJson(sfNumber, "0e6") == STNumber(sfNumber, 0));
98 BEAST_EXPECT(numberFromJson(sfNumber, "0.0e6") == STNumber(sfNumber, 0));
99 BEAST_EXPECT(numberFromJson(sfNumber, "0.000e6") == STNumber(sfNumber, 0));
100 BEAST_EXPECT(numberFromJson(sfNumber, "-0e6") == STNumber(sfNumber, 0));
101 BEAST_EXPECT(numberFromJson(sfNumber, "-0.0e6") == STNumber(sfNumber, 0));
102 BEAST_EXPECT(numberFromJson(sfNumber, "-0.000e6") == STNumber(sfNumber, 0));
103
104 {
105 auto const parseNumber = [](std::string const& boundary) {
106 return numberFromJson(sfNumber, boundary);
107 };
108 auto const expectParseThrows = [this, &parseNumber](std::string const& boundary) {
109 try
110 {
111 parseNumber(boundary);
112 fail();
113 }
114 catch (std::exception const& e)
115 {
116 BEAST_EXPECT(std::string(e.what()) == "number cannot be represented");
117 }
118 };
119
120 // Small rejects this; large scales parse it as 9223372036854775800e-1.
121 auto constexpr positiveBoundary = "922337203685477580";
122 auto constexpr negativeBoundary = "-922337203685477580";
124 {
125 expectParseThrows(positiveBoundary);
126 expectParseThrows(negativeBoundary);
127 }
128 else
129 {
130 BEAST_EXPECT(
131 parseNumber(positiveBoundary) ==
132 STNumber(sfNumber, Number{922'337'203'685'477'580, 0}));
133 BEAST_EXPECT(
134 parseNumber(negativeBoundary) ==
135 STNumber(sfNumber, Number{-922'337'203'685'477'580, 0}));
136 }
137
139 // maxint64 9,223,372,036,854,775,807
141 // minint64 -9,223,372,036,854,775,808
144 {
145 // min/maxInt can't be exactly represented with the small mantissa, so they
146 // don't parse, and are expected to throw.
147 expectParseThrows(maxInt);
148 expectParseThrows(minInt);
149 }
150 else
151 {
152 // with large mantissas, maxint is fine
153 BEAST_EXPECT(
154 parseNumber(maxInt) ==
155 STNumber(sfNumber, Number{9'223'372'036'854'775'807, 0}));
156 // but minint's mantissa is > kMaxRep, and so rounds, and thus can't be parsed
157 expectParseThrows(minInt);
158 }
159 }
160
161 constexpr auto kIMin = std::numeric_limits<int>::min();
162 BEAST_EXPECT(numberFromJson(sfNumber, kIMin) == STNumber(sfNumber, Number(kIMin, 0)));
163 BEAST_EXPECT(
164 numberFromJson(sfNumber, std::to_string(kIMin)) ==
165 STNumber(sfNumber, Number(kIMin, 0)));
166
167 constexpr auto kIMax = std::numeric_limits<int>::max();
168 BEAST_EXPECT(numberFromJson(sfNumber, kIMax) == STNumber(sfNumber, Number(kIMax, 0)));
169 BEAST_EXPECT(
170 numberFromJson(sfNumber, std::to_string(kIMax)) ==
171 STNumber(sfNumber, Number(kIMax, 0)));
172
173 constexpr auto kUMax = std::numeric_limits<unsigned int>::max();
174 BEAST_EXPECT(numberFromJson(sfNumber, kUMax) == STNumber(sfNumber, Number(kUMax, 0)));
175 BEAST_EXPECT(
176 numberFromJson(sfNumber, std::to_string(kUMax)) ==
177 STNumber(sfNumber, Number(kUMax, 0)));
178
179 // Obvious non-numbers tested here
180 try
181 {
182 auto _ = numberFromJson(sfNumber, "");
183 BEAST_EXPECT(false);
184 }
185 catch (std::runtime_error const& e)
186 {
187 std::string const expected = "'' is not a number";
188 BEAST_EXPECT(e.what() == expected);
189 }
190
191 try
192 {
193 auto _ = numberFromJson(sfNumber, "e");
194 BEAST_EXPECT(false);
195 }
196 catch (std::runtime_error const& e)
197 {
198 std::string const expected = "'e' is not a number";
199 BEAST_EXPECT(e.what() == expected);
200 }
201
202 try
203 {
204 auto _ = numberFromJson(sfNumber, "1e");
205 BEAST_EXPECT(false);
206 }
207 catch (std::runtime_error const& e)
208 {
209 std::string const expected = "'1e' is not a number";
210 BEAST_EXPECT(e.what() == expected);
211 }
212
213 try
214 {
215 auto _ = numberFromJson(sfNumber, "e2");
216 BEAST_EXPECT(false);
217 }
218 catch (std::runtime_error const& e)
219 {
220 std::string const expected = "'e2' is not a number";
221 BEAST_EXPECT(e.what() == expected);
222 }
223
224 try
225 {
226 auto _ = numberFromJson(sfNumber, json::Value());
227 BEAST_EXPECT(false);
228 }
229 catch (std::runtime_error const& e)
230 {
231 std::string const expected = "not a number";
232 BEAST_EXPECT(e.what() == expected);
233 }
234
235 try
236 {
237 auto _ = numberFromJson(
238 sfNumber,
239 "1234567890123456789012345678901234567890123456789012345678"
240 "9012345678901234567890123456789012345678901234567890123456"
241 "78901234567890123456789012345678901234567890");
242 BEAST_EXPECT(false);
243 }
244 catch (std::bad_cast const& e)
245 {
246 BEAST_EXPECT(true);
247 }
248
249 // We do not handle leading zeros
250 try
251 {
252 auto _ = numberFromJson(sfNumber, "001");
253 BEAST_EXPECT(false);
254 }
255 catch (std::runtime_error const& e)
256 {
257 std::string const expected = "'001' is not a number";
258 BEAST_EXPECT(e.what() == expected);
259 }
260
261 try
262 {
263 auto _ = numberFromJson(sfNumber, "000.0");
264 BEAST_EXPECT(false);
265 }
266 catch (std::runtime_error const& e)
267 {
268 std::string const expected = "'000.0' is not a number";
269 BEAST_EXPECT(e.what() == expected);
270 }
271
272 // We do not handle dangling dot
273 try
274 {
275 auto _ = numberFromJson(sfNumber, ".1");
276 BEAST_EXPECT(false);
277 }
278 catch (std::runtime_error const& e)
279 {
280 std::string const expected = "'.1' is not a number";
281 BEAST_EXPECT(e.what() == expected);
282 }
283
284 try
285 {
286 auto _ = numberFromJson(sfNumber, "1.");
287 BEAST_EXPECT(false);
288 }
289 catch (std::runtime_error const& e)
290 {
291 std::string const expected = "'1.' is not a number";
292 BEAST_EXPECT(e.what() == expected);
293 }
294
295 try
296 {
297 auto _ = numberFromJson(sfNumber, "1.e3");
298 BEAST_EXPECT(false);
299 }
300 catch (std::runtime_error const& e)
301 {
302 std::string const expected = "'1.e3' is not a number";
303 BEAST_EXPECT(e.what() == expected);
304 }
305 }
306 }
307
308 void
309 run() override
310 {
312
313 for (auto const scale : MantissaRange::getAllScales())
314 {
317 doRun();
318 }
319 }
320};
321
323
324} // namespace xrpl
A testsuite class.
Definition suite.h:52
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:554
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
Represents a JSON value.
Definition json_value.h:117
Floating point representation of amounts with high dynamic range.
Definition IOUAmount.h:26
A currency issued by an account.
Definition Issue.h:18
Sets the new scale and restores the old scale when it leaves scope.
Definition Number.h:963
Number is a floating point type that can represent a wide range of values.
Definition Number.h:351
static constexpr int kMinExponent
Definition Number.h:361
static MantissaRange::MantissaScale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
static constexpr int kMaxExponent
Definition Number.h:362
constexpr TIss const & get() const
IOUAmount iou() const
Definition STAmount.cpp:286
A serializable number.
Definition STNumber.h:42
void add(Serializer &s) const override
Definition STNumber.cpp:69
bool isDefault() const override
Definition STNumber.cpp:147
std::string getText() const override
Definition STNumber.cpp:50
SerializedTypeID getSType() const override
Definition STNumber.cpp:44
Number const & value() const
Definition STNumber.cpp:114
Slice slice() const noexcept
Definition Serializer.h:45
std::size_t size() const noexcept
Definition Serializer.h:51
T is_convertible_v
T max(T... args)
T min(T... args)
unsigned int UInt
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
int scale(Number const &number, Asset const &asset)
Get the scale of a Number for a given asset.
Definition STAmount.h:794
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:572
STNumber numberFromJson(SField const &field, json::Value const &value)
Definition STNumber.cpp:219
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition Issue.h:118
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, xrpl)
static std::set< MantissaScale > const & getAllScales()
Definition Number.h:178
void testCombo(Number number)
void run() override
Runs the suite.
T to_string(T... args)
T what(T... args)