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