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