rippled
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 <ripple/basics/Blob.h>
21 #include <ripple/basics/base_uint.h>
22 #include <ripple/basics/hardened_hash.h>
23 #include <ripple/beast/unit_test.h>
24 #include <boost/endian/conversion.hpp>
25 #include <complex>
26 
27 #include <type_traits>
28 
29 namespace ripple {
30 namespace test {
31 
32 // a non-hashing Hasher that just copies the bytes.
33 // Used to test hash_append in base_uint
34 template <std::size_t Bits>
35 struct nonhash
36 {
37  static constexpr auto const endian = boost::endian::order::big;
38  static constexpr std::size_t WIDTH = Bits / 8;
39 
41 
42  nonhash() = default;
43 
44  void
45  operator()(void const* key, std::size_t len) noexcept
46  {
47  assert(len == WIDTH);
48  memcpy(data_.data(), key, len);
49  }
50 
51  explicit operator std::size_t() noexcept
52  {
53  return WIDTH;
54  }
55 };
56 
57 struct base_uint_test : beast::unit_test::suite
58 {
61  static_assert(std::is_copy_assignable<test96>::value, "");
62 
63  void
64  run() override
65  {
66  testcase("base_uint: general purpose tests");
67 
68  static_assert(
70  static_assert(
72  // used to verify set insertion (hashing required)
74 
75  Blob raw{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
76  BEAST_EXPECT(test96::bytes == raw.size());
77 
78  test96 u{raw};
79  uset.insert(u);
80  BEAST_EXPECT(raw.size() == u.size());
81  BEAST_EXPECT(to_string(u) == "0102030405060708090A0B0C");
82  BEAST_EXPECT(*u.data() == 1);
83  BEAST_EXPECT(u.signum() == 1);
84  BEAST_EXPECT(!!u);
85  BEAST_EXPECT(!u.isZero());
86  BEAST_EXPECT(u.isNonZero());
87  unsigned char t = 0;
88  for (auto& d : u)
89  {
90  BEAST_EXPECT(d == ++t);
91  }
92 
93  // Test hash_append by "hashing" with a no-op hasher (h)
94  // and then extracting the bytes that were written during hashing
95  // back into another base_uint (w) for comparison with the original
96  nonhash<96> h;
97  hash_append(h, u);
99  BEAST_EXPECT(w == u);
100 
101  test96 v{~u};
102  uset.insert(v);
103  BEAST_EXPECT(to_string(v) == "FEFDFCFBFAF9F8F7F6F5F4F3");
104  BEAST_EXPECT(*v.data() == 0xfe);
105  BEAST_EXPECT(v.signum() == 1);
106  BEAST_EXPECT(!!v);
107  BEAST_EXPECT(!v.isZero());
108  BEAST_EXPECT(v.isNonZero());
109  t = 0xff;
110  for (auto& d : v)
111  {
112  BEAST_EXPECT(d == --t);
113  }
114 
115  BEAST_EXPECT(compare(u, v) < 0);
116  BEAST_EXPECT(compare(v, u) > 0);
117 
118  v = u;
119  BEAST_EXPECT(v == u);
120 
121  test96 z{beast::zero};
122  uset.insert(z);
123  BEAST_EXPECT(to_string(z) == "000000000000000000000000");
124  BEAST_EXPECT(*z.data() == 0);
125  BEAST_EXPECT(*z.begin() == 0);
126  BEAST_EXPECT(*std::prev(z.end(), 1) == 0);
127  BEAST_EXPECT(z.signum() == 0);
128  BEAST_EXPECT(!z);
129  BEAST_EXPECT(z.isZero());
130  BEAST_EXPECT(!z.isNonZero());
131  for (auto& d : z)
132  {
133  BEAST_EXPECT(d == 0);
134  }
135 
136  test96 n{z};
137  n++;
138  BEAST_EXPECT(n == test96(1));
139  n--;
140  BEAST_EXPECT(n == beast::zero);
141  BEAST_EXPECT(n == z);
142  n--;
143  BEAST_EXPECT(to_string(n) == "FFFFFFFFFFFFFFFFFFFFFFFF");
144  n = beast::zero;
145  BEAST_EXPECT(n == z);
146 
147  test96 zp1{z};
148  zp1++;
149  test96 zm1{z};
150  zm1--;
151  test96 x{zm1 ^ zp1};
152  uset.insert(x);
153  BEAST_EXPECTS(to_string(x) == "FFFFFFFFFFFFFFFFFFFFFFFE", to_string(x));
154 
155  BEAST_EXPECT(uset.size() == 4);
156 
157  test96 tmp;
158  BEAST_EXPECT(tmp.parseHex(to_string(u)));
159  BEAST_EXPECT(tmp == u);
160  tmp = z;
161 
162  // fails with extra char
163  BEAST_EXPECT(!tmp.parseHex("A" + to_string(u)));
164  tmp = z;
165 
166  // fails with extra char at end
167  BEAST_EXPECT(!tmp.parseHex(to_string(u) + "A"));
168 
169  // fails with a non-hex character at some point in the string:
170  tmp = z;
171 
172  for (std::size_t i = 0; i != 24; ++i)
173  {
174  std::string x = to_string(z);
175  x[i] = ('G' + (i % 10));
176  BEAST_EXPECT(!tmp.parseHex(x));
177  }
178 
179  // Walking 1s:
180  for (std::size_t i = 0; i != 24; ++i)
181  {
182  std::string s1 = "000000000000000000000000";
183  s1[i] = '1';
184 
185  BEAST_EXPECT(tmp.parseHex(s1));
186  BEAST_EXPECT(to_string(tmp) == s1);
187  }
188 
189  // Walking 0s:
190  for (std::size_t i = 0; i != 24; ++i)
191  {
192  std::string s1 = "111111111111111111111111";
193  s1[i] = '0';
194 
195  BEAST_EXPECT(tmp.parseHex(s1));
196  BEAST_EXPECT(to_string(tmp) == s1);
197  }
198 
199  // Constexpr constructors
200  {
201  static_assert(test96{}.signum() == 0);
202  static_assert(test96("0").signum() == 0);
203  static_assert(test96("000000000000000000000000").signum() == 0);
204  static_assert(test96("000000000000000000000001").signum() == 1);
205  static_assert(test96("800000000000000000000000").signum() == 1);
206 
207 // Everything within the #if should fail during compilation.
208 #if 0
209  // Too few characters
210  static_assert(test96("00000000000000000000000").signum() == 0);
211 
212  // Too many characters
213  static_assert(test96("0000000000000000000000000").signum() == 0);
214 
215  // Non-hex characters
216  static_assert(test96("00000000000000000000000 ").signum() == 1);
217  static_assert(test96("00000000000000000000000/").signum() == 1);
218  static_assert(test96("00000000000000000000000:").signum() == 1);
219  static_assert(test96("00000000000000000000000@").signum() == 1);
220  static_assert(test96("00000000000000000000000G").signum() == 1);
221  static_assert(test96("00000000000000000000000`").signum() == 1);
222  static_assert(test96("00000000000000000000000g").signum() == 1);
223  static_assert(test96("00000000000000000000000~").signum() == 1);
224 #endif // 0
225 
226  // Using the constexpr constructor in a non-constexpr context
227  // with an error in the parsing throws an exception.
228  {
229  // Invalid length for string.
230  bool caught = false;
231  try
232  {
233  // Try to prevent constant evaluation.
234  std::vector<char> str(23, '7');
235  std::string_view sView(str.data(), str.size());
236  [[maybe_unused]] test96 t96(sView);
237  }
238  catch (std::invalid_argument const& e)
239  {
240  BEAST_EXPECT(
241  e.what() ==
242  std::string("invalid length for hex string"));
243  caught = true;
244  }
245  BEAST_EXPECT(caught);
246  }
247  {
248  // Invalid character in string.
249  bool caught = false;
250  try
251  {
252  // Try to prevent constant evaluation.
253  std::vector<char> str(23, '7');
254  str.push_back('G');
255  std::string_view sView(str.data(), str.size());
256  [[maybe_unused]] test96 t96(sView);
257  }
258  catch (std::range_error const& e)
259  {
260  BEAST_EXPECT(
261  e.what() == std::string("invalid hex character"));
262  caught = true;
263  }
264  BEAST_EXPECT(caught);
265  }
266 
267  // Verify that constexpr base_uints interpret a string the same
268  // way parseHex() does.
269  struct StrBaseUint
270  {
271  char const* const str;
272  test96 tst;
273 
274  constexpr StrBaseUint(char const* s) : str(s), tst(s)
275  {
276  }
277  };
278  constexpr StrBaseUint testCases[] = {
279  "000000000000000000000000",
280  "000000000000000000000001",
281  "fedcba9876543210ABCDEF91",
282  "19FEDCBA0123456789abcdef",
283  "800000000000000000000000",
284  "fFfFfFfFfFfFfFfFfFfFfFfF"};
285 
286  for (StrBaseUint const& t : testCases)
287  {
288  test96 t96;
289  BEAST_EXPECT(t96.parseHex(t.str));
290  BEAST_EXPECT(t96 == t.tst);
291  }
292  }
293  }
294 };
295 
296 BEAST_DEFINE_TESTSUITE(base_uint, ripple_basics, ripple);
297 
298 } // namespace test
299 } // namespace ripple
std::string
STL class.
ripple::test::base_uint_test
Definition: base_uint_test.cpp:57
std::string_view
STL class.
std::unordered_set
STL class.
ripple::test::nonhash::WIDTH
static constexpr std::size_t WIDTH
Definition: base_uint_test.cpp:38
std::vector< unsigned char >
std::unordered_set::size
T size(T... args)
std::is_assignable
std::vector::push_back
T push_back(T... args)
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:81
ripple::base_uint::bytes
static constexpr std::size_t bytes
Definition: base_uint.h:104
ripple::compare
int compare(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:553
std::array< std::uint8_t, WIDTH >
std::invalid_argument
STL class.
ripple::test::nonhash::endian
static constexpr const auto endian
Definition: base_uint_test.cpp:37
ripple::base_uint::signum
constexpr int signum() const
Definition: base_uint.h:326
ripple::test::base_uint_test::test96
base_uint< 96 > test96
Definition: base_uint_test.cpp:59
ripple::test::nonhash::nonhash
nonhash()=default
std::is_copy_constructible
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::nonhash
Definition: base_uint_test.cpp:35
std::array::begin
T begin(T... args)
std::unordered_set::insert
T insert(T... args)
ripple::test::nonhash::operator()
void operator()(void const *key, std::size_t len) noexcept
Definition: base_uint_test.cpp:45
std::is_constructible
complex
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
std::array::end
T end(T... args)
std::is_copy_assignable
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:495
std::prev
T prev(T... args)
std::range_error
STL class.
ripple::hash_append
void hash_append(Hasher &h, ValidatorBlobInfo const &blobInfo)
Definition: ValidatorList.h:897
ripple::test::nonhash::data_
std::array< std::uint8_t, WIDTH > data_
Definition: base_uint_test.cpp:40
ripple::test::base_uint_test::run
void run() override
Definition: base_uint_test.cpp:64
std::array::data
T data(T... args)
type_traits
std::invalid_argument::what
T what(T... args)
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)