xrpld
Loading...
Searching...
No Matches
STAmount_test.cpp
1
2#include <xrpl/basics/Number.h>
3#include <xrpl/basics/random.h>
4#include <xrpl/beast/unit_test/suite.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/json/json_forwards.h>
7#include <xrpl/json/json_value.h>
8#include <xrpl/protocol/AccountID.h>
9#include <xrpl/protocol/IOUAmount.h>
10#include <xrpl/protocol/Indexes.h>
11#include <xrpl/protocol/Issue.h>
12#include <xrpl/protocol/MPTAmount.h>
13#include <xrpl/protocol/MPTIssue.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/STAmount.h>
16#include <xrpl/protocol/Serializer.h>
17#include <xrpl/protocol/UintTypes.h>
18#include <xrpl/protocol/XRPAmount.h>
19
20#include <cstdint>
21#include <exception>
22#include <limits>
23#include <stdexcept>
24#include <string>
25#include <type_traits>
26#include <typeinfo>
27
28namespace xrpl {
29
31{
32public:
33 static STAmount
35 {
36 Serializer ser;
37 s.add(ser);
38
39 SerialIter sit(ser.slice());
40 return STAmount(sit, sfGeneric);
41 }
42
43 //--------------------------------------------------------------------------
44 static STAmount
45 roundSelf(STAmount const& amount)
46 {
47 if (amount.native())
48 return amount;
49
50 std::uint64_t mantissa = amount.mantissa();
51 std::uint64_t const valueDigits = mantissa % 1000000000;
52
53 if (valueDigits == 1)
54 {
55 mantissa--;
56
57 if (mantissa < STAmount::kMinValue)
58 return {amount.asset(), mantissa, amount.exponent(), amount.negative()};
59
60 return {
61 amount.asset(),
62 mantissa,
63 amount.exponent(),
64 amount.negative(),
66 }
67
68 if (valueDigits == 999999999)
69 {
70 mantissa++;
71
72 if (mantissa > STAmount::kMaxValue)
73 return {amount.asset(), mantissa, amount.exponent(), amount.negative()};
74
75 return {
76 amount.asset(),
77 mantissa,
78 amount.exponent(),
79 amount.negative(),
81 }
82
83 return amount;
84 }
85
86 void
87 roundTest(int n, int d, int m)
88 {
89 // check STAmount rounding
90 STAmount const num(noIssue(), n);
91 STAmount const den(noIssue(), d);
92 STAmount const mul(noIssue(), m);
93 STAmount const quot = divide(STAmount(n), STAmount(d), noIssue());
94 STAmount const res = roundSelf(multiply(quot, mul, noIssue()));
95
96 BEAST_EXPECT(!res.native());
97
98 STAmount const cmp(noIssue(), (n * m) / d);
99
100 BEAST_EXPECT(!cmp.native());
101
102 BEAST_EXPECT(cmp.get<Issue>().currency == res.get<Issue>().currency);
103
104 if (res != cmp)
105 {
106 log << "(" << num.getText() << "/" << den.getText() << ") X " << mul.getText() << " = "
107 << res.getText() << " not " << cmp.getText();
108 fail("Rounding");
109 return;
110 }
111 }
112
113 void
114 mulTest(int a, int b)
115 {
116 STAmount const aa(noIssue(), a);
117 STAmount const bb(noIssue(), b);
118 STAmount const prod1(multiply(aa, bb, noIssue()));
119
120 BEAST_EXPECT(!prod1.native());
121
122 STAmount const prod2(
123 noIssue(), static_cast<std::uint64_t>(a) * static_cast<std::uint64_t>(b));
124
125 if (prod1 != prod2)
126 {
127 log << "nn(" << aa.getFullText() << " * " << bb.getFullText()
128 << ") = " << prod1.getFullText() << " not " << prod2.getFullText();
129 fail("Multiplication result is not exact");
130 }
131 }
132
133 //--------------------------------------------------------------------------
134
135 void
136 testSetValue(std::string const& value, Issue const& issue, bool success = true)
137 {
138 try
139 {
140 STAmount const amount = amountFromString(issue, value);
141 BEAST_EXPECT(amount.getText() == value);
142 }
143 catch (std::exception const&)
144 {
145 BEAST_EXPECT(!success);
146 }
147 }
148
149 void
151 {
152 {
153 testcase("set value (native)");
154
155 Issue const xrp(xrpIssue());
156
157 // fractional XRP (i.e. drops)
158 testSetValue("1", xrp);
159 testSetValue("22", xrp);
160 testSetValue("333", xrp);
161 testSetValue("4444", xrp);
162 testSetValue("55555", xrp);
163 testSetValue("666666", xrp);
164
165 // 1 XRP up to 100 billion, in powers of 10 (in drops)
166 testSetValue("1000000", xrp);
167 testSetValue("10000000", xrp);
168 testSetValue("100000000", xrp);
169 testSetValue("1000000000", xrp);
170 testSetValue("10000000000", xrp);
171 testSetValue("100000000000", xrp);
172 testSetValue("1000000000000", xrp);
173 testSetValue("10000000000000", xrp);
174 testSetValue("100000000000000", xrp);
175 testSetValue("1000000000000000", xrp);
176 testSetValue("10000000000000000", xrp);
177 testSetValue("100000000000000000", xrp);
178
179 // Invalid native values:
180 testSetValue("1.1", xrp, false);
181 testSetValue("100000000000000001", xrp, false);
182 testSetValue("1000000000000000000", xrp, false);
183 }
184
185 {
186 testcase("set value (iou)");
187
188 Issue const usd(Currency(0x5553440000000000), AccountID(0x4985601));
189
190 testSetValue("1", usd);
191 testSetValue("10", usd);
192 testSetValue("100", usd);
193 testSetValue("1000", usd);
194 testSetValue("10000", usd);
195 testSetValue("100000", usd);
196 testSetValue("1000000", usd);
197 testSetValue("10000000", usd);
198 testSetValue("100000000", usd);
199 testSetValue("1000000000", usd);
200 testSetValue("10000000000", usd);
201
202 testSetValue("1234567.1", usd);
203 testSetValue("1234567.12", usd);
204 testSetValue("1234567.123", usd);
205 testSetValue("1234567.1234", usd);
206 testSetValue("1234567.12345", usd);
207 testSetValue("1234567.123456", usd);
208 testSetValue("1234567.1234567", usd);
209 testSetValue("1234567.12345678", usd);
210 testSetValue("1234567.123456789", usd);
211 }
212 }
213
214 //--------------------------------------------------------------------------
215
216 void
218 {
219 testcase("native currency");
220
221 STAmount const zeroSt;
222 STAmount const one(1);
223 STAmount const hundred(100);
224
225 // VFALCO NOTE Why repeat "STAmount fail" so many times??
226 unexpected(serializeAndDeserialize(zeroSt) != zeroSt, "STAmount fail");
227 unexpected(serializeAndDeserialize(one) != one, "STAmount fail");
228 unexpected(serializeAndDeserialize(hundred) != hundred, "STAmount fail");
229 unexpected(!zeroSt.native(), "STAmount fail");
230 unexpected(!hundred.native(), "STAmount fail");
231 unexpected(zeroSt != beast::kZero, "STAmount fail");
232 unexpected(one == beast::kZero, "STAmount fail");
233 unexpected(hundred == beast::kZero, "STAmount fail");
234 unexpected((zeroSt < zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
235 unexpected(!(zeroSt < one), "STAmount fail");
236 unexpected(!(zeroSt < hundred), "STAmount fail");
237 unexpected((one < zeroSt), "STAmount fail");
238 unexpected((one < one), "STAmount fail"); // NOLINT(misc-redundant-expression)
239 unexpected(!(one < hundred), "STAmount fail");
240 unexpected((hundred < zeroSt), "STAmount fail");
241 unexpected((hundred < one), "STAmount fail");
242 unexpected((hundred < hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
243 unexpected((zeroSt > zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
244 unexpected((zeroSt > one), "STAmount fail");
245 unexpected((zeroSt > hundred), "STAmount fail");
246 unexpected(!(one > zeroSt), "STAmount fail");
247 unexpected((one > one), "STAmount fail"); // NOLINT(misc-redundant-expression)
248 unexpected((one > hundred), "STAmount fail");
249 unexpected(!(hundred > zeroSt), "STAmount fail");
250 unexpected(!(hundred > one), "STAmount fail");
251 unexpected((hundred > hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
252 unexpected(!(zeroSt <= zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
253 unexpected(!(zeroSt <= one), "STAmount fail");
254 unexpected(!(zeroSt <= hundred), "STAmount fail");
255 unexpected((one <= zeroSt), "STAmount fail");
256 unexpected(!(one <= one), "STAmount fail"); // NOLINT(misc-redundant-expression)
257 unexpected(!(one <= hundred), "STAmount fail");
258 unexpected((hundred <= zeroSt), "STAmount fail");
259 unexpected((hundred <= one), "STAmount fail");
260 unexpected(!(hundred <= hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
261 unexpected(!(zeroSt >= zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
262 unexpected((zeroSt >= one), "STAmount fail");
263 unexpected((zeroSt >= hundred), "STAmount fail");
264 unexpected(!(one >= zeroSt), "STAmount fail");
265 unexpected(!(one >= one), "STAmount fail"); // NOLINT(misc-redundant-expression)
266 unexpected((one >= hundred), "STAmount fail");
267 unexpected(!(hundred >= zeroSt), "STAmount fail");
268 unexpected(!(hundred >= one), "STAmount fail");
269 unexpected(!(hundred >= hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
270 unexpected(!(zeroSt == zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
271 unexpected((zeroSt == one), "STAmount fail");
272 unexpected((zeroSt == hundred), "STAmount fail");
273 unexpected((one == zeroSt), "STAmount fail");
274 unexpected(!(one == one), "STAmount fail"); // NOLINT(misc-redundant-expression)
275 unexpected((one == hundred), "STAmount fail");
276 unexpected((hundred == zeroSt), "STAmount fail");
277 unexpected((hundred == one), "STAmount fail");
278 unexpected(!(hundred == hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
279 unexpected((zeroSt != zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
280 unexpected(!(zeroSt != one), "STAmount fail");
281 unexpected(!(zeroSt != hundred), "STAmount fail");
282 unexpected(!(one != zeroSt), "STAmount fail");
283 unexpected((one != one), "STAmount fail"); // NOLINT(misc-redundant-expression)
284 unexpected(!(one != hundred), "STAmount fail");
285 unexpected(!(hundred != zeroSt), "STAmount fail");
286 unexpected(!(hundred != one), "STAmount fail");
287 unexpected((hundred != hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
288 unexpected(STAmount().getText() != "0", "STAmount fail");
289 unexpected(STAmount(31).getText() != "31", "STAmount fail");
290 unexpected(STAmount(310).getText() != "310", "STAmount fail");
291 unexpected(to_string(Currency()) != "XRP", "cHC(XRP)");
292 Currency c;
293 unexpected(!toCurrency(c, "USD"), "create USD currency");
294 unexpected(to_string(c) != "USD", "check USD currency");
295
296 std::string const cur = "015841551A748AD2C1F76FF6ECB0CCCD00000000";
297 unexpected(!toCurrency(c, cur), "create custom currency");
298 unexpected(to_string(c) != cur, "check custom currency");
299 }
300
301 //--------------------------------------------------------------------------
302
303 void
305 {
306 testcase("custom currency");
307
308 STAmount const zeroSt(noIssue());
309 STAmount const one(noIssue(), 1);
310 STAmount const hundred(noIssue(), 100);
311
312 unexpected(serializeAndDeserialize(zeroSt) != zeroSt, "STAmount fail");
313 unexpected(serializeAndDeserialize(one) != one, "STAmount fail");
314 unexpected(serializeAndDeserialize(hundred) != hundred, "STAmount fail");
315 unexpected(zeroSt.native(), "STAmount fail");
316 unexpected(hundred.native(), "STAmount fail");
317 unexpected(zeroSt != beast::kZero, "STAmount fail");
318 unexpected(one == beast::kZero, "STAmount fail");
319 unexpected(hundred == beast::kZero, "STAmount fail");
320 unexpected((zeroSt < zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
321 unexpected(!(zeroSt < one), "STAmount fail");
322 unexpected(!(zeroSt < hundred), "STAmount fail");
323 unexpected((one < zeroSt), "STAmount fail");
324 unexpected((one < one), "STAmount fail"); // NOLINT(misc-redundant-expression)
325 unexpected(!(one < hundred), "STAmount fail");
326 unexpected((hundred < zeroSt), "STAmount fail");
327 unexpected((hundred < one), "STAmount fail");
328 unexpected((hundred < hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
329 unexpected((zeroSt > zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
330 unexpected((zeroSt > one), "STAmount fail");
331 unexpected((zeroSt > hundred), "STAmount fail");
332 unexpected(!(one > zeroSt), "STAmount fail");
333 unexpected((one > one), "STAmount fail"); // NOLINT(misc-redundant-expression)
334 unexpected((one > hundred), "STAmount fail");
335 unexpected(!(hundred > zeroSt), "STAmount fail");
336 unexpected(!(hundred > one), "STAmount fail");
337 unexpected((hundred > hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
338 unexpected(!(zeroSt <= zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
339 unexpected(!(zeroSt <= one), "STAmount fail");
340 unexpected(!(zeroSt <= hundred), "STAmount fail");
341 unexpected((one <= zeroSt), "STAmount fail");
342 unexpected(!(one <= one), "STAmount fail"); // NOLINT(misc-redundant-expression)
343 unexpected(!(one <= hundred), "STAmount fail");
344 unexpected((hundred <= zeroSt), "STAmount fail");
345 unexpected((hundred <= one), "STAmount fail");
346 unexpected(!(hundred <= hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
347 unexpected(!(zeroSt >= zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
348 unexpected((zeroSt >= one), "STAmount fail");
349 unexpected((zeroSt >= hundred), "STAmount fail");
350 unexpected(!(one >= zeroSt), "STAmount fail");
351 unexpected(!(one >= one), "STAmount fail"); // NOLINT(misc-redundant-expression)
352 unexpected((one >= hundred), "STAmount fail");
353 unexpected(!(hundred >= zeroSt), "STAmount fail");
354 unexpected(!(hundred >= one), "STAmount fail");
355 unexpected(!(hundred >= hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
356 unexpected(!(zeroSt == zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
357 unexpected((zeroSt == one), "STAmount fail");
358 unexpected((zeroSt == hundred), "STAmount fail");
359 unexpected((one == zeroSt), "STAmount fail");
360 unexpected(!(one == one), "STAmount fail"); // NOLINT(misc-redundant-expression)
361 unexpected((one == hundred), "STAmount fail");
362 unexpected((hundred == zeroSt), "STAmount fail");
363 unexpected((hundred == one), "STAmount fail");
364 unexpected(!(hundred == hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
365 unexpected((zeroSt != zeroSt), "STAmount fail"); // NOLINT(misc-redundant-expression)
366 unexpected(!(zeroSt != one), "STAmount fail");
367 unexpected(!(zeroSt != hundred), "STAmount fail");
368 unexpected(!(one != zeroSt), "STAmount fail");
369 unexpected((one != one), "STAmount fail"); // NOLINT(misc-redundant-expression)
370 unexpected(!(one != hundred), "STAmount fail");
371 unexpected(!(hundred != zeroSt), "STAmount fail");
372 unexpected(!(hundred != one), "STAmount fail");
373 unexpected((hundred != hundred), "STAmount fail"); // NOLINT(misc-redundant-expression)
374 unexpected(STAmount(noIssue()).getText() != "0", "STAmount fail");
375 unexpected(STAmount(noIssue(), 31).getText() != "31", "STAmount fail");
376 unexpected(STAmount(noIssue(), 31, 1).getText() != "310", "STAmount fail");
377 unexpected(STAmount(noIssue(), 31, -1).getText() != "3.1", "STAmount fail");
378 unexpected(STAmount(noIssue(), 31, -2).getText() != "0.31", "STAmount fail");
380 multiply(STAmount(noIssue(), 20), STAmount(3), noIssue()).getText() != "60",
381 "STAmount multiply fail 1");
383 multiply(STAmount(noIssue(), 20), STAmount(3), xrpIssue()).getText() != "60",
384 "STAmount multiply fail 2");
386 multiply(STAmount(20), STAmount(3), noIssue()).getText() != "60",
387 "STAmount multiply fail 3");
389 multiply(STAmount(20), STAmount(3), xrpIssue()).getText() != "60",
390 "STAmount multiply fail 4");
391
392 if (divide(STAmount(noIssue(), 60), STAmount(3), noIssue()).getText() != "20")
393 {
394 log << "60/3 = " << divide(STAmount(noIssue(), 60), STAmount(3), noIssue()).getText();
395 fail("STAmount divide fail");
396 }
397 else
398 {
399 pass();
400 }
401
403 divide(STAmount(noIssue(), 60), STAmount(3), xrpIssue()).getText() != "20",
404 "STAmount divide fail");
405
407 divide(STAmount(noIssue(), 60), STAmount(noIssue(), 3), noIssue()).getText() != "20",
408 "STAmount divide fail");
409
411 divide(STAmount(noIssue(), 60), STAmount(noIssue(), 3), xrpIssue()).getText() != "20",
412 "STAmount divide fail");
413
414 STAmount const a1(noIssue(), 60);
415 STAmount const a2(noIssue(), 10, -1);
416
418 divide(a2, a1, noIssue()) != amountFromQuality(getRate(a1, a2)),
419 "STAmount setRate(getRate) fail");
420
422 divide(a1, a2, noIssue()) != amountFromQuality(getRate(a2, a1)),
423 "STAmount setRate(getRate) fail");
424 }
425
426 //--------------------------------------------------------------------------
427
428 void
430 {
431 testcase("arithmetic");
432
433 // Test currency multiplication and division operations such as
434 // convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed,
435 // and getNeeded
436
438 getRate(STAmount(1), STAmount(10)) !=
439 (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
440 "STAmount getRate fail 1");
441
443 getRate(STAmount(10), STAmount(1)) !=
444 (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
445 "STAmount getRate fail 2");
446
448 getRate(STAmount(noIssue(), 1), STAmount(noIssue(), 10)) !=
449 (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
450 "STAmount getRate fail 3");
451
453 getRate(STAmount(noIssue(), 10), STAmount(noIssue(), 1)) !=
454 (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
455 "STAmount getRate fail 4");
456
458 getRate(STAmount(noIssue(), 1), STAmount(10)) !=
459 (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
460 "STAmount getRate fail 5");
461
463 getRate(STAmount(noIssue(), 10), STAmount(1)) !=
464 (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
465 "STAmount getRate fail 6");
466
468 getRate(STAmount(1), STAmount(noIssue(), 10)) !=
469 (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
470 "STAmount getRate fail 7");
471
473 getRate(STAmount(10), STAmount(noIssue(), 1)) !=
474 (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
475 "STAmount getRate fail 8");
476
477 roundTest(1, 3, 3);
478 roundTest(2, 3, 9);
479 roundTest(1, 7, 21);
480 roundTest(1, 2, 4);
481 roundTest(3, 9, 18);
482 roundTest(7, 11, 44);
483
484 for (int i = 0; i <= 100000; ++i)
485 {
486 mulTest(randInt(10000000), randInt(10000000));
487 }
488 }
489
490 //--------------------------------------------------------------------------
491
492 void
494 {
495 testcase("underflow");
496
497 STAmount const bigNative(STAmount::kMaxNative / 2);
498 STAmount const bigValue(
500 STAmount const smallValue(
502 STAmount const zeroSt(noIssue(), 0);
503
504 STAmount const smallXSmall = multiply(smallValue, smallValue, noIssue());
505
506 BEAST_EXPECT(smallXSmall == beast::kZero);
507
508 STAmount bigDsmall = divide(smallValue, bigValue, noIssue());
509
510 BEAST_EXPECT(bigDsmall == beast::kZero);
511
512 BEAST_EXPECT(bigDsmall == beast::kZero);
513
514 bigDsmall = divide(smallValue, bigValue, xrpIssue());
515
516 BEAST_EXPECT(bigDsmall == beast::kZero);
517
518 bigDsmall = divide(smallValue, bigNative, xrpIssue());
519
520 BEAST_EXPECT(bigDsmall == beast::kZero);
521
522 // very bad offer
523 std::uint64_t r = getRate(smallValue, bigValue);
524
525 BEAST_EXPECT(r == 0);
526
527 // very good offer
528 r = getRate(bigValue, smallValue);
529
530 BEAST_EXPECT(r == 0);
531 }
532
533 //--------------------------------------------------------------------------
534
535 void
537 {
538 // VFALCO TODO There are no actual tests here, just printed output?
539 // Change this to actually do something.
540
541#if 0
542 beginTestCase ("rounding ");
543
544 std::uint64_t value = 25000000000000000ull;
545 int offset = -14;
546 canonicalizeRound (false, value, offset, true);
547
548 STAmount one (noIssue(), 1);
549 STAmount two (noIssue(), 2);
550 STAmount three (noIssue(), 3);
551
552 STAmount oneThird1 = divRound (one, three, noIssue(), false);
553 STAmount oneThird2 = divide (one, three, noIssue());
554 STAmount oneThird3 = divRound (one, three, noIssue(), true);
555 log << oneThird1;
556 log << oneThird2;
557 log << oneThird3;
558
559 STAmount twoThird1 = divRound (two, three, noIssue(), false);
560 STAmount twoThird2 = divide (two, three, noIssue());
561 STAmount twoThird3 = divRound (two, three, noIssue(), true);
562 log << twoThird1;
563 log << twoThird2;
564 log << twoThird3;
565
566 STAmount oneA = mulRound (oneThird1, three, noIssue(), false);
567 STAmount oneB = multiply (oneThird2, three, noIssue());
568 STAmount oneC = mulRound (oneThird3, three, noIssue(), true);
569 log << oneA;
570 log << oneB;
571 log << oneC;
572
573 STAmount fourThirdsB = twoThird2 + twoThird2;
574 log << fourThirdsA;
575 log << fourThirdsB;
576 log << fourThirdsC;
577
578 STAmount dripTest1 = mulRound (twoThird2, two, xrpIssue (), false);
579 STAmount dripTest2 = multiply (twoThird2, two, xrpIssue ());
580 STAmount dripTest3 = mulRound (twoThird2, two, xrpIssue (), true);
581 log << dripTest1;
582 log << dripTest2;
583 log << dripTest3;
584#endif
585 }
586
587 void
589 {
591
592 {
593 STAmount const stnum{sfNumber};
594 BEAST_EXPECT(stnum.getSType() == STI_AMOUNT);
595 BEAST_EXPECT(stnum.getText() == "0");
596 BEAST_EXPECT(stnum.isDefault() == true);
597 BEAST_EXPECT(stnum.value() == Number{0});
598 }
599
600 {
601 BEAST_EXPECT(amountFromJson(sfNumber, json::Value(42)) == XRPAmount(42));
602 BEAST_EXPECT(amountFromJson(sfNumber, json::Value(-42)) == XRPAmount(-42));
603
604 BEAST_EXPECT(amountFromJson(sfNumber, json::UInt(42)) == XRPAmount(42));
605
606 BEAST_EXPECT(amountFromJson(sfNumber, "-123") == XRPAmount(-123));
607
608 BEAST_EXPECT(amountFromJson(sfNumber, "123") == XRPAmount(123));
609 BEAST_EXPECT(amountFromJson(sfNumber, "-123") == XRPAmount(-123));
610
611 BEAST_EXPECT(amountFromJson(sfNumber, "3.14e2") == XRPAmount(314));
612 BEAST_EXPECT(amountFromJson(sfNumber, "-3.14e2") == XRPAmount(-314));
613
614 BEAST_EXPECT(amountFromJson(sfNumber, "0") == XRPAmount(0));
615 BEAST_EXPECT(amountFromJson(sfNumber, "-0") == XRPAmount(0));
616
617 constexpr auto kIMin = std::numeric_limits<int>::min();
618 BEAST_EXPECT(amountFromJson(sfNumber, kIMin) == XRPAmount(kIMin));
619 BEAST_EXPECT(amountFromJson(sfNumber, std::to_string(kIMin)) == XRPAmount(kIMin));
620
621 constexpr auto kIMax = std::numeric_limits<int>::max();
622 BEAST_EXPECT(amountFromJson(sfNumber, kIMax) == XRPAmount(kIMax));
623 BEAST_EXPECT(amountFromJson(sfNumber, std::to_string(kIMax)) == XRPAmount(kIMax));
624
625 constexpr auto kUMax = std::numeric_limits<unsigned int>::max();
626 BEAST_EXPECT(amountFromJson(sfNumber, kUMax) == XRPAmount(kUMax));
627 BEAST_EXPECT(amountFromJson(sfNumber, std::to_string(kUMax)) == XRPAmount(kUMax));
628
629 // XRP does not handle fractional part
630 try
631 {
632 auto _ = amountFromJson(sfNumber, "0.0");
633 BEAST_EXPECT(false);
634 }
635 catch (std::runtime_error const& e)
636 {
637 std::string const expected = "XRP and MPT must be specified as integral amount.";
638 BEAST_EXPECT(e.what() == expected);
639 }
640
641 // XRP does not handle fractional part
642 try
643 {
644 auto _ = amountFromJson(sfNumber, "1000e-2");
645 BEAST_EXPECT(false);
646 }
647 catch (std::runtime_error const& e)
648 {
649 std::string const expected = "XRP and MPT must be specified as integral amount.";
650 BEAST_EXPECT(e.what() == expected);
651 }
652
653 // Obvious non-numbers tested here
654 try
655 {
656 auto _ = amountFromJson(sfNumber, "");
657 BEAST_EXPECT(false);
658 }
659 catch (std::runtime_error const& e)
660 {
661 std::string const expected = "'' is not a number";
662 BEAST_EXPECT(e.what() == expected);
663 }
664
665 try
666 {
667 auto _ = amountFromJson(sfNumber, "e");
668 BEAST_EXPECT(false);
669 }
670 catch (std::runtime_error const& e)
671 {
672 std::string const expected = "'e' is not a number";
673 BEAST_EXPECT(e.what() == expected);
674 }
675
676 try
677 {
678 auto _ = amountFromJson(sfNumber, "1e");
679 BEAST_EXPECT(false);
680 }
681 catch (std::runtime_error const& e)
682 {
683 std::string const expected = "'1e' is not a number";
684 BEAST_EXPECT(e.what() == expected);
685 }
686
687 try
688 {
689 auto _ = amountFromJson(sfNumber, "e2");
690 BEAST_EXPECT(false);
691 }
692 catch (std::runtime_error const& e)
693 {
694 std::string const expected = "'e2' is not a number";
695 BEAST_EXPECT(e.what() == expected);
696 }
697
698 try
699 {
700 auto _ = amountFromJson(sfNumber, json::Value());
701 BEAST_EXPECT(false);
702 }
703 catch (std::runtime_error const& e)
704 {
705 std::string const expected = "XRP may not be specified with a null Json value";
706 BEAST_EXPECT(e.what() == expected);
707 }
708
709 try
710 {
711 auto _ = amountFromJson(
712 sfNumber,
713 "123456789012345678901234567890123456789012345678901234"
714 "5678"
715 "901234567890123456789012345678901234567890123456789012"
716 "3456"
717 "78901234567890123456789012345678901234567890");
718 BEAST_EXPECT(false);
719 }
720 catch (std::bad_cast const& e)
721 {
722 BEAST_EXPECT(true);
723 }
724
725 // We do not handle leading zeros
726 try
727 {
728 auto _ = amountFromJson(sfNumber, "001");
729 BEAST_EXPECT(false);
730 }
731 catch (std::runtime_error const& e)
732 {
733 std::string const expected = "'001' is not a number";
734 BEAST_EXPECT(e.what() == expected);
735 }
736
737 try
738 {
739 auto _ = amountFromJson(sfNumber, "000.0");
740 BEAST_EXPECT(false);
741 }
742 catch (std::runtime_error const& e)
743 {
744 std::string const expected = "'000.0' is not a number";
745 BEAST_EXPECT(e.what() == expected);
746 }
747
748 // We do not handle dangling dot
749 try
750 {
751 auto _ = amountFromJson(sfNumber, ".1");
752 BEAST_EXPECT(false);
753 }
754 catch (std::runtime_error const& e)
755 {
756 std::string const expected = "'.1' is not a number";
757 BEAST_EXPECT(e.what() == expected);
758 }
759
760 try
761 {
762 auto _ = amountFromJson(sfNumber, "1.");
763 BEAST_EXPECT(false);
764 }
765 catch (std::runtime_error const& e)
766 {
767 std::string const expected = "'1.' is not a number";
768 BEAST_EXPECT(e.what() == expected);
769 }
770
771 try
772 {
773 auto _ = amountFromJson(sfNumber, "1.e3");
774 BEAST_EXPECT(false);
775 }
776 catch (std::runtime_error const& e)
777 {
778 std::string const expected = "'1.e3' is not a number";
779 BEAST_EXPECT(e.what() == expected);
780 }
781 }
782 }
783
784 void
786 {
787 testcase("STAmount to XRPAmount conversions");
788
789 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
790 Issue const xrp{xrpIssue()};
791
792 for (std::uint64_t drops = 100000000000000000; drops != 1; drops = drops / 10)
793 {
794 auto const t = amountFromString(xrp, std::to_string(drops));
795 auto const s = t.xrp();
796 BEAST_EXPECT(s.drops() == drops);
797 BEAST_EXPECT(t == STAmount(XRPAmount(drops)));
798 BEAST_EXPECT(s == XRPAmount(drops));
799 }
800
801 try
802 {
803 auto const t = amountFromString(usd, "136500");
804 fail(to_string(t.xrp()));
805 }
806 catch (std::logic_error const&)
807 {
808 pass();
809 }
810 catch (std::exception const&)
811 {
812 fail("wrong exception");
813 }
814 }
815
816 void
818 {
819 testcase("STAmount to IOUAmount conversions");
820
821 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
822 Issue const xrp{xrpIssue()};
823
824 for (std::uint64_t dollars = 10000000000; dollars != 1; dollars = dollars / 10)
825 {
826 auto const t = amountFromString(usd, std::to_string(dollars));
827 auto const s = t.iou();
828 BEAST_EXPECT(t == STAmount(s, usd));
829 BEAST_EXPECT(s.mantissa() == t.mantissa());
830 BEAST_EXPECT(s.exponent() == t.exponent());
831 }
832
833 try
834 {
835 auto const t = amountFromString(xrp, "136500");
836 fail(to_string(t.iou()));
837 }
838 catch (std::logic_error const&)
839 {
840 pass();
841 }
842 catch (std::exception const&)
843 {
844 fail("wrong exception");
845 }
846 }
847
848 void
850 {
851 testcase("can add xrp");
852
853 // Adding zero
854 {
855 STAmount const amt1(XRPAmount(0));
856 STAmount const amt2(XRPAmount(1000));
857 BEAST_EXPECT(canAdd(amt1, amt2) == true);
858 }
859
860 // Adding zero
861 {
862 STAmount const amt1(XRPAmount(1000));
863 STAmount const amt2(XRPAmount(0));
864 BEAST_EXPECT(canAdd(amt1, amt2) == true);
865 }
866
867 // Adding two positive XRP amounts
868 {
869 STAmount const amt1(XRPAmount(500));
870 STAmount const amt2(XRPAmount(1500));
871 BEAST_EXPECT(canAdd(amt1, amt2) == true);
872 }
873
874 // Adding two negative XRP amounts
875 {
876 STAmount const amt1(XRPAmount(-500));
877 STAmount const amt2(XRPAmount(-1500));
878 BEAST_EXPECT(canAdd(amt1, amt2) == true);
879 }
880
881 // Adding a positive and a negative XRP amount
882 {
883 STAmount const amt1(XRPAmount(1000));
884 STAmount const amt2(XRPAmount(-1000));
885 BEAST_EXPECT(canAdd(amt1, amt2) == true);
886 }
887
888 // Overflow check for max XRP amounts
889 {
891 STAmount const amt2(XRPAmount(1));
892 BEAST_EXPECT(canAdd(amt1, amt2) == false);
893 }
894
895 // Overflow check for min XRP amounts
896 {
898 amt1 += XRPAmount(1);
899 STAmount const amt2(XRPAmount(-1));
900 BEAST_EXPECT(canAdd(amt1, amt2) == false);
901 }
902 }
903
904 void
906 {
907 testcase("can add iou");
908
909 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
910 Issue const eur{Currency(0x4555520000000000), AccountID(0x4985601)};
911
912 // Adding two IOU amounts
913 {
914 STAmount const amt1(usd, 500);
915 STAmount const amt2(usd, 1500);
916 BEAST_EXPECT(canAdd(amt1, amt2) == true);
917 }
918
919 // Adding a positive and a negative IOU amount
920 {
921 STAmount const amt1(usd, 1000);
922 STAmount const amt2(usd, -1000);
923 BEAST_EXPECT(canAdd(amt1, amt2) == true);
924 }
925
926 // Overflow check for max IOU amounts
927 {
929 STAmount const amt2(usd, 1);
930 BEAST_EXPECT(canAdd(amt1, amt2) == false);
931 }
932
933 // Overflow check for min IOU amounts
934 {
936 STAmount const amt2(usd, -1);
937 BEAST_EXPECT(canAdd(amt1, amt2) == false);
938 }
939
940 // Adding XRP and IOU
941 {
942 STAmount const amt1(XRPAmount(1));
943 STAmount const amt2(usd, 1);
944 BEAST_EXPECT(canAdd(amt1, amt2) == false);
945 }
946
947 // Adding different IOU issues (non zero)
948 {
949 STAmount const amt1(usd, 1000);
950 STAmount const amt2(eur, 500);
951 BEAST_EXPECT(canAdd(amt1, amt2) == false);
952 }
953
954 // Adding different IOU issues (zero)
955 {
956 STAmount const amt1(usd, 0);
957 STAmount const amt2(eur, 500);
958 BEAST_EXPECT(canAdd(amt1, amt2) == false);
959 }
960 }
961
962 void
964 {
965 testcase("can add mpt");
966
967 MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}};
968 MPTIssue const mpt2{MPTIssue{makeMptID(2, AccountID(0x4985601))}};
969
970 // Adding zero
971 {
972 STAmount const amt1(mpt, 0);
973 STAmount const amt2(mpt, 1000);
974 BEAST_EXPECT(canAdd(amt1, amt2) == true);
975 }
976
977 // Adding zero
978 {
979 STAmount const amt1(mpt, 1000);
980 STAmount const amt2(mpt, 0);
981 BEAST_EXPECT(canAdd(amt1, amt2) == true);
982 }
983
984 // Adding two positive MPT amounts
985 {
986 STAmount const amt1(mpt, 500);
987 STAmount const amt2(mpt, 1500);
988 BEAST_EXPECT(canAdd(amt1, amt2) == true);
989 }
990
991 // Adding two negative MPT amounts
992 {
993 STAmount const amt1(mpt, -500);
994 STAmount const amt2(mpt, -1500);
995 BEAST_EXPECT(canAdd(amt1, amt2) == true);
996 }
997
998 // Adding a positive and a negative MPT amount
999 {
1000 STAmount const amt1(mpt, 1000);
1001 STAmount const amt2(mpt, -1000);
1002 BEAST_EXPECT(canAdd(amt1, amt2) == true);
1003 }
1004
1005 // Overflow check for max MPT amounts
1006 {
1008 STAmount const amt2(mpt, 1);
1009 BEAST_EXPECT(canAdd(amt1, amt2) == false);
1010 }
1011
1012 // Overflow check for min MPT amounts
1013 // Note: Cannot check min MPT overflow because you cannot initialize the
1014 // STAmount with a negative MPT amount.
1015
1016 // Adding MPT and XRP
1017 {
1018 STAmount const amt1(XRPAmount(1000));
1019 STAmount const amt2(mpt, 1000);
1020 BEAST_EXPECT(canAdd(amt1, amt2) == false);
1021 }
1022
1023 // Adding different MPT issues (non zero)
1024 {
1025 STAmount const amt1(mpt2, 500);
1026 STAmount const amt2(mpt, 500);
1027 BEAST_EXPECT(canAdd(amt1, amt2) == false);
1028 }
1029
1030 // Adding different MPT issues (non zero)
1031 {
1032 STAmount const amt1(mpt2, 0);
1033 STAmount const amt2(mpt, 500);
1034 BEAST_EXPECT(canAdd(amt1, amt2) == false);
1035 }
1036 }
1037
1038 void
1040 {
1041 testcase("can subtract xrp");
1042
1043 // Subtracting zero
1044 {
1045 STAmount const amt1(XRPAmount(1000));
1046 STAmount const amt2(XRPAmount(0));
1047 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1048 }
1049
1050 // Subtracting zero
1051 {
1052 STAmount const amt1(XRPAmount(0));
1053 STAmount const amt2(XRPAmount(1000));
1054 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1055 }
1056
1057 // Subtracting two positive XRP amounts
1058 {
1059 STAmount const amt1(XRPAmount(1500));
1060 STAmount const amt2(XRPAmount(500));
1061 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1062 }
1063
1064 // Subtracting two negative XRP amounts
1065 {
1066 STAmount const amt1(XRPAmount(-1500));
1067 STAmount const amt2(XRPAmount(-500));
1068 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1069 }
1070
1071 // Subtracting a positive and a negative XRP amount
1072 {
1073 STAmount const amt1(XRPAmount(1000));
1074 STAmount const amt2(XRPAmount(-1000));
1075 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1076 }
1077
1078 // Underflow check for min XRP amounts
1079 {
1081 amt1 += XRPAmount(1);
1082 STAmount const amt2(XRPAmount(1));
1083 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1084 }
1085
1086 // Overflow check for max XRP amounts
1087 {
1089 STAmount const amt2(XRPAmount(-1));
1090 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1091 }
1092 }
1093
1094 void
1096 {
1097 testcase("can subtract iou");
1098 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
1099 Issue const eur{Currency(0x4555520000000000), AccountID(0x4985601)};
1100
1101 // Subtracting two IOU amounts
1102 {
1103 STAmount const amt1(usd, 1500);
1104 STAmount const amt2(usd, 500);
1105 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1106 }
1107
1108 // Subtracting XRP and IOU
1109 {
1110 STAmount const amt1(XRPAmount(1000));
1111 STAmount const amt2(usd, 1000);
1112 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1113 }
1114
1115 // Subtracting different IOU issues (non zero)
1116 {
1117 STAmount const amt1(usd, 1000);
1118 STAmount const amt2(eur, 500);
1119 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1120 }
1121
1122 // Subtracting different IOU issues (zero)
1123 {
1124 STAmount const amt1(usd, 0);
1125 STAmount const amt2(eur, 500);
1126 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1127 }
1128 }
1129
1130 void
1132 {
1133 testcase("can subtract mpt");
1134
1135 MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}};
1136 MPTIssue const mpt2{MPTIssue{makeMptID(2, AccountID(0x4985601))}};
1137
1138 // Subtracting zero
1139 {
1140 STAmount const amt1(mpt, 1000);
1141 STAmount const amt2(mpt, 0);
1142 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1143 }
1144
1145 // Subtracting zero
1146 {
1147 STAmount const amt1(mpt, 0);
1148 STAmount const amt2(mpt, 1000);
1149 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1150 }
1151
1152 // Subtracting two positive MPT amounts
1153 {
1154 STAmount const amt1(mpt, 1500);
1155 STAmount const amt2(mpt, 500);
1156 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1157 }
1158
1159 // Subtracting two negative MPT amounts
1160 {
1161 STAmount const amt1(mpt, -1500);
1162 STAmount const amt2(mpt, -500);
1163 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1164 }
1165
1166 // Subtracting a positive and a negative MPT amount
1167 {
1168 STAmount const amt1(mpt, 1000);
1169 STAmount const amt2(mpt, -1000);
1170 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
1171 }
1172
1173 // Underflow check for min MPT amounts
1174 // Note: Cannot check min MPT underflow because you cannot initialize
1175 // the STAmount with a negative MPT amount.
1176
1177 // Overflow check for max positive MPT amounts (should fail)
1178 {
1180 STAmount const amt2(mpt, -2);
1181 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1182 }
1183
1184 // Subtracting MPT and XRP
1185 {
1186 STAmount const amt1(XRPAmount(1000));
1187 STAmount const amt2(mpt, 1000);
1188 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1189 }
1190
1191 // Subtracting different MPT issues (non zero)
1192 {
1193 STAmount const amt1(mpt, 1000);
1194 STAmount const amt2(mpt2, 500);
1195 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1196 }
1197
1198 // Subtracting different MPT issues (zero)
1199 {
1200 STAmount const amt1(mpt, 0);
1201 STAmount const amt2(mpt2, 500);
1202 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1203 }
1204 }
1205
1206 void
1208 {
1209 testcase("isZeroAtScale");
1210
1211 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
1212
1213 // IOU: 10 IOU — mantissa = kMinValue (10^15), exponent = -14.
1214 // One ULP at this scale is 10^-14; half-ULP is 5*10^-15.
1215 {
1216 STAmount const ref{usd, STAmount::kMinValue, -14};
1217 int const refScale = ref.exponent(); // -14
1218 BEAST_EXPECT(refScale == -14);
1219
1220 // Zero rounds to zero at any scale.
1221 STAmount const iouZero{usd, 0};
1222 BEAST_EXPECT(iouZero.isZeroAtScale(refScale));
1223
1224 // Sub-ULP: 1e-16 IOU (mantissa = kMinValue, exponent = -31).
1225 // Far below half-ULP → rounds to zero.
1226 STAmount const subUlp{usd, STAmount::kMinValue, -31};
1227 BEAST_EXPECT(subUlp.isZeroAtScale(refScale));
1228
1229 // One ULP: 1e-14 IOU (mantissa = kMinValue, exponent = -29).
1230 // Exactly the smallest representable unit at refScale → not zero.
1231 STAmount const oneUlp{usd, STAmount::kMinValue, -29};
1232 BEAST_EXPECT(!oneUlp.isZeroAtScale(refScale));
1233
1234 // The reference value itself: exponent == scale → returned
1235 // unchanged → not zero.
1236 BEAST_EXPECT(!ref.isZeroAtScale(refScale));
1237
1238 // A much larger value: certainly not zero at this scale.
1239 STAmount const large{usd, STAmount::kMinValue, 0}; // 1e15 IOU
1240 BEAST_EXPECT(!large.isZeroAtScale(refScale));
1241
1242 // When scale equals the value's own exponent, roundToScale
1243 // short-circuits and returns the value unchanged.
1244 BEAST_EXPECT(!subUlp.isZeroAtScale(subUlp.exponent()));
1245 BEAST_EXPECT(!oneUlp.isZeroAtScale(oneUlp.exponent()));
1246
1247 // Half-ULP boundary. roundToScale forms (value + ref) - ref
1248 // where ref = 10 IOU has mantissa 1e15 (LSB 0, even).
1249 // Number's default rounding is to-nearest-even, so an exact
1250 // half-ULP tie rounds toward the even-LSB neighbour — the
1251 // reference itself — and the round-trip result is zero.
1252 // Just below half-ULP rounds the same way; just above
1253 // clears half-ULP and bumps the mantissa to 1e15 + 1.
1254 STAmount const justBelowHalf{usd, STAmount::kMinValue * 4, -30};
1255 BEAST_EXPECT(justBelowHalf.isZeroAtScale(refScale));
1256
1257 STAmount const halfUlp{usd, STAmount::kMinValue * 5, -30};
1258 BEAST_EXPECT(halfUlp.isZeroAtScale(refScale));
1259
1260 STAmount const justAboveHalf{usd, STAmount::kMinValue * 6, -30};
1261 BEAST_EXPECT(!justAboveHalf.isZeroAtScale(refScale));
1262
1263 // Large magnitude gap: dust value far below an enormous scale.
1264 // 1e-80 with scale +15 — the value vanishes utterly.
1265 STAmount const dust{usd, STAmount::kMinValue, -95};
1266 BEAST_EXPECT(dust.isZeroAtScale(15));
1267
1268 // Negative values mirror positive behaviour.
1269 STAmount const negSubUlp{usd, STAmount::kMinValue, -31, true};
1270 BEAST_EXPECT(negSubUlp.isZeroAtScale(refScale));
1271
1272 STAmount const negOneUlp{usd, STAmount::kMinValue, -29, true};
1273 BEAST_EXPECT(!negOneUlp.isZeroAtScale(refScale));
1274 }
1275
1276 // XRP is integral — roundToScale short-circuits, value is preserved.
1277 {
1278 STAmount const xrp{XRPAmount{1}};
1279 BEAST_EXPECT(!xrp.isZeroAtScale(-14));
1280 BEAST_EXPECT(!xrp.isZeroAtScale(0));
1281
1282 STAmount const xrpZero{XRPAmount{0}};
1283 BEAST_EXPECT(xrpZero.isZeroAtScale(-14));
1284 }
1285
1286 // MPT is integral — same short-circuit behaviour as XRP.
1287 {
1288 MPTIssue const mpt{makeMptID(1, AccountID(0x4985601))};
1289 STAmount const mptAmt{mpt, 1};
1290 BEAST_EXPECT(!mptAmt.isZeroAtScale(0));
1291 BEAST_EXPECT(!mptAmt.isZeroAtScale(-14));
1292
1293 STAmount const mptZero{mpt, 0};
1294 BEAST_EXPECT(mptZero.isZeroAtScale(0));
1295 }
1296 }
1297
1298 //--------------------------------------------------------------------------
1299
1300 void
1301 run() override
1302 {
1303 testSetValue();
1307 testUnderflow();
1308 testRounding();
1309 testParseJson();
1312 testCanAddXRP();
1313 testCanAddIOU();
1314 testCanAddMPT();
1319 }
1320};
1321
1323
1324} // namespace xrpl
A testsuite class.
Definition suite.h:50
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:484
void pass()
Record a successful test condition.
Definition suite.h:500
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:522
LogOs< char > log
Logging output stream.
Definition suite.h:146
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
Represents a JSON value.
Definition json_value.h:130
A currency issued by an account.
Definition Issue.h:13
Currency currency
Definition Issue.h:15
Number is a floating point type that can represent a wide range of values.
Definition Number.h:306
static STAmount roundSelf(STAmount const &amount)
void testSetValue(std::string const &value, Issue const &issue, bool success=true)
void run() override
Runs the suite.
void mulTest(int a, int b)
static STAmount serializeAndDeserialize(STAmount const &s)
void roundTest(int n, int d, int m)
constexpr TIss const & get() const
std::string getFullText() const override
Definition STAmount.cpp:636
void add(Serializer &s) const override
Definition STAmount.cpp:742
std::uint64_t mantissa() const noexcept
Definition STAmount.h:472
std::string getText() const override
Definition STAmount.cpp:646
static constexpr int kMinOffset
Definition STAmount.h:47
SerializedTypeID getSType() const override
Definition STAmount.cpp:630
bool negative() const noexcept
Definition STAmount.h:466
bool isDefault() const override
Definition STAmount.cpp:797
bool native() const noexcept
Definition STAmount.h:453
Asset const & asset() const
Definition STAmount.h:478
int exponent() const noexcept
Definition STAmount.h:441
bool isZeroAtScale(int scale) const
Checks if this amount evaluates to zero when constrained to a specific accounting scale.
static constexpr std::uint64_t kMinValue
Definition STAmount.h:51
static constexpr std::uint64_t kMaxValue
Definition STAmount.h:53
static constexpr std::uint64_t kMaxNative
Definition STAmount.h:55
static constexpr int kMaxOffset
Definition STAmount.h:48
STAmount const & value() const noexcept
Definition STAmount.h:592
Slice slice() const noexcept
Definition Serializer.h:44
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
STAmount divide(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:69
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition Issue.h:97
SField const sfGeneric
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Definition UintTypes.h:36
std::enable_if_t< std::is_integral_v< Integral >, Integral > randInt()
STAmount amountFromString(Asset const &asset, std::string const &amount)
Definition STAmount.cpp:907
bool toCurrency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition UintTypes.cpp:65
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
Definition STAmount.cpp:464
STAmount amountFromQuality(std::uint64_t rate)
Definition STAmount.cpp:895
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition STAmount.cpp:422
STAmount amountFromJson(SField const &name, json::Value const &v)
Definition STAmount.cpp:916
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
bool canSubtract(STAmount const &amt1, STAmount const &amt2)
Determines if it is safe to subtract one STAmount from another.
Definition STAmount.cpp:541
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition Issue.h:105
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, xrpl)
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
Definition Indexes.cpp:172
static void canonicalizeRound(bool integral, std::uint64_t &value, int &offset, bool)
T to_string(T... args)
T what(T... args)