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