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