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