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(*u.data() == 1);
155 BEAST_EXPECT(u.signum() == 1);
156 BEAST_EXPECT(!!u);
157 BEAST_EXPECT(!u.isZero());
158 BEAST_EXPECT(u.isNonZero());
159 unsigned char t = 0;
160 for (auto& d : u)
161 {
162 BEAST_EXPECT(d == ++t);
163 }
164
165 // Test hash_append by "hashing" with a no-op hasher (h)
166 // and then extracting the bytes that were written during hashing
167 // back into another base_uint (w) for comparison with the original
168 nonhash<96> h;
169 hash_append(h, u);
171 BEAST_EXPECT(w == u);
172
173 test96 v{~u};
174 uset.insert(v);
175 BEAST_EXPECT(to_string(v) == "FEFDFCFBFAF9F8F7F6F5F4F3");
176 BEAST_EXPECT(*v.data() == 0xfe);
177 BEAST_EXPECT(v.signum() == 1);
178 BEAST_EXPECT(!!v);
179 BEAST_EXPECT(!v.isZero());
180 BEAST_EXPECT(v.isNonZero());
181 t = 0xff;
182 for (auto& d : v)
183 {
184 BEAST_EXPECT(d == --t);
185 }
186
187 BEAST_EXPECT(u < v);
188 BEAST_EXPECT(v > u);
189
190 v = u;
191 BEAST_EXPECT(v == u);
192
193 test96 z{beast::zero};
194 uset.insert(z);
195 BEAST_EXPECT(to_string(z) == "000000000000000000000000");
196 BEAST_EXPECT(*z.data() == 0);
197 BEAST_EXPECT(*z.begin() == 0);
198 BEAST_EXPECT(*std::prev(z.end(), 1) == 0);
199 BEAST_EXPECT(z.signum() == 0);
200 BEAST_EXPECT(!z);
201 BEAST_EXPECT(z.isZero());
202 BEAST_EXPECT(!z.isNonZero());
203 for (auto& d : z)
204 {
205 BEAST_EXPECT(d == 0);
206 }
207
208 test96 n{z};
209 n++;
210 BEAST_EXPECT(n == test96(1));
211 n--;
212 BEAST_EXPECT(n == beast::zero);
213 BEAST_EXPECT(n == z);
214 n--;
215 BEAST_EXPECT(to_string(n) == "FFFFFFFFFFFFFFFFFFFFFFFF");
216 n = beast::zero;
217 BEAST_EXPECT(n == z);
218
219 test96 zp1{z};
220 zp1++;
221 test96 zm1{z};
222 zm1--;
223 test96 x{zm1 ^ zp1};
224 uset.insert(x);
225 BEAST_EXPECTS(to_string(x) == "FFFFFFFFFFFFFFFFFFFFFFFE", to_string(x));
226
227 BEAST_EXPECT(uset.size() == 4);
228
229 test96 tmp;
230 BEAST_EXPECT(tmp.parseHex(to_string(u)));
231 BEAST_EXPECT(tmp == u);
232 tmp = z;
233
234 // fails with extra char
235 BEAST_EXPECT(!tmp.parseHex("A" + to_string(u)));
236 tmp = z;
237
238 // fails with extra char at end
239 BEAST_EXPECT(!tmp.parseHex(to_string(u) + "A"));
240
241 // fails with a non-hex character at some point in the string:
242 tmp = z;
243
244 for (std::size_t i = 0; i != 24; ++i)
245 {
246 std::string x = to_string(z);
247 x[i] = ('G' + (i % 10));
248 BEAST_EXPECT(!tmp.parseHex(x));
249 }
250
251 // Walking 1s:
252 for (std::size_t i = 0; i != 24; ++i)
253 {
254 std::string s1 = "000000000000000000000000";
255 s1[i] = '1';
256
257 BEAST_EXPECT(tmp.parseHex(s1));
258 BEAST_EXPECT(to_string(tmp) == s1);
259 }
260
261 // Walking 0s:
262 for (std::size_t i = 0; i != 24; ++i)
263 {
264 std::string s1 = "111111111111111111111111";
265 s1[i] = '0';
266
267 BEAST_EXPECT(tmp.parseHex(s1));
268 BEAST_EXPECT(to_string(tmp) == s1);
269 }
270
271 // Constexpr constructors
272 {
273 static_assert(test96{}.signum() == 0);
274 static_assert(test96("0").signum() == 0);
275 static_assert(test96("000000000000000000000000").signum() == 0);
276 static_assert(test96("000000000000000000000001").signum() == 1);
277 static_assert(test96("800000000000000000000000").signum() == 1);
278
279// Everything within the #if should fail during compilation.
280#if 0
281 // Too few characters
282 static_assert(test96("00000000000000000000000").signum() == 0);
283
284 // Too many characters
285 static_assert(test96("0000000000000000000000000").signum() == 0);
286
287 // Non-hex characters
288 static_assert(test96("00000000000000000000000 ").signum() == 1);
289 static_assert(test96("00000000000000000000000/").signum() == 1);
290 static_assert(test96("00000000000000000000000:").signum() == 1);
291 static_assert(test96("00000000000000000000000@").signum() == 1);
292 static_assert(test96("00000000000000000000000G").signum() == 1);
293 static_assert(test96("00000000000000000000000`").signum() == 1);
294 static_assert(test96("00000000000000000000000g").signum() == 1);
295 static_assert(test96("00000000000000000000000~").signum() == 1);
296#endif // 0
297
298 // Using the constexpr constructor in a non-constexpr context
299 // with an error in the parsing throws an exception.
300 {
301 // Invalid length for string.
302 bool caught = false;
303 try
304 {
305 // Try to prevent constant evaluation.
306 std::vector<char> str(23, '7');
307 std::string_view sView(str.data(), str.size());
308 [[maybe_unused]] test96 t96(sView);
309 }
310 catch (std::invalid_argument const& e)
311 {
312 BEAST_EXPECT(
313 e.what() ==
314 std::string("invalid length for hex string"));
315 caught = true;
316 }
317 BEAST_EXPECT(caught);
318 }
319 {
320 // Invalid character in string.
321 bool caught = false;
322 try
323 {
324 // Try to prevent constant evaluation.
325 std::vector<char> str(23, '7');
326 str.push_back('G');
327 std::string_view sView(str.data(), str.size());
328 [[maybe_unused]] test96 t96(sView);
329 }
330 catch (std::range_error const& e)
331 {
332 BEAST_EXPECT(
333 e.what() == std::string("invalid hex character"));
334 caught = true;
335 }
336 BEAST_EXPECT(caught);
337 }
338
339 // Verify that constexpr base_uints interpret a string the same
340 // way parseHex() does.
341 struct StrBaseUint
342 {
343 char const* const str;
344 test96 tst;
345
346 constexpr StrBaseUint(char const* s) : str(s), tst(s)
347 {
348 }
349 };
350 constexpr StrBaseUint testCases[] = {
351 "000000000000000000000000",
352 "000000000000000000000001",
353 "fedcba9876543210ABCDEF91",
354 "19FEDCBA0123456789abcdef",
355 "800000000000000000000000",
356 "fFfFfFfFfFfFfFfFfFfFfFfF"};
357
358 for (StrBaseUint const& t : testCases)
359 {
360 test96 t96;
361 BEAST_EXPECT(t96.parseHex(t.str));
362 BEAST_EXPECT(t96 == t.tst);
363 }
364 }
365 }
366};
367
368BEAST_DEFINE_TESTSUITE(base_uint, ripple_basics, ripple);
369
370} // namespace test
371} // 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_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_