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