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