rippled
Loading...
Searching...
No Matches
base_uint_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2016 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/basics/Blob.h>
21#include <xrpl/basics/base_uint.h>
22#include <xrpl/basics/hardened_hash.h>
23#include <xrpl/beast/unit_test.h>
24#include <boost/endian/conversion.hpp>
25#include <complex>
26
27#include <type_traits>
28
29namespace ripple {
30namespace test {
31
32// a non-hashing Hasher that just copies the bytes.
33// Used to test hash_append in base_uint
34template <std::size_t Bits>
35struct nonhash
36{
37 static constexpr auto const endian = boost::endian::order::big;
38 static constexpr std::size_t WIDTH = Bits / 8;
39
41
42 nonhash() = default;
43
44 void
45 operator()(void const* key, std::size_t len) noexcept
46 {
47 assert(len == WIDTH);
48 memcpy(data_.data(), key, len);
49 }
50
51 explicit
52 operator std::size_t() noexcept
53 {
54 return WIDTH;
55 }
56};
57
59{
63
64 void
66 {
67 {
68 static constexpr std::
69 array<std::pair<std::string_view, std::string_view>, 6>
70 test_args{
71 {{"0000000000000000", "0000000000000001"},
72 {"0000000000000000", "ffffffffffffffff"},
73 {"1234567812345678", "2345678923456789"},
74 {"8000000000000000", "8000000000000001"},
75 {"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"},
76 {"fffffffffffffffe", "ffffffffffffffff"}}};
77
78 for (auto const& arg : test_args)
79 {
80 ripple::base_uint<64> const u{arg.first}, v{arg.second};
81 BEAST_EXPECT(u < v);
82 BEAST_EXPECT(u <= v);
83 BEAST_EXPECT(u != v);
84 BEAST_EXPECT(!(u == v));
85 BEAST_EXPECT(!(u > v));
86 BEAST_EXPECT(!(u >= v));
87 BEAST_EXPECT(!(v < u));
88 BEAST_EXPECT(!(v <= u));
89 BEAST_EXPECT(v != u);
90 BEAST_EXPECT(!(v == u));
91 BEAST_EXPECT(v > u);
92 BEAST_EXPECT(v >= u);
93 BEAST_EXPECT(u == u);
94 BEAST_EXPECT(v == v);
95 }
96 }
97
98 {
99 static constexpr std::array<
101 6>
102 test_args{{
103 {"000000000000000000000000", "000000000000000000000001"},
104 {"000000000000000000000000", "ffffffffffffffffffffffff"},
105 {"0123456789ab0123456789ab", "123456789abc123456789abc"},
106 {"555555555555555555555555", "55555555555a555555555555"},
107 {"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"},
108 {"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"},
109 }};
110
111 for (auto const& arg : test_args)
112 {
113 ripple::base_uint<96> const u{arg.first}, v{arg.second};
114 BEAST_EXPECT(u < v);
115 BEAST_EXPECT(u <= v);
116 BEAST_EXPECT(u != v);
117 BEAST_EXPECT(!(u == v));
118 BEAST_EXPECT(!(u > v));
119 BEAST_EXPECT(!(u >= v));
120 BEAST_EXPECT(!(v < u));
121 BEAST_EXPECT(!(v <= u));
122 BEAST_EXPECT(v != u);
123 BEAST_EXPECT(!(v == u));
124 BEAST_EXPECT(v > u);
125 BEAST_EXPECT(v >= u);
126 BEAST_EXPECT(u == u);
127 BEAST_EXPECT(v == v);
128 }
129 }
130 }
131
132 void
133 run() override
134 {
135 testcase("base_uint: general purpose tests");
136
137 static_assert(
139 static_assert(
141
143
144 // used to verify set insertion (hashing required)
146
147 Blob raw{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
148 BEAST_EXPECT(test96::bytes == raw.size());
149
150 test96 u{raw};
151 uset.insert(u);
152 BEAST_EXPECT(raw.size() == u.size());
153 BEAST_EXPECT(to_string(u) == "0102030405060708090A0B0C");
154 BEAST_EXPECT(to_short_string(u) == "01020304...");
155 BEAST_EXPECT(*u.data() == 1);
156 BEAST_EXPECT(u.signum() == 1);
157 BEAST_EXPECT(!!u);
158 BEAST_EXPECT(!u.isZero());
159 BEAST_EXPECT(u.isNonZero());
160 unsigned char t = 0;
161 for (auto& d : u)
162 {
163 BEAST_EXPECT(d == ++t);
164 }
165
166 // Test hash_append by "hashing" with a no-op hasher (h)
167 // and then extracting the bytes that were written during hashing
168 // back into another base_uint (w) for comparison with the original
169 nonhash<96> h;
170 hash_append(h, u);
172 BEAST_EXPECT(w == u);
173
174 test96 v{~u};
175 uset.insert(v);
176 BEAST_EXPECT(to_string(v) == "FEFDFCFBFAF9F8F7F6F5F4F3");
177 BEAST_EXPECT(to_short_string(v) == "FEFDFCFB...");
178 BEAST_EXPECT(*v.data() == 0xfe);
179 BEAST_EXPECT(v.signum() == 1);
180 BEAST_EXPECT(!!v);
181 BEAST_EXPECT(!v.isZero());
182 BEAST_EXPECT(v.isNonZero());
183 t = 0xff;
184 for (auto& d : v)
185 {
186 BEAST_EXPECT(d == --t);
187 }
188
189 BEAST_EXPECT(u < v);
190 BEAST_EXPECT(v > u);
191
192 v = u;
193 BEAST_EXPECT(v == u);
194
195 test96 z{beast::zero};
196 uset.insert(z);
197 BEAST_EXPECT(to_string(z) == "000000000000000000000000");
198 BEAST_EXPECT(to_short_string(z) == "00000000...");
199 BEAST_EXPECT(*z.data() == 0);
200 BEAST_EXPECT(*z.begin() == 0);
201 BEAST_EXPECT(*std::prev(z.end(), 1) == 0);
202 BEAST_EXPECT(z.signum() == 0);
203 BEAST_EXPECT(!z);
204 BEAST_EXPECT(z.isZero());
205 BEAST_EXPECT(!z.isNonZero());
206 for (auto& d : z)
207 {
208 BEAST_EXPECT(d == 0);
209 }
210
211 test96 n{z};
212 n++;
213 BEAST_EXPECT(n == test96(1));
214 n--;
215 BEAST_EXPECT(n == beast::zero);
216 BEAST_EXPECT(n == z);
217 n--;
218 BEAST_EXPECT(to_string(n) == "FFFFFFFFFFFFFFFFFFFFFFFF");
219 BEAST_EXPECT(to_short_string(n) == "FFFFFFFF...");
220 n = beast::zero;
221 BEAST_EXPECT(n == z);
222
223 test96 zp1{z};
224 zp1++;
225 test96 zm1{z};
226 zm1--;
227 test96 x{zm1 ^ zp1};
228 uset.insert(x);
229 BEAST_EXPECTS(to_string(x) == "FFFFFFFFFFFFFFFFFFFFFFFE", to_string(x));
230 BEAST_EXPECTS(to_short_string(x) == "FFFFFFFF...", to_short_string(x));
231
232 BEAST_EXPECT(uset.size() == 4);
233
234 test96 tmp;
235 BEAST_EXPECT(tmp.parseHex(to_string(u)));
236 BEAST_EXPECT(tmp == u);
237 tmp = z;
238
239 // fails with extra char
240 BEAST_EXPECT(!tmp.parseHex("A" + to_string(u)));
241 tmp = z;
242
243 // fails with extra char at end
244 BEAST_EXPECT(!tmp.parseHex(to_string(u) + "A"));
245
246 // fails with a non-hex character at some point in the string:
247 tmp = z;
248
249 for (std::size_t i = 0; i != 24; ++i)
250 {
251 std::string x = to_string(z);
252 x[i] = ('G' + (i % 10));
253 BEAST_EXPECT(!tmp.parseHex(x));
254 }
255
256 // Walking 1s:
257 for (std::size_t i = 0; i != 24; ++i)
258 {
259 std::string s1 = "000000000000000000000000";
260 s1[i] = '1';
261
262 BEAST_EXPECT(tmp.parseHex(s1));
263 BEAST_EXPECT(to_string(tmp) == s1);
264 }
265
266 // Walking 0s:
267 for (std::size_t i = 0; i != 24; ++i)
268 {
269 std::string s1 = "111111111111111111111111";
270 s1[i] = '0';
271
272 BEAST_EXPECT(tmp.parseHex(s1));
273 BEAST_EXPECT(to_string(tmp) == s1);
274 }
275
276 // Constexpr constructors
277 {
278 static_assert(test96{}.signum() == 0);
279 static_assert(test96("0").signum() == 0);
280 static_assert(test96("000000000000000000000000").signum() == 0);
281 static_assert(test96("000000000000000000000001").signum() == 1);
282 static_assert(test96("800000000000000000000000").signum() == 1);
283
284// Everything within the #if should fail during compilation.
285#if 0
286 // Too few characters
287 static_assert(test96("00000000000000000000000").signum() == 0);
288
289 // Too many characters
290 static_assert(test96("0000000000000000000000000").signum() == 0);
291
292 // Non-hex characters
293 static_assert(test96("00000000000000000000000 ").signum() == 1);
294 static_assert(test96("00000000000000000000000/").signum() == 1);
295 static_assert(test96("00000000000000000000000:").signum() == 1);
296 static_assert(test96("00000000000000000000000@").signum() == 1);
297 static_assert(test96("00000000000000000000000G").signum() == 1);
298 static_assert(test96("00000000000000000000000`").signum() == 1);
299 static_assert(test96("00000000000000000000000g").signum() == 1);
300 static_assert(test96("00000000000000000000000~").signum() == 1);
301#endif // 0
302
303 // Using the constexpr constructor in a non-constexpr context
304 // with an error in the parsing throws an exception.
305 {
306 // Invalid length for string.
307 bool caught = false;
308 try
309 {
310 // Try to prevent constant evaluation.
311 std::vector<char> str(23, '7');
312 std::string_view sView(str.data(), str.size());
313 [[maybe_unused]] test96 t96(sView);
314 }
315 catch (std::invalid_argument const& e)
316 {
317 BEAST_EXPECT(
318 e.what() ==
319 std::string("invalid length for hex string"));
320 caught = true;
321 }
322 BEAST_EXPECT(caught);
323 }
324 {
325 // Invalid character in string.
326 bool caught = false;
327 try
328 {
329 // Try to prevent constant evaluation.
330 std::vector<char> str(23, '7');
331 str.push_back('G');
332 std::string_view sView(str.data(), str.size());
333 [[maybe_unused]] test96 t96(sView);
334 }
335 catch (std::range_error const& e)
336 {
337 BEAST_EXPECT(
338 e.what() == std::string("invalid hex character"));
339 caught = true;
340 }
341 BEAST_EXPECT(caught);
342 }
343
344 // Verify that constexpr base_uints interpret a string the same
345 // way parseHex() does.
346 struct StrBaseUint
347 {
348 char const* const str;
349 test96 tst;
350
351 constexpr StrBaseUint(char const* s) : str(s), tst(s)
352 {
353 }
354 };
355 constexpr StrBaseUint testCases[] = {
356 "000000000000000000000000",
357 "000000000000000000000001",
358 "fedcba9876543210ABCDEF91",
359 "19FEDCBA0123456789abcdef",
360 "800000000000000000000000",
361 "fFfFfFfFfFfFfFfFfFfFfFfF"};
362
363 for (StrBaseUint const& t : testCases)
364 {
365 test96 t96;
366 BEAST_EXPECT(t96.parseHex(t.str));
367 BEAST_EXPECT(t96 == t.tst);
368 }
369 }
370 }
371};
372
373BEAST_DEFINE_TESTSUITE(base_uint, ripple_basics, ripple);
374
375} // namespace test
376} // namespace ripple
T begin(T... args)
A testsuite class.
Definition: suite.h:53
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
std::string const & arg() const
Return the argument associated with the runner.
Definition: suite.h:286
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:85
static std::size_t constexpr bytes
Definition: base_uint.h:107
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:502
constexpr int signum() const
Definition: base_uint.h:333
T data(T... args)
T end(T... args)
T insert(T... args)
void hash_append(Hasher &h, Account const &v) noexcept
Definition: Account.h:156
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string to_short_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:636
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
T prev(T... args)
T push_back(T... args)
T size(T... args)
void run() override
Runs the suite.
static constexpr auto const endian
static constexpr std::size_t WIDTH
void operator()(void const *key, std::size_t len) noexcept
std::array< std::uint8_t, WIDTH > data_