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