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