rippled
Loading...
Searching...
No Matches
XRPAmount_test.cpp
1#include <xrpl/beast/unit_test.h>
2#include <xrpl/protocol/XRPAmount.h>
3
4namespace xrpl {
5
7{
8public:
9 void
11 {
12 testcase("signum");
13
14 for (auto i : {-1, 0, 1})
15 {
16 XRPAmount const x(i);
17
18 if (i < 0)
19 {
20 BEAST_EXPECT(x.signum() < 0);
21 }
22 else if (i > 0)
23 {
24 BEAST_EXPECT(x.signum() > 0);
25 }
26 else
27 {
28 BEAST_EXPECT(x.signum() == 0);
29 }
30 }
31 }
32
33 void
35 {
36 testcase("beast::Zero Comparisons");
37
38 using beast::zero;
39
40 for (auto i : {-1, 0, 1})
41 {
42 XRPAmount const x(i);
43
44 BEAST_EXPECT((i == 0) == (x == zero));
45 BEAST_EXPECT((i != 0) == (x != zero));
46 BEAST_EXPECT((i < 0) == (x < zero));
47 BEAST_EXPECT((i > 0) == (x > zero));
48 BEAST_EXPECT((i <= 0) == (x <= zero));
49 BEAST_EXPECT((i >= 0) == (x >= zero));
50
51 BEAST_EXPECT((0 == i) == (zero == x));
52 BEAST_EXPECT((0 != i) == (zero != x));
53 BEAST_EXPECT((0 < i) == (zero < x));
54 BEAST_EXPECT((0 > i) == (zero > x));
55 BEAST_EXPECT((0 <= i) == (zero <= x));
56 BEAST_EXPECT((0 >= i) == (zero >= x));
57 }
58 }
59
60 void
62 {
63 testcase("XRP Comparisons");
64
65 for (auto i : {-1, 0, 1})
66 {
67 XRPAmount const x(i);
68
69 for (auto j : {-1, 0, 1})
70 {
71 XRPAmount const y(j);
72
73 BEAST_EXPECT((i == j) == (x == y));
74 BEAST_EXPECT((i != j) == (x != y));
75 BEAST_EXPECT((i < j) == (x < y));
76 BEAST_EXPECT((i > j) == (x > y));
77 BEAST_EXPECT((i <= j) == (x <= y));
78 BEAST_EXPECT((i >= j) == (x >= y));
79 }
80 }
81 }
82
83 void
85 {
86 testcase("Addition & Subtraction");
87
88 for (auto i : {-1, 0, 1})
89 {
90 XRPAmount const x(i);
91
92 for (auto j : {-1, 0, 1})
93 {
94 XRPAmount const y(j);
95
96 BEAST_EXPECT(XRPAmount(i + j) == (x + y));
97 BEAST_EXPECT(XRPAmount(i - j) == (x - y));
98
99 BEAST_EXPECT((x + y) == (y + x)); // addition is commutative
100 }
101 }
102 }
103
104 void
106 {
107 // Tautology
108 BEAST_EXPECT(DROPS_PER_XRP.decimalXRP() == 1);
109
110 XRPAmount test{1};
111 BEAST_EXPECT(test.decimalXRP() == 0.000001);
112
113 test = -test;
114 BEAST_EXPECT(test.decimalXRP() == -0.000001);
115
116 test = 100'000'000;
117 BEAST_EXPECT(test.decimalXRP() == 100);
118
119 test = -test;
120 BEAST_EXPECT(test.decimalXRP() == -100);
121 }
122
123 void
125 {
126 // Explicitly test every defined function for the XRPAmount class
127 // since some of them are templated, but not used anywhere else.
128 auto make = [&](auto x) -> XRPAmount { return XRPAmount{x}; };
129
130 XRPAmount const defaulted{};
131 (void)defaulted;
132 XRPAmount test{0};
133 BEAST_EXPECT(test.drops() == 0);
134
135 test = make(beast::zero);
136 BEAST_EXPECT(test.drops() == 0);
137
138 test = beast::zero;
139 BEAST_EXPECT(test.drops() == 0);
140
141 test = make(100);
142 BEAST_EXPECT(test.drops() == 100);
143
144 test = make(100u);
145 BEAST_EXPECT(test.drops() == 100);
146
147 XRPAmount const targetSame{200u};
148 test = make(targetSame);
149 BEAST_EXPECT(test.drops() == 200);
150 BEAST_EXPECT(test == targetSame);
151 BEAST_EXPECT(test < XRPAmount{1000});
152 BEAST_EXPECT(test > XRPAmount{100});
153
154 test = std::int64_t(200);
155 BEAST_EXPECT(test.drops() == 200);
156 test = std::uint32_t(300);
157 BEAST_EXPECT(test.drops() == 300);
158
159 test = targetSame;
160 BEAST_EXPECT(test.drops() == 200);
161 auto testOther = test.dropsAs<std::uint32_t>();
162 BEAST_EXPECT(testOther);
163 BEAST_EXPECT(*testOther == 200); // NOLINT(bugprone-unchecked-optional-access)
165 testOther = test.dropsAs<std::uint32_t>();
166 BEAST_EXPECT(!testOther);
167 test = -1;
168 testOther = test.dropsAs<std::uint32_t>();
169 BEAST_EXPECT(!testOther);
170
171 test = targetSame * 2;
172 BEAST_EXPECT(test.drops() == 400);
173 test = 3 * targetSame;
174 BEAST_EXPECT(test.drops() == 600);
175 test = 20;
176 BEAST_EXPECT(test.drops() == 20);
177
178 test += targetSame;
179 BEAST_EXPECT(test.drops() == 220);
180
181 test -= targetSame;
182 BEAST_EXPECT(test.drops() == 20);
183
184 test *= 5;
185 BEAST_EXPECT(test.drops() == 100);
186 test = 50;
187 BEAST_EXPECT(test.drops() == 50);
188 test -= 39;
189 BEAST_EXPECT(test.drops() == 11);
190
191 // legal with signed
192 test = -test;
193 BEAST_EXPECT(test.drops() == -11);
194 BEAST_EXPECT(test.signum() == -1);
195 BEAST_EXPECT(to_string(test) == "-11");
196
197 BEAST_EXPECT(test);
198 test = 0;
199 BEAST_EXPECT(!test);
200 BEAST_EXPECT(test.signum() == 0);
201 test = targetSame;
202 BEAST_EXPECT(test.signum() == 1);
203 BEAST_EXPECT(to_string(test) == "200");
204 }
205
206 void
208 {
209 testcase("mulRatio");
210
211 constexpr auto maxUInt32 = std::numeric_limits<std::uint32_t>::max();
212 constexpr auto maxXRP = std::numeric_limits<XRPAmount::value_type>::max();
213 constexpr auto minXRP = std::numeric_limits<XRPAmount::value_type>::min();
214
215 {
216 // multiply by a number that would overflow then divide by the same
217 // number, and check we didn't lose any value
218 XRPAmount big(maxXRP);
219 BEAST_EXPECT(big == mulRatio(big, maxUInt32, maxUInt32, true));
220 // rounding mode shouldn't matter as the result is exact
221 BEAST_EXPECT(big == mulRatio(big, maxUInt32, maxUInt32, false));
222
223 // multiply and divide by values that would overflow if done
224 // naively, and check that it gives the correct answer
225 big -= 0xf; // Subtract a little so it's divisible by 4
226 BEAST_EXPECT(mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3);
227 BEAST_EXPECT(mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3);
228 BEAST_EXPECT((big.value() * 3) / 4 != (big.value() / 4) * 3);
229 }
230
231 {
232 // Similar test as above, but for negative values
233 XRPAmount big(minXRP); // NOLINT(misc-const-correctness): const breaks overflow check
234 // at end of this scope
235 BEAST_EXPECT(big == mulRatio(big, maxUInt32, maxUInt32, true));
236 // rounding mode shouldn't matter as the result is exact
237 BEAST_EXPECT(big == mulRatio(big, maxUInt32, maxUInt32, false));
238
239 // multiply and divide by values that would overflow if done
240 // naively, and check that it gives the correct answer
241 BEAST_EXPECT(mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3);
242 BEAST_EXPECT(mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3);
243 BEAST_EXPECT((big.value() * 3) / 4 != (big.value() / 4) * 3);
244 }
245
246 {
247 // small amounts
248 XRPAmount const tiny(1);
249 // Round up should give the smallest allowable number
250 BEAST_EXPECT(tiny == mulRatio(tiny, 1, maxUInt32, true));
251 // rounding down should be zero
252 BEAST_EXPECT(beast::zero == mulRatio(tiny, 1, maxUInt32, false));
253 BEAST_EXPECT(beast::zero == mulRatio(tiny, maxUInt32 - 1, maxUInt32, false));
254
255 // tiny negative numbers
256 XRPAmount const tinyNeg(-1);
257 // Round up should give zero
258 BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, 1, maxUInt32, true));
259 BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, true));
260 // rounding down should be tiny
261 BEAST_EXPECT(tinyNeg == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, false));
262 }
263
264 { // rounding
265 {
266 XRPAmount const one(1);
267 auto const rup = mulRatio(one, maxUInt32 - 1, maxUInt32, true);
268 auto const rdown = mulRatio(one, maxUInt32 - 1, maxUInt32, false);
269 BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
270 }
271
272 {
273 XRPAmount const big(maxXRP);
274 auto const rup = mulRatio(big, maxUInt32 - 1, maxUInt32, true);
275 auto const rdown = mulRatio(big, maxUInt32 - 1, maxUInt32, false);
276 BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
277 }
278
279 {
280 XRPAmount const negOne(-1);
281 auto const rup = mulRatio(negOne, maxUInt32 - 1, maxUInt32, true);
282 auto const rdown = mulRatio(negOne, maxUInt32 - 1, maxUInt32, false);
283 BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
284 }
285 }
286
287 {
288 // division by zero
289 XRPAmount one(1);
290 except([&] { mulRatio(one, 1, 0, true); });
291 }
292
293 {
294 // overflow
295 XRPAmount big(maxXRP);
296 except([&] { mulRatio(big, 2, 1, true); });
297 }
298
299 {
300 // underflow
301 XRPAmount const bigNegative(minXRP + 10);
302 BEAST_EXPECT(mulRatio(bigNegative, 2, 1, true) == minXRP);
303 }
304 } // namespace xrpl
305
306 //--------------------------------------------------------------------------
307
308 void
309 run() override
310 {
311 testSigNum();
314 testAddSub();
315 testDecimal();
317 testMulRatio();
318 }
319};
320
321BEAST_DEFINE_TESTSUITE(XRPAmount, basics, xrpl);
322
323} // namespace xrpl
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
bool except(F &&f, String const &reason)
Definition suite.h:434
void run() override
Runs the suite.
constexpr value_type value() const
Returns the underlying value.
Definition XRPAmount.h:218
constexpr double decimalXRP() const
Definition XRPAmount.h:241
constexpr int signum() const noexcept
Return the sign of the amount.
Definition XRPAmount.h:150
T max(T... args)
T min(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
constexpr XRPAmount DROPS_PER_XRP
Number of drops per 1 XRP.
Definition XRPAmount.h:238