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