rippled
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 <ripple/basics/XRPAmount.h>
21 #include <ripple/beast/unit_test.h>
22 
23 namespace ripple {
24 
25 class XRPAmount_test : public beast::unit_test::suite
26 {
27 public:
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  {XRPAmount one(1);
288  auto const rup = mulRatio(one, maxUInt32 - 1, maxUInt32, true);
289  auto const rdown = mulRatio(one, maxUInt32 - 1, maxUInt32, false);
290  BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
291  }
292 
293  {
294  XRPAmount big(maxXRP);
295  auto const rup = mulRatio(big, maxUInt32 - 1, maxUInt32, true);
296  auto const rdown = mulRatio(big, maxUInt32 - 1, maxUInt32, false);
297  BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
298  }
299 
300  {
301  XRPAmount negOne(-1);
302  auto const rup = mulRatio(negOne, maxUInt32 - 1, maxUInt32, true);
303  auto const rdown = mulRatio(negOne, maxUInt32 - 1, maxUInt32, false);
304  BEAST_EXPECT(rup.drops() - rdown.drops() == 1);
305  }
306 }
307 
308 {
309  // division by zero
310  XRPAmount one(1);
311  except([&] { mulRatio(one, 1, 0, true); });
312 }
313 
314 {
315  // overflow
316  XRPAmount big(maxXRP);
317  except([&] { mulRatio(big, 2, 1, true); });
318 }
319 
320 {
321  // underflow
322  XRPAmount bigNegative(minXRP + 10);
323  BEAST_EXPECT(mulRatio(bigNegative, 2, 1, true) == minXRP);
324 }
325 } // namespace ripple
326 
327 //--------------------------------------------------------------------------
328 
329 void
330 run() override
331 {
332  testSigNum();
333  testBeastZero();
334  testComparisons();
335  testAddSub();
336  testDecimal();
337  testFunctions();
338  testMulRatio();
339 }
340 }
341 ;
342 
344 
345 } // ripple
ripple::mulRatio
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
Definition: IOUAmount.cpp:182
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::XRPAmount::value
constexpr value_type value() const
Returns the underlying value.
Definition: XRPAmount.h:230
ripple::XRPAmount_test::testMulRatio
void testMulRatio()
Definition: XRPAmount_test.cpp:220
ripple::XRPAmount::decimalXRP
constexpr double decimalXRP() const
Definition: XRPAmount.h:253
ripple::XRPAmount_test::testBeastZero
void testBeastZero()
Definition: XRPAmount_test.cpp:47
std::int64_t
std::numeric_limits::min
T min(T... args)
ripple::DROPS_PER_XRP
constexpr XRPAmount DROPS_PER_XRP
Number of drops per 1 XRP.
Definition: XRPAmount.h:250
ripple::XRPAmount_test::testSigNum
void testSigNum()
Definition: XRPAmount_test.cpp:29
ripple::XRPAmount_test::testDecimal
void testDecimal()
Definition: XRPAmount_test.cpp:118
ripple::XRPAmount_test
Definition: XRPAmount_test.cpp:25
ripple::one
constexpr Number one
Definition: Number.cpp:169
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::XRPAmount_test::testFunctions
void testFunctions()
Definition: XRPAmount_test.cpp:137
protocol
Definition: ValidatorList.h:38
ripple::XRPAmount_test::testComparisons
void testComparisons()
Definition: XRPAmount_test.cpp:74
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
std::numeric_limits::max
T max(T... args)
ripple::XRPAmount_test::testAddSub
void testAddSub()
Definition: XRPAmount_test.cpp:97
ripple::XRPAmount::signum
constexpr int signum() const noexcept
Return the sign of the amount.
Definition: XRPAmount.h:165
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::XRPAmount_test::run
void run() override
Definition: XRPAmount_test.cpp:330