rippled
Loading...
Searching...
No Matches
STAmount_test.cpp
1#include <test/jtx.h>
2
3#include <xrpl/basics/random.h>
4#include <xrpl/beast/unit_test.h>
5#include <xrpl/protocol/STAmount.h>
6
7namespace ripple {
8
10{
11public:
12 static STAmount
14 {
15 Serializer ser;
16 s.add(ser);
17
18 SerialIter sit(ser.slice());
19 return STAmount(sit, sfGeneric);
20 }
21
22 //--------------------------------------------------------------------------
24 roundSelf(STAmount const& amount)
25 {
26 if (amount.native())
27 return amount;
28
29 std::uint64_t mantissa = amount.mantissa();
30 std::uint64_t valueDigits = mantissa % 1000000000;
31
32 if (valueDigits == 1)
33 {
34 mantissa--;
35
36 if (mantissa < STAmount::cMinValue)
37 return {
38 amount.issue(),
39 mantissa,
40 amount.exponent(),
41 amount.negative()};
42
43 return {
44 amount.issue(),
45 mantissa,
46 amount.exponent(),
47 amount.negative(),
49 }
50
51 if (valueDigits == 999999999)
52 {
53 mantissa++;
54
55 if (mantissa > STAmount::cMaxValue)
56 return {
57 amount.issue(),
58 mantissa,
59 amount.exponent(),
60 amount.negative()};
61
62 return {
63 amount.issue(),
64 mantissa,
65 amount.exponent(),
66 amount.negative(),
68 }
69
70 return amount;
71 }
72
73 void
74 roundTest(int n, int d, int m)
75 {
76 // check STAmount rounding
77 STAmount num(noIssue(), n);
78 STAmount den(noIssue(), d);
79 STAmount mul(noIssue(), m);
80 STAmount quot = divide(STAmount(n), STAmount(d), noIssue());
81 STAmount res = roundSelf(multiply(quot, mul, noIssue()));
82
83 BEAST_EXPECT(!res.native());
84
85 STAmount cmp(noIssue(), (n * m) / d);
86
87 BEAST_EXPECT(!cmp.native());
88
89 BEAST_EXPECT(cmp.issue().currency == res.issue().currency);
90
91 if (res != cmp)
92 {
93 log << "(" << num.getText() << "/" << den.getText() << ") X "
94 << mul.getText() << " = " << res.getText() << " not "
95 << cmp.getText();
96 fail("Rounding");
97 return;
98 }
99 }
100
101 void
102 mulTest(int a, int b)
103 {
104 STAmount aa(noIssue(), a);
105 STAmount bb(noIssue(), b);
106 STAmount prod1(multiply(aa, bb, noIssue()));
107
108 BEAST_EXPECT(!prod1.native());
109
110 STAmount prod2(
111 noIssue(),
112 static_cast<std::uint64_t>(a) * static_cast<std::uint64_t>(b));
113
114 if (prod1 != prod2)
115 {
116 log << "nn(" << aa.getFullText() << " * " << bb.getFullText()
117 << ") = " << prod1.getFullText() << " not "
118 << prod2.getFullText();
119 fail("Multiplication result is not exact");
120 }
121 }
122
123 //--------------------------------------------------------------------------
124
125 void
127 std::string const& value,
128 Issue const& issue,
129 bool success = true)
130 {
131 try
132 {
133 STAmount const amount = amountFromString(issue, value);
134 BEAST_EXPECT(amount.getText() == value);
135 }
136 catch (std::exception const&)
137 {
138 BEAST_EXPECT(!success);
139 }
140 }
141
142 void
144 {
145 {
146 testcase("set value (native)");
147
148 Issue const xrp(xrpIssue());
149
150 // fractional XRP (i.e. drops)
151 testSetValue("1", xrp);
152 testSetValue("22", xrp);
153 testSetValue("333", xrp);
154 testSetValue("4444", xrp);
155 testSetValue("55555", xrp);
156 testSetValue("666666", xrp);
157
158 // 1 XRP up to 100 billion, in powers of 10 (in drops)
159 testSetValue("1000000", xrp);
160 testSetValue("10000000", xrp);
161 testSetValue("100000000", xrp);
162 testSetValue("1000000000", xrp);
163 testSetValue("10000000000", xrp);
164 testSetValue("100000000000", xrp);
165 testSetValue("1000000000000", xrp);
166 testSetValue("10000000000000", xrp);
167 testSetValue("100000000000000", xrp);
168 testSetValue("1000000000000000", xrp);
169 testSetValue("10000000000000000", xrp);
170 testSetValue("100000000000000000", xrp);
171
172 // Invalid native values:
173 testSetValue("1.1", xrp, false);
174 testSetValue("100000000000000001", xrp, false);
175 testSetValue("1000000000000000000", xrp, false);
176 }
177
178 {
179 testcase("set value (iou)");
180
181 Issue const usd(Currency(0x5553440000000000), AccountID(0x4985601));
182
183 testSetValue("1", usd);
184 testSetValue("10", usd);
185 testSetValue("100", usd);
186 testSetValue("1000", usd);
187 testSetValue("10000", usd);
188 testSetValue("100000", usd);
189 testSetValue("1000000", usd);
190 testSetValue("10000000", usd);
191 testSetValue("100000000", usd);
192 testSetValue("1000000000", usd);
193 testSetValue("10000000000", usd);
194
195 testSetValue("1234567.1", usd);
196 testSetValue("1234567.12", usd);
197 testSetValue("1234567.123", usd);
198 testSetValue("1234567.1234", usd);
199 testSetValue("1234567.12345", usd);
200 testSetValue("1234567.123456", usd);
201 testSetValue("1234567.1234567", usd);
202 testSetValue("1234567.12345678", usd);
203 testSetValue("1234567.123456789", usd);
204 }
205 }
206
207 //--------------------------------------------------------------------------
208
209 void
211 {
212 testcase("native currency");
213 STAmount zeroSt, one(1), hundred(100);
214 // VFALCO NOTE Why repeat "STAmount fail" so many times??
215 unexpected(serializeAndDeserialize(zeroSt) != zeroSt, "STAmount fail");
216 unexpected(serializeAndDeserialize(one) != one, "STAmount fail");
218 serializeAndDeserialize(hundred) != hundred, "STAmount fail");
219 unexpected(!zeroSt.native(), "STAmount fail");
220 unexpected(!hundred.native(), "STAmount fail");
221 unexpected(zeroSt != beast::zero, "STAmount fail");
222 unexpected(one == beast::zero, "STAmount fail");
223 unexpected(hundred == beast::zero, "STAmount fail");
224 unexpected((zeroSt < zeroSt), "STAmount fail");
225 unexpected(!(zeroSt < one), "STAmount fail");
226 unexpected(!(zeroSt < hundred), "STAmount fail");
227 unexpected((one < zeroSt), "STAmount fail");
228 unexpected((one < one), "STAmount fail");
229 unexpected(!(one < hundred), "STAmount fail");
230 unexpected((hundred < zeroSt), "STAmount fail");
231 unexpected((hundred < one), "STAmount fail");
232 unexpected((hundred < hundred), "STAmount fail");
233 unexpected((zeroSt > zeroSt), "STAmount fail");
234 unexpected((zeroSt > one), "STAmount fail");
235 unexpected((zeroSt > hundred), "STAmount fail");
236 unexpected(!(one > zeroSt), "STAmount fail");
237 unexpected((one > one), "STAmount fail");
238 unexpected((one > hundred), "STAmount fail");
239 unexpected(!(hundred > zeroSt), "STAmount fail");
240 unexpected(!(hundred > one), "STAmount fail");
241 unexpected((hundred > hundred), "STAmount fail");
242 unexpected(!(zeroSt <= zeroSt), "STAmount fail");
243 unexpected(!(zeroSt <= one), "STAmount fail");
244 unexpected(!(zeroSt <= hundred), "STAmount fail");
245 unexpected((one <= zeroSt), "STAmount fail");
246 unexpected(!(one <= one), "STAmount fail");
247 unexpected(!(one <= hundred), "STAmount fail");
248 unexpected((hundred <= zeroSt), "STAmount fail");
249 unexpected((hundred <= one), "STAmount fail");
250 unexpected(!(hundred <= hundred), "STAmount fail");
251 unexpected(!(zeroSt >= zeroSt), "STAmount fail");
252 unexpected((zeroSt >= one), "STAmount fail");
253 unexpected((zeroSt >= hundred), "STAmount fail");
254 unexpected(!(one >= zeroSt), "STAmount fail");
255 unexpected(!(one >= one), "STAmount fail");
256 unexpected((one >= hundred), "STAmount fail");
257 unexpected(!(hundred >= zeroSt), "STAmount fail");
258 unexpected(!(hundred >= one), "STAmount fail");
259 unexpected(!(hundred >= hundred), "STAmount fail");
260 unexpected(!(zeroSt == zeroSt), "STAmount fail");
261 unexpected((zeroSt == one), "STAmount fail");
262 unexpected((zeroSt == hundred), "STAmount fail");
263 unexpected((one == zeroSt), "STAmount fail");
264 unexpected(!(one == one), "STAmount fail");
265 unexpected((one == hundred), "STAmount fail");
266 unexpected((hundred == zeroSt), "STAmount fail");
267 unexpected((hundred == one), "STAmount fail");
268 unexpected(!(hundred == hundred), "STAmount fail");
269 unexpected((zeroSt != zeroSt), "STAmount fail");
270 unexpected(!(zeroSt != one), "STAmount fail");
271 unexpected(!(zeroSt != hundred), "STAmount fail");
272 unexpected(!(one != zeroSt), "STAmount fail");
273 unexpected((one != one), "STAmount fail");
274 unexpected(!(one != hundred), "STAmount fail");
275 unexpected(!(hundred != zeroSt), "STAmount fail");
276 unexpected(!(hundred != one), "STAmount fail");
277 unexpected((hundred != hundred), "STAmount fail");
278 unexpected(STAmount().getText() != "0", "STAmount fail");
279 unexpected(STAmount(31).getText() != "31", "STAmount fail");
280 unexpected(STAmount(310).getText() != "310", "STAmount fail");
281 unexpected(to_string(Currency()) != "XRP", "cHC(XRP)");
282 Currency c;
283 unexpected(!to_currency(c, "USD"), "create USD currency");
284 unexpected(to_string(c) != "USD", "check USD currency");
285
286 std::string const cur = "015841551A748AD2C1F76FF6ECB0CCCD00000000";
287 unexpected(!to_currency(c, cur), "create custom currency");
288 unexpected(to_string(c) != cur, "check custom currency");
289 }
290
291 //--------------------------------------------------------------------------
292
293 void
295 {
296 testcase("custom currency");
297 STAmount zeroSt(noIssue()), one(noIssue(), 1), hundred(noIssue(), 100);
298 unexpected(serializeAndDeserialize(zeroSt) != zeroSt, "STAmount fail");
299 unexpected(serializeAndDeserialize(one) != one, "STAmount fail");
301 serializeAndDeserialize(hundred) != hundred, "STAmount fail");
302 unexpected(zeroSt.native(), "STAmount fail");
303 unexpected(hundred.native(), "STAmount fail");
304 unexpected(zeroSt != beast::zero, "STAmount fail");
305 unexpected(one == beast::zero, "STAmount fail");
306 unexpected(hundred == beast::zero, "STAmount fail");
307 unexpected((zeroSt < zeroSt), "STAmount fail");
308 unexpected(!(zeroSt < one), "STAmount fail");
309 unexpected(!(zeroSt < hundred), "STAmount fail");
310 unexpected((one < zeroSt), "STAmount fail");
311 unexpected((one < one), "STAmount fail");
312 unexpected(!(one < hundred), "STAmount fail");
313 unexpected((hundred < zeroSt), "STAmount fail");
314 unexpected((hundred < one), "STAmount fail");
315 unexpected((hundred < hundred), "STAmount fail");
316 unexpected((zeroSt > zeroSt), "STAmount fail");
317 unexpected((zeroSt > one), "STAmount fail");
318 unexpected((zeroSt > hundred), "STAmount fail");
319 unexpected(!(one > zeroSt), "STAmount fail");
320 unexpected((one > one), "STAmount fail");
321 unexpected((one > hundred), "STAmount fail");
322 unexpected(!(hundred > zeroSt), "STAmount fail");
323 unexpected(!(hundred > one), "STAmount fail");
324 unexpected((hundred > hundred), "STAmount fail");
325 unexpected(!(zeroSt <= zeroSt), "STAmount fail");
326 unexpected(!(zeroSt <= one), "STAmount fail");
327 unexpected(!(zeroSt <= hundred), "STAmount fail");
328 unexpected((one <= zeroSt), "STAmount fail");
329 unexpected(!(one <= one), "STAmount fail");
330 unexpected(!(one <= hundred), "STAmount fail");
331 unexpected((hundred <= zeroSt), "STAmount fail");
332 unexpected((hundred <= one), "STAmount fail");
333 unexpected(!(hundred <= hundred), "STAmount fail");
334 unexpected(!(zeroSt >= zeroSt), "STAmount fail");
335 unexpected((zeroSt >= one), "STAmount fail");
336 unexpected((zeroSt >= hundred), "STAmount fail");
337 unexpected(!(one >= zeroSt), "STAmount fail");
338 unexpected(!(one >= one), "STAmount fail");
339 unexpected((one >= hundred), "STAmount fail");
340 unexpected(!(hundred >= zeroSt), "STAmount fail");
341 unexpected(!(hundred >= one), "STAmount fail");
342 unexpected(!(hundred >= hundred), "STAmount fail");
343 unexpected(!(zeroSt == zeroSt), "STAmount fail");
344 unexpected((zeroSt == one), "STAmount fail");
345 unexpected((zeroSt == hundred), "STAmount fail");
346 unexpected((one == zeroSt), "STAmount fail");
347 unexpected(!(one == one), "STAmount fail");
348 unexpected((one == hundred), "STAmount fail");
349 unexpected((hundred == zeroSt), "STAmount fail");
350 unexpected((hundred == one), "STAmount fail");
351 unexpected(!(hundred == hundred), "STAmount fail");
352 unexpected((zeroSt != zeroSt), "STAmount fail");
353 unexpected(!(zeroSt != one), "STAmount fail");
354 unexpected(!(zeroSt != hundred), "STAmount fail");
355 unexpected(!(one != zeroSt), "STAmount fail");
356 unexpected((one != one), "STAmount fail");
357 unexpected(!(one != hundred), "STAmount fail");
358 unexpected(!(hundred != zeroSt), "STAmount fail");
359 unexpected(!(hundred != one), "STAmount fail");
360 unexpected((hundred != hundred), "STAmount fail");
361 unexpected(STAmount(noIssue()).getText() != "0", "STAmount fail");
362 unexpected(STAmount(noIssue(), 31).getText() != "31", "STAmount fail");
364 STAmount(noIssue(), 31, 1).getText() != "310", "STAmount fail");
366 STAmount(noIssue(), 31, -1).getText() != "3.1", "STAmount fail");
368 STAmount(noIssue(), 31, -2).getText() != "0.31", "STAmount fail");
371 .getText() != "60",
372 "STAmount multiply fail 1");
375 .getText() != "60",
376 "STAmount multiply fail 2");
378 multiply(STAmount(20), STAmount(3), noIssue()).getText() != "60",
379 "STAmount multiply fail 3");
381 multiply(STAmount(20), STAmount(3), xrpIssue()).getText() != "60",
382 "STAmount multiply fail 4");
383
384 if (divide(STAmount(noIssue(), 60), STAmount(3), noIssue()).getText() !=
385 "20")
386 {
387 log << "60/3 = "
388 << divide(STAmount(noIssue(), 60), STAmount(3), noIssue())
389 .getText();
390 fail("STAmount divide fail");
391 }
392 else
393 {
394 pass();
395 }
396
399 .getText() != "20",
400 "STAmount divide fail");
401
404 .getText() != "20",
405 "STAmount divide fail");
406
409 .getText() != "20",
410 "STAmount divide fail");
411
412 STAmount a1(noIssue(), 60), a2(noIssue(), 10, -1);
413
415 divide(a2, a1, noIssue()) != amountFromQuality(getRate(a1, a2)),
416 "STAmount setRate(getRate) fail");
417
419 divide(a1, a2, noIssue()) != amountFromQuality(getRate(a2, a1)),
420 "STAmount setRate(getRate) fail");
421 }
422
423 //--------------------------------------------------------------------------
424
425 void
427 {
428 testcase("arithmetic");
429
430 // Test currency multiplication and division operations such as
431 // convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed,
432 // and getNeeded
433
435 getRate(STAmount(1), STAmount(10)) !=
436 (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
437 "STAmount getRate fail 1");
438
440 getRate(STAmount(10), STAmount(1)) !=
441 (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
442 "STAmount getRate fail 2");
443
445 getRate(STAmount(noIssue(), 1), STAmount(noIssue(), 10)) !=
446 (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
447 "STAmount getRate fail 3");
448
450 getRate(STAmount(noIssue(), 10), STAmount(noIssue(), 1)) !=
451 (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
452 "STAmount getRate fail 4");
453
455 getRate(STAmount(noIssue(), 1), STAmount(10)) !=
456 (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
457 "STAmount getRate fail 5");
458
460 getRate(STAmount(noIssue(), 10), STAmount(1)) !=
461 (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
462 "STAmount getRate fail 6");
463
465 getRate(STAmount(1), STAmount(noIssue(), 10)) !=
466 (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
467 "STAmount getRate fail 7");
468
470 getRate(STAmount(10), STAmount(noIssue(), 1)) !=
471 (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
472 "STAmount getRate fail 8");
473
474 roundTest(1, 3, 3);
475 roundTest(2, 3, 9);
476 roundTest(1, 7, 21);
477 roundTest(1, 2, 4);
478 roundTest(3, 9, 18);
479 roundTest(7, 11, 44);
480
481 for (int i = 0; i <= 100000; ++i)
482 {
483 mulTest(rand_int(10000000), rand_int(10000000));
484 }
485 }
486
487 //--------------------------------------------------------------------------
488
489 void
491 {
492 testcase("underflow");
493
494 STAmount bigNative(STAmount::cMaxNative / 2);
495 STAmount bigValue(
496 noIssue(),
499 STAmount smallValue(
500 noIssue(),
503 STAmount zeroSt(noIssue(), 0);
504
505 STAmount smallXsmall = multiply(smallValue, smallValue, noIssue());
506
507 BEAST_EXPECT(smallXsmall == beast::zero);
508
509 STAmount bigDsmall = divide(smallValue, bigValue, noIssue());
510
511 BEAST_EXPECT(bigDsmall == beast::zero);
512
513 BEAST_EXPECT(bigDsmall == beast::zero);
514
515 bigDsmall = divide(smallValue, bigValue, xrpIssue());
516
517 BEAST_EXPECT(bigDsmall == beast::zero);
518
519 bigDsmall = divide(smallValue, bigNative, xrpIssue());
520
521 BEAST_EXPECT(bigDsmall == beast::zero);
522
523 // very bad offer
524 std::uint64_t r = getRate(smallValue, bigValue);
525
526 BEAST_EXPECT(r == 0);
527
528 // very good offer
529 r = getRate(bigValue, smallValue);
530
531 BEAST_EXPECT(r == 0);
532 }
533
534 //--------------------------------------------------------------------------
535
536 void
538 {
539 // VFALCO TODO There are no actual tests here, just printed output?
540 // Change this to actually do something.
541
542#if 0
543 beginTestCase ("rounding ");
544
545 std::uint64_t value = 25000000000000000ull;
546 int offset = -14;
547 canonicalizeRound (false, value, offset, true);
548
549 STAmount one (noIssue(), 1);
550 STAmount two (noIssue(), 2);
551 STAmount three (noIssue(), 3);
552
553 STAmount oneThird1 = divRound (one, three, noIssue(), false);
554 STAmount oneThird2 = divide (one, three, noIssue());
555 STAmount oneThird3 = divRound (one, three, noIssue(), true);
556 log << oneThird1;
557 log << oneThird2;
558 log << oneThird3;
559
560 STAmount twoThird1 = divRound (two, three, noIssue(), false);
561 STAmount twoThird2 = divide (two, three, noIssue());
562 STAmount twoThird3 = divRound (two, three, noIssue(), true);
563 log << twoThird1;
564 log << twoThird2;
565 log << twoThird3;
566
567 STAmount oneA = mulRound (oneThird1, three, noIssue(), false);
568 STAmount oneB = multiply (oneThird2, three, noIssue());
569 STAmount oneC = mulRound (oneThird3, three, noIssue(), true);
570 log << oneA;
571 log << oneB;
572 log << oneC;
573
574 STAmount fourThirdsB = twoThird2 + twoThird2;
575 log << fourThirdsA;
576 log << fourThirdsB;
577 log << fourThirdsC;
578
579 STAmount dripTest1 = mulRound (twoThird2, two, xrpIssue (), false);
580 STAmount dripTest2 = multiply (twoThird2, two, xrpIssue ());
581 STAmount dripTest3 = mulRound (twoThird2, two, xrpIssue (), true);
582 log << dripTest1;
583 log << dripTest2;
584 log << dripTest3;
585#endif
586 }
587
588 void
590 {
591 testcase("STAmount to XRPAmount conversions");
592
593 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
594 Issue const xrp{xrpIssue()};
595
596 for (std::uint64_t drops = 100000000000000000; drops != 1;
597 drops = drops / 10)
598 {
599 auto const t = amountFromString(xrp, std::to_string(drops));
600 auto const s = t.xrp();
601 BEAST_EXPECT(s.drops() == drops);
602 BEAST_EXPECT(t == STAmount(XRPAmount(drops)));
603 BEAST_EXPECT(s == XRPAmount(drops));
604 }
605
606 try
607 {
608 auto const t = amountFromString(usd, "136500");
609 fail(to_string(t.xrp()));
610 }
611 catch (std::logic_error const&)
612 {
613 pass();
614 }
615 catch (std::exception const&)
616 {
617 fail("wrong exception");
618 }
619 }
620
621 void
623 {
624 testcase("STAmount to IOUAmount conversions");
625
626 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
627 Issue const xrp{xrpIssue()};
628
629 for (std::uint64_t dollars = 10000000000; dollars != 1;
630 dollars = dollars / 10)
631 {
632 auto const t = amountFromString(usd, std::to_string(dollars));
633 auto const s = t.iou();
634 BEAST_EXPECT(t == STAmount(s, usd));
635 BEAST_EXPECT(s.mantissa() == t.mantissa());
636 BEAST_EXPECT(s.exponent() == t.exponent());
637 }
638
639 try
640 {
641 auto const t = amountFromString(xrp, "136500");
642 fail(to_string(t.iou()));
643 }
644 catch (std::logic_error const&)
645 {
646 pass();
647 }
648 catch (std::exception const&)
649 {
650 fail("wrong exception");
651 }
652 }
653
654 void
656 {
657 testcase("can add xrp");
658
659 // Adding zero
660 {
661 STAmount amt1(XRPAmount(0));
662 STAmount amt2(XRPAmount(1000));
663 BEAST_EXPECT(canAdd(amt1, amt2) == true);
664 }
665
666 // Adding zero
667 {
668 STAmount amt1(XRPAmount(1000));
669 STAmount amt2(XRPAmount(0));
670 BEAST_EXPECT(canAdd(amt1, amt2) == true);
671 }
672
673 // Adding two positive XRP amounts
674 {
675 STAmount amt1(XRPAmount(500));
676 STAmount amt2(XRPAmount(1500));
677 BEAST_EXPECT(canAdd(amt1, amt2) == true);
678 }
679
680 // Adding two negative XRP amounts
681 {
682 STAmount amt1(XRPAmount(-500));
683 STAmount amt2(XRPAmount(-1500));
684 BEAST_EXPECT(canAdd(amt1, amt2) == true);
685 }
686
687 // Adding a positive and a negative XRP amount
688 {
689 STAmount amt1(XRPAmount(1000));
690 STAmount amt2(XRPAmount(-1000));
691 BEAST_EXPECT(canAdd(amt1, amt2) == true);
692 }
693
694 // Overflow check for max XRP amounts
695 {
697 STAmount amt2(XRPAmount(1));
698 BEAST_EXPECT(canAdd(amt1, amt2) == false);
699 }
700
701 // Overflow check for min XRP amounts
702 {
704 amt1 += XRPAmount(1);
705 STAmount amt2(XRPAmount(-1));
706 BEAST_EXPECT(canAdd(amt1, amt2) == false);
707 }
708 }
709
710 void
712 {
713 testcase("can add iou");
714
715 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
716 Issue const eur{Currency(0x4555520000000000), AccountID(0x4985601)};
717
718 // Adding two IOU amounts
719 {
720 STAmount amt1(usd, 500);
721 STAmount amt2(usd, 1500);
722 BEAST_EXPECT(canAdd(amt1, amt2) == true);
723 }
724
725 // Adding a positive and a negative IOU amount
726 {
727 STAmount amt1(usd, 1000);
728 STAmount amt2(usd, -1000);
729 BEAST_EXPECT(canAdd(amt1, amt2) == true);
730 }
731
732 // Overflow check for max IOU amounts
733 {
735 STAmount amt2(usd, 1);
736 BEAST_EXPECT(canAdd(amt1, amt2) == false);
737 }
738
739 // Overflow check for min IOU amounts
740 {
742 STAmount amt2(usd, -1);
743 BEAST_EXPECT(canAdd(amt1, amt2) == false);
744 }
745
746 // Adding XRP and IOU
747 {
748 STAmount amt1(XRPAmount(1));
749 STAmount amt2(usd, 1);
750 BEAST_EXPECT(canAdd(amt1, amt2) == false);
751 }
752
753 // Adding different IOU issues (non zero)
754 {
755 STAmount amt1(usd, 1000);
756 STAmount amt2(eur, 500);
757 BEAST_EXPECT(canAdd(amt1, amt2) == false);
758 }
759
760 // Adding different IOU issues (zero)
761 {
762 STAmount amt1(usd, 0);
763 STAmount amt2(eur, 500);
764 BEAST_EXPECT(canAdd(amt1, amt2) == false);
765 }
766 }
767
768 void
770 {
771 testcase("can add mpt");
772
773 MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}};
774 MPTIssue const mpt2{MPTIssue{makeMptID(2, AccountID(0x4985601))}};
775
776 // Adding zero
777 {
778 STAmount amt1(mpt, 0);
779 STAmount amt2(mpt, 1000);
780 BEAST_EXPECT(canAdd(amt1, amt2) == true);
781 }
782
783 // Adding zero
784 {
785 STAmount amt1(mpt, 1000);
786 STAmount amt2(mpt, 0);
787 BEAST_EXPECT(canAdd(amt1, amt2) == true);
788 }
789
790 // Adding two positive MPT amounts
791 {
792 STAmount amt1(mpt, 500);
793 STAmount amt2(mpt, 1500);
794 BEAST_EXPECT(canAdd(amt1, amt2) == true);
795 }
796
797 // Adding two negative MPT amounts
798 {
799 STAmount amt1(mpt, -500);
800 STAmount amt2(mpt, -1500);
801 BEAST_EXPECT(canAdd(amt1, amt2) == true);
802 }
803
804 // Adding a positive and a negative MPT amount
805 {
806 STAmount amt1(mpt, 1000);
807 STAmount amt2(mpt, -1000);
808 BEAST_EXPECT(canAdd(amt1, amt2) == true);
809 }
810
811 // Overflow check for max MPT amounts
812 {
813 STAmount amt1(
815 STAmount amt2(mpt, 1);
816 BEAST_EXPECT(canAdd(amt1, amt2) == false);
817 }
818
819 // Overflow check for min MPT amounts
820 // Note: Cannot check min MPT overflow because you cannot initialize the
821 // STAmount with a negative MPT amount.
822
823 // Adding MPT and XRP
824 {
825 STAmount amt1(XRPAmount(1000));
826 STAmount amt2(mpt, 1000);
827 BEAST_EXPECT(canAdd(amt1, amt2) == false);
828 }
829
830 // Adding different MPT issues (non zero)
831 {
832 STAmount amt1(mpt2, 500);
833 STAmount amt2(mpt, 500);
834 BEAST_EXPECT(canAdd(amt1, amt2) == false);
835 }
836
837 // Adding different MPT issues (non zero)
838 {
839 STAmount amt1(mpt2, 0);
840 STAmount amt2(mpt, 500);
841 BEAST_EXPECT(canAdd(amt1, amt2) == false);
842 }
843 }
844
845 void
847 {
848 testcase("can subtract xrp");
849
850 // Subtracting zero
851 {
852 STAmount amt1(XRPAmount(1000));
853 STAmount amt2(XRPAmount(0));
854 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
855 }
856
857 // Subtracting zero
858 {
859 STAmount amt1(XRPAmount(0));
860 STAmount amt2(XRPAmount(1000));
861 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
862 }
863
864 // Subtracting two positive XRP amounts
865 {
866 STAmount amt1(XRPAmount(1500));
867 STAmount amt2(XRPAmount(500));
868 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
869 }
870
871 // Subtracting two negative XRP amounts
872 {
873 STAmount amt1(XRPAmount(-1500));
874 STAmount amt2(XRPAmount(-500));
875 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
876 }
877
878 // Subtracting a positive and a negative XRP amount
879 {
880 STAmount amt1(XRPAmount(1000));
881 STAmount amt2(XRPAmount(-1000));
882 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
883 }
884
885 // Underflow check for min XRP amounts
886 {
888 amt1 += XRPAmount(1);
889 STAmount amt2(XRPAmount(1));
890 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
891 }
892
893 // Overflow check for max XRP amounts
894 {
896 STAmount amt2(XRPAmount(-1));
897 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
898 }
899 }
900
901 void
903 {
904 testcase("can subtract iou");
905 Issue const usd{Currency(0x5553440000000000), AccountID(0x4985601)};
906 Issue const eur{Currency(0x4555520000000000), AccountID(0x4985601)};
907
908 // Subtracting two IOU amounts
909 {
910 STAmount amt1(usd, 1500);
911 STAmount amt2(usd, 500);
912 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
913 }
914
915 // Subtracting XRP and IOU
916 {
917 STAmount amt1(XRPAmount(1000));
918 STAmount amt2(usd, 1000);
919 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
920 }
921
922 // Subtracting different IOU issues (non zero)
923 {
924 STAmount amt1(usd, 1000);
925 STAmount amt2(eur, 500);
926 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
927 }
928
929 // Subtracting different IOU issues (zero)
930 {
931 STAmount amt1(usd, 0);
932 STAmount amt2(eur, 500);
933 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
934 }
935 }
936
937 void
939 {
940 testcase("can subtract mpt");
941
942 MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}};
943 MPTIssue const mpt2{MPTIssue{makeMptID(2, AccountID(0x4985601))}};
944
945 // Subtracting zero
946 {
947 STAmount amt1(mpt, 1000);
948 STAmount amt2(mpt, 0);
949 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
950 }
951
952 // Subtracting zero
953 {
954 STAmount amt1(mpt, 0);
955 STAmount amt2(mpt, 1000);
956 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
957 }
958
959 // Subtracting two positive MPT amounts
960 {
961 STAmount amt1(mpt, 1500);
962 STAmount amt2(mpt, 500);
963 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
964 }
965
966 // Subtracting two negative MPT amounts
967 {
968 STAmount amt1(mpt, -1500);
969 STAmount amt2(mpt, -500);
970 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
971 }
972
973 // Subtracting a positive and a negative MPT amount
974 {
975 STAmount amt1(mpt, 1000);
976 STAmount amt2(mpt, -1000);
977 BEAST_EXPECT(canSubtract(amt1, amt2) == true);
978 }
979
980 // Underflow check for min MPT amounts
981 // Note: Cannot check min MPT underflow because you cannot initialize
982 // the STAmount with a negative MPT amount.
983
984 // Overflow check for max positive MPT amounts (should fail)
985 {
986 STAmount amt1(
988 STAmount amt2(mpt, -2);
989 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
990 }
991
992 // Subtracting MPT and XRP
993 {
994 STAmount amt1(XRPAmount(1000));
995 STAmount amt2(mpt, 1000);
996 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
997 }
998
999 // Subtracting different MPT issues (non zero)
1000 {
1001 STAmount amt1(mpt, 1000);
1002 STAmount amt2(mpt2, 500);
1003 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1004 }
1005
1006 // Subtracting different MPT issues (zero)
1007 {
1008 STAmount amt1(mpt, 0);
1009 STAmount amt2(mpt2, 500);
1010 BEAST_EXPECT(canSubtract(amt1, amt2) == false);
1011 }
1012 }
1013
1014 //--------------------------------------------------------------------------
1015
1016 void
1017 run() override
1018 {
1019 testSetValue();
1023 testUnderflow();
1024 testRounding();
1027 testCanAddXRP();
1028 testCanAddIOU();
1029 testCanAddMPT();
1033 }
1034};
1035
1036BEAST_DEFINE_TESTSUITE(STAmount, protocol, ripple);
1037
1038} // namespace ripple
A testsuite class.
Definition suite.h:52
log_os< char > log
Logging output stream.
Definition suite.h:149
void pass()
Record a successful test condition.
Definition suite.h:508
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:496
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:152
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:530
A currency issued by an account.
Definition Issue.h:14
Currency currency
Definition Issue.h:16
void roundTest(int n, int d, int m)
STAmount roundSelf(STAmount const &amount)
static STAmount serializeAndDeserialize(STAmount const &s)
void testSetValue(std::string const &value, Issue const &issue, bool success=true)
void mulTest(int a, int b)
void run() override
Runs the suite.
int exponent() const noexcept
Definition STAmount.h:433
static int const cMaxOffset
Definition STAmount.h:47
static int const cMinOffset
Definition STAmount.h:46
static std::uint64_t const cMinValue
Definition STAmount.h:50
void add(Serializer &s) const override
Definition STAmount.cpp:761
static std::uint64_t const cMaxValue
Definition STAmount.h:51
std::string getText() const override
Definition STAmount.cpp:664
bool negative() const noexcept
Definition STAmount.h:452
Issue const & issue() const
Definition STAmount.h:477
static std::uint64_t const cMaxNative
Definition STAmount.h:52
std::uint64_t mantissa() const noexcept
Definition STAmount.h:458
std::string getFullText() const override
Definition STAmount.cpp:654
bool native() const noexcept
Definition STAmount.h:439
Slice slice() const noexcept
Definition Serializer.h:47
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:29
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition Issue.h:96
STAmount divide(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:74
constexpr Number one
Definition Number.cpp:156
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
bool canSubtract(STAmount const &amt1, STAmount const &amt2)
Determines if it is safe to subtract one STAmount from another.
Definition STAmount.cpp:566
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:486
STAmount amountFromQuality(std::uint64_t rate)
Definition STAmount.cpp:965
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:34
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition STAmount.cpp:444
base_uint< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Definition UintTypes.h:37
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition Issue.h:104
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
STAmount amountFromString(Asset const &asset, std::string const &amount)
Definition STAmount.cpp:977
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
SField const sfGeneric
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
Definition Indexes.cpp:151
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition UintTypes.cpp:65
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset, bool)
T to_string(T... args)