rippled
Loading...
Searching...
No Matches
XRPAmount_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/beast/unit_test.h>
21#include <xrpl/protocol/XRPAmount.h>
22
23namespace ripple {
24
26{
27public:
28 void
30 {
31 testcase("signum");
32
33 for (auto i : {-1, 0, 1})
34 {
35 XRPAmount const x(i);
36
37 if (i < 0)
38 BEAST_EXPECT(x.signum() < 0);
39 else if (i > 0)
40 BEAST_EXPECT(x.signum() > 0);
41 else
42 BEAST_EXPECT(x.signum() == 0);
43 }
44 }
45
46 void
48 {
49 testcase("beast::Zero Comparisons");
50
51 using beast::zero;
52
53 for (auto i : {-1, 0, 1})
54 {
55 XRPAmount const x(i);
56
57 BEAST_EXPECT((i == 0) == (x == zero));
58 BEAST_EXPECT((i != 0) == (x != zero));
59 BEAST_EXPECT((i < 0) == (x < zero));
60 BEAST_EXPECT((i > 0) == (x > zero));
61 BEAST_EXPECT((i <= 0) == (x <= zero));
62 BEAST_EXPECT((i >= 0) == (x >= zero));
63
64 BEAST_EXPECT((0 == i) == (zero == x));
65 BEAST_EXPECT((0 != i) == (zero != x));
66 BEAST_EXPECT((0 < i) == (zero < x));
67 BEAST_EXPECT((0 > i) == (zero > x));
68 BEAST_EXPECT((0 <= i) == (zero <= x));
69 BEAST_EXPECT((0 >= i) == (zero >= x));
70 }
71 }
72
73 void
75 {
76 testcase("XRP Comparisons");
77
78 for (auto i : {-1, 0, 1})
79 {
80 XRPAmount const x(i);
81
82 for (auto j : {-1, 0, 1})
83 {
84 XRPAmount const y(j);
85
86 BEAST_EXPECT((i == j) == (x == y));
87 BEAST_EXPECT((i != j) == (x != y));
88 BEAST_EXPECT((i < j) == (x < y));
89 BEAST_EXPECT((i > j) == (x > y));
90 BEAST_EXPECT((i <= j) == (x <= y));
91 BEAST_EXPECT((i >= j) == (x >= y));
92 }
93 }
94 }
95
96 void
98 {
99 testcase("Addition & Subtraction");
100
101 for (auto i : {-1, 0, 1})
102 {
103 XRPAmount const x(i);
104
105 for (auto j : {-1, 0, 1})
106 {
107 XRPAmount const y(j);
108
109 BEAST_EXPECT(XRPAmount(i + j) == (x + y));
110 BEAST_EXPECT(XRPAmount(i - j) == (x - y));
111
112 BEAST_EXPECT((x + y) == (y + x)); // addition is commutative
113 }
114 }
115 }
116
117 void
119 {
120 // Tautology
121 BEAST_EXPECT(DROPS_PER_XRP.decimalXRP() == 1);
122
123 XRPAmount test{1};
124 BEAST_EXPECT(test.decimalXRP() == 0.000001);
125
126 test = -test;
127 BEAST_EXPECT(test.decimalXRP() == -0.000001);
128
129 test = 100'000'000;
130 BEAST_EXPECT(test.decimalXRP() == 100);
131
132 test = -test;
133 BEAST_EXPECT(test.decimalXRP() == -100);
134 }
135
136 void
138 {
139 // Explicitly test every defined function for the XRPAmount class
140 // since some of them are templated, but not used anywhere else.
141 auto make = [&](auto x) -> XRPAmount { return XRPAmount{x}; };
142
143 XRPAmount defaulted;
144 (void)defaulted;
145 XRPAmount test{0};
146 BEAST_EXPECT(test.drops() == 0);
147
148 test = make(beast::zero);
149 BEAST_EXPECT(test.drops() == 0);
150
151 test = beast::zero;
152 BEAST_EXPECT(test.drops() == 0);
153
154 test = make(100);
155 BEAST_EXPECT(test.drops() == 100);
156
157 test = make(100u);
158 BEAST_EXPECT(test.drops() == 100);
159
160 XRPAmount const targetSame{200u};
161 test = make(targetSame);
162 BEAST_EXPECT(test.drops() == 200);
163 BEAST_EXPECT(test == targetSame);
164 BEAST_EXPECT(test < XRPAmount{1000});
165 BEAST_EXPECT(test > XRPAmount{100});
166
167 test = std::int64_t(200);
168 BEAST_EXPECT(test.drops() == 200);
169 test = std::uint32_t(300);
170 BEAST_EXPECT(test.drops() == 300);
171
172 test = targetSame;
173 BEAST_EXPECT(test.drops() == 200);
174 auto testOther = test.dropsAs<std::uint32_t>();
175 BEAST_EXPECT(testOther);
176 BEAST_EXPECT(*testOther == 200);
178 testOther = test.dropsAs<std::uint32_t>();
179 BEAST_EXPECT(!testOther);
180 test = -1;
181 testOther = test.dropsAs<std::uint32_t>();
182 BEAST_EXPECT(!testOther);
183
184 test = targetSame * 2;
185 BEAST_EXPECT(test.drops() == 400);
186 test = 3 * targetSame;
187 BEAST_EXPECT(test.drops() == 600);
188 test = 20;
189 BEAST_EXPECT(test.drops() == 20);
190
191 test += targetSame;
192 BEAST_EXPECT(test.drops() == 220);
193
194 test -= targetSame;
195 BEAST_EXPECT(test.drops() == 20);
196
197 test *= 5;
198 BEAST_EXPECT(test.drops() == 100);
199 test = 50;
200 BEAST_EXPECT(test.drops() == 50);
201 test -= 39;
202 BEAST_EXPECT(test.drops() == 11);
203
204 // legal with signed
205 test = -test;
206 BEAST_EXPECT(test.drops() == -11);
207 BEAST_EXPECT(test.signum() == -1);
208 BEAST_EXPECT(to_string(test) == "-11");
209
210 BEAST_EXPECT(test);
211 test = 0;
212 BEAST_EXPECT(!test);
213 BEAST_EXPECT(test.signum() == 0);
214 test = targetSame;
215 BEAST_EXPECT(test.signum() == 1);
216 BEAST_EXPECT(to_string(test) == "200");
217 }
218
219 void
221 {
222 testcase("mulRatio");
223
224 constexpr auto maxUInt32 = std::numeric_limits<std::uint32_t>::max();
225 constexpr auto maxXRP =
227 constexpr auto minXRP =
229
230 {
231 // multiply by a number that would overflow then divide by the same
232 // number, and check we didn't lose any value
233 XRPAmount big(maxXRP);
234 BEAST_EXPECT(big == mulRatio(big, maxUInt32, maxUInt32, true));
235 // rounding mode shouldn't matter as the result is exact
236 BEAST_EXPECT(big == mulRatio(big, maxUInt32, maxUInt32, false));
237
238 // multiply and divide by values that would overflow if done
239 // naively, and check that it gives the correct answer
240 big -= 0xf; // Subtract a little so it's divisable by 4
241 BEAST_EXPECT(
242 mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3);
243 BEAST_EXPECT(
244 mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3);
245 BEAST_EXPECT((big.value() * 3) / 4 != (big.value() / 4) * 3);
246 }
247
248 {
249 // Similar test as above, but for negative values
250 XRPAmount big(minXRP);
251 BEAST_EXPECT(big == mulRatio(big, maxUInt32, maxUInt32, true));
252 // rounding mode shouldn't matter as the result is exact
253 BEAST_EXPECT(big == mulRatio(big, maxUInt32, maxUInt32, false));
254
255 // multiply and divide by values that would overflow if done
256 // naively, and check that it gives the correct answer
257 BEAST_EXPECT(
258 mulRatio(big, 3, 4, false).value() == (big.value() / 4) * 3);
259 BEAST_EXPECT(
260 mulRatio(big, 3, 4, true).value() == (big.value() / 4) * 3);
261 BEAST_EXPECT((big.value() * 3) / 4 != (big.value() / 4) * 3);
262 }
263
264 {
265 // small amounts
266 XRPAmount tiny(1);
267 // Round up should give the smallest allowable number
268 BEAST_EXPECT(tiny == mulRatio(tiny, 1, maxUInt32, true));
269 // rounding down should be zero
270 BEAST_EXPECT(beast::zero == mulRatio(tiny, 1, maxUInt32, false));
271 BEAST_EXPECT(
272 beast::zero == mulRatio(tiny, maxUInt32 - 1, maxUInt32, false));
273
274 // tiny negative numbers
275 XRPAmount tinyNeg(-1);
276 // Round up should give zero
277 BEAST_EXPECT(beast::zero == mulRatio(tinyNeg, 1, maxUInt32, true));
278 BEAST_EXPECT(
279 beast::zero ==
280 mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, true));
281 // rounding down should be tiny
282 BEAST_EXPECT(
283 tinyNeg == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, false));
284 }
285
286 { // rounding
287 {
288 XRPAmount one(1);
289 auto const rup = mulRatio(one, maxUInt32 - 1, maxUInt32, true);
290 auto const rdown =
291 mulRatio(one, maxUInt32 - 1, maxUInt32, false);
292 BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
293 }
294
295 {
296 XRPAmount big(maxXRP);
297 auto const rup = mulRatio(big, maxUInt32 - 1, maxUInt32, true);
298 auto const rdown =
299 mulRatio(big, maxUInt32 - 1, maxUInt32, false);
300 BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
301 }
302
303 {
304 XRPAmount negOne(-1);
305 auto const rup =
306 mulRatio(negOne, maxUInt32 - 1, maxUInt32, true);
307 auto const rdown =
308 mulRatio(negOne, maxUInt32 - 1, maxUInt32, false);
309 BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
310 }
311 }
312
313 {
314 // division by zero
315 XRPAmount one(1);
316 except([&] { mulRatio(one, 1, 0, true); });
317 }
318
319 {
320 // overflow
321 XRPAmount big(maxXRP);
322 except([&] { mulRatio(big, 2, 1, true); });
323 }
324
325 {
326 // underflow
327 XRPAmount bigNegative(minXRP + 10);
328 BEAST_EXPECT(mulRatio(bigNegative, 2, 1, true) == minXRP);
329 }
330 } // namespace ripple
331
332 //--------------------------------------------------------------------------
333
334 void
335 run() override
336 {
337 testSigNum();
340 testAddSub();
341 testDecimal();
343 testMulRatio();
344 }
345};
346
347BEAST_DEFINE_TESTSUITE(XRPAmount, basics, ripple);
348
349} // namespace ripple
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
bool except(F &&f, String const &reason)
Definition suite.h:448
void run() override
Runs the suite.
constexpr value_type value() const
Returns the underlying value.
Definition XRPAmount.h:239
constexpr int signum() const noexcept
Return the sign of the amount.
Definition XRPAmount.h:170
constexpr double decimalXRP() const
Definition XRPAmount.h:262
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:25
constexpr Number one
Definition Number.cpp:175
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
constexpr XRPAmount DROPS_PER_XRP
Number of drops per 1 XRP.
Definition XRPAmount.h:259