rippled
LexicalCast_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of Beast: https://github.com/vinniefalco/Beast
4  Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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/beast/core/LexicalCast.h>
21 #include <ripple/beast/unit_test.h>
22 #include <ripple/beast/xor_shift_engine.h>
23 
24 namespace beast {
25 
26 class LexicalCast_test : public unit_test::suite
27 {
28 public:
29  template <class IntType>
30  static IntType nextRandomInt (xor_shift_engine& r)
31  {
32  return static_cast <IntType> (r());
33  }
34 
35  template <class IntType>
36  void testInteger (IntType in)
37  {
38  std::string s;
39  IntType out (in+1);
40 
41  expect (lexicalCastChecked (s, in));
42  expect (lexicalCastChecked (out, s));
43  expect (out == in);
44  }
45 
46  template <class IntType>
48  {
49  {
51  ss <<
52  "random " << typeid (IntType).name ();
53  testcase (ss.str());
54 
55  for (int i = 0; i < 1000; ++i)
56  {
57  IntType const value (nextRandomInt <IntType> (r));
58  testInteger (value);
59  }
60  }
61 
62  {
64  ss <<
65  "numeric_limits <" << typeid (IntType).name () << ">";
66  testcase (ss.str());
67 
70  }
71  }
72 
74  {
75  testcase("pathologies");
76  try
77  {
78  lexicalCastThrow<int>("\xef\xbc\x91\xef\xbc\x90"); // utf-8 encoded
79  }
80  catch(BadLexicalCast const&)
81  {
82  pass();
83  }
84  }
85 
86  template <class T>
87  void tryBadConvert (std::string const& s)
88  {
89  T out;
90  expect (!lexicalCastChecked (out, s), s);
91  }
92 
94  {
95  testcase ("conversion overflows");
96 
97  tryBadConvert <std::uint64_t> ("99999999999999999999");
98  tryBadConvert <std::uint32_t> ("4294967300");
99  tryBadConvert <std::uint16_t> ("75821");
100  }
101 
103  {
104  testcase ("conversion underflows");
105 
106  tryBadConvert <std::uint32_t> ("-1");
107 
108  tryBadConvert <std::int64_t> ("-99999999999999999999");
109  tryBadConvert <std::int32_t> ("-4294967300");
110  tryBadConvert <std::int16_t> ("-75821");
111  }
112 
113  template <class T>
114  bool tryEdgeCase (std::string const& s)
115  {
116  T ret;
117 
118  bool const result = lexicalCastChecked (ret, s);
119 
120  if (!result)
121  return false;
122 
123  return s == std::to_string (ret);
124  }
125 
127  {
128  testcase ("conversion edge cases");
129 
130  expect(tryEdgeCase <std::uint64_t> ("18446744073709551614"));
131  expect(tryEdgeCase <std::uint64_t> ("18446744073709551615"));
132  expect(!tryEdgeCase <std::uint64_t> ("18446744073709551616"));
133 
134  expect(tryEdgeCase <std::int64_t> ("9223372036854775806"));
135  expect(tryEdgeCase <std::int64_t> ("9223372036854775807"));
136  expect(!tryEdgeCase <std::int64_t> ("9223372036854775808"));
137 
138  expect(tryEdgeCase <std::int64_t> ("-9223372036854775807"));
139  expect(tryEdgeCase <std::int64_t> ("-9223372036854775808"));
140  expect(!tryEdgeCase <std::int64_t> ("-9223372036854775809"));
141 
142  expect(tryEdgeCase <std::uint32_t> ("4294967294"));
143  expect(tryEdgeCase <std::uint32_t> ("4294967295"));
144  expect(!tryEdgeCase <std::uint32_t> ("4294967296"));
145 
146  expect(tryEdgeCase <std::int32_t> ("2147483646"));
147  expect(tryEdgeCase <std::int32_t> ("2147483647"));
148  expect(!tryEdgeCase <std::int32_t> ("2147483648"));
149 
150  expect(tryEdgeCase <std::int32_t> ("-2147483647"));
151  expect(tryEdgeCase <std::int32_t> ("-2147483648"));
152  expect(!tryEdgeCase <std::int32_t> ("-2147483649"));
153 
154  expect(tryEdgeCase <std::uint16_t> ("65534"));
155  expect(tryEdgeCase <std::uint16_t> ("65535"));
156  expect(!tryEdgeCase <std::uint16_t> ("65536"));
157 
158  expect(tryEdgeCase <std::int16_t> ("32766"));
159  expect(tryEdgeCase <std::int16_t> ("32767"));
160  expect(!tryEdgeCase <std::int16_t> ("32768"));
161 
162  expect(tryEdgeCase <std::int16_t> ("-32767"));
163  expect(tryEdgeCase <std::int16_t> ("-32768"));
164  expect(!tryEdgeCase <std::int16_t> ("-32769"));
165  }
166 
167  template <class T>
168  void testThrowConvert(std::string const& s, bool success)
169  {
170  bool result = !success;
171  T out;
172 
173  try
174  {
175  out = lexicalCastThrow <T> (s);
176  result = true;
177  }
178  catch(BadLexicalCast const&)
179  {
180  result = false;
181  }
182 
183  expect (result == success, s);
184  }
185 
187  {
188  testcase ("throwing conversion");
189 
190  testThrowConvert <std::uint64_t> ("99999999999999999999", false);
191  testThrowConvert <std::uint64_t> ("9223372036854775806", true);
192 
193  testThrowConvert <std::uint32_t> ("4294967290", true);
194  testThrowConvert <std::uint32_t> ("42949672900", false);
195  testThrowConvert <std::uint32_t> ("429496729000", false);
196  testThrowConvert <std::uint32_t> ("4294967290000", false);
197 
198  testThrowConvert <std::int32_t> ("5294967295", false);
199  testThrowConvert <std::int32_t> ("-2147483644", true);
200 
201  testThrowConvert <std::int16_t> ("66666", false);
202  testThrowConvert <std::int16_t> ("-5711", true);
203  }
204 
205  void testZero ()
206  {
207  testcase ("zero conversion");
208 
209  {
210  std::int32_t out;
211 
212  expect (lexicalCastChecked (out, "-0"), "0");
213  expect (lexicalCastChecked (out, "0"), "0");
214  expect (lexicalCastChecked (out, "+0"), "0");
215  }
216 
217  {
218  std::uint32_t out;
219 
220  expect (!lexicalCastChecked (out, "-0"), "0");
221  expect (lexicalCastChecked (out, "0"), "0");
222  expect (lexicalCastChecked (out, "+0"), "0");
223  }
224  }
225 
227  {
228  testcase ("entire range");
229 
231  std::string const empty("");
232 
234  {
235  std::int16_t j = static_cast<std::int16_t>(i);
236 
237  auto actual = std::to_string (j);
238 
239  auto result = lexicalCast (j, empty);
240 
241  expect (result == actual, actual + " (string to integer)");
242 
243  if (result == actual)
244  {
245  auto number = lexicalCast <std::int16_t> (result);
246 
247  if (number != j)
248  expect (false, actual + " (integer to string)");
249  }
250 
251  i++;
252  }
253  }
254 
255  void run() override
256  {
257  std::int64_t const seedValue = 50;
258 
259  xor_shift_engine r (seedValue);
260 
261  testIntegers <int> (r);
262  testIntegers <unsigned int> (r);
263  testIntegers <short> (r);
264  testIntegers <unsigned short> (r);
265  testIntegers <std::int32_t> (r);
266  testIntegers <std::uint32_t> (r);
267  testIntegers <std::int64_t> (r);
268  testIntegers <std::uint64_t> (r);
269 
270  testPathologies();
274  testZero ();
275  testEdgeCases ();
276  testEntireRange ();
277  }
278 };
279 
280 BEAST_DEFINE_TESTSUITE(LexicalCast,beast_core,beast);
281 
282 } // beast
beast::LexicalCast_test::testInteger
void testInteger(IntType in)
Definition: LexicalCast_test.cpp:36
beast::LexicalCast_test::run
void run() override
Definition: LexicalCast_test.cpp:255
beast::LexicalCast_test
Definition: LexicalCast_test.cpp:26
std::string
STL class.
beast::LexicalCast_test::testConversionUnderflows
void testConversionUnderflows()
Definition: LexicalCast_test.cpp:102
beast::LexicalCast_test::testPathologies
void testPathologies()
Definition: LexicalCast_test.cpp:73
beast::LexicalCast_test::tryEdgeCase
bool tryEdgeCase(std::string const &s)
Definition: LexicalCast_test.cpp:114
beast::lexicalCast
Out lexicalCast(In in, Out defaultValue=Out())
Convert from one type to another.
Definition: LexicalCast.h:290
std::stringstream
STL class.
beast::BadLexicalCast
Thrown when a conversion is not possible with LexicalCast.
Definition: LexicalCast.h:253
beast::LexicalCast_test::tryBadConvert
void tryBadConvert(std::string const &s)
Definition: LexicalCast_test.cpp:87
beast::LexicalCast_test::testEdgeCases
void testEdgeCases()
Definition: LexicalCast_test.cpp:126
beast::LexicalCast_test::testThrowingConversions
void testThrowingConversions()
Definition: LexicalCast_test.cpp:186
beast::LexicalCast_test::nextRandomInt
static IntType nextRandomInt(xor_shift_engine &r)
Definition: LexicalCast_test.cpp:30
beast::LexicalCast_test::testZero
void testZero()
Definition: LexicalCast_test.cpp:205
std::to_string
T to_string(T... args)
beast::LexicalCast_test::testThrowConvert
void testThrowConvert(std::string const &s, bool success)
Definition: LexicalCast_test.cpp:168
std::int32_t
std::numeric_limits::min
T min(T... args)
beast::lexicalCastChecked
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Definition: LexicalCast.h:262
beast::LexicalCast_test::testIntegers
void testIntegers(xor_shift_engine &r)
Definition: LexicalCast_test.cpp:47
std::stringstream::str
T str(T... args)
beast::LexicalCast_test::testConversionOverflows
void testConversionOverflows()
Definition: LexicalCast_test.cpp:93
beast::detail::xor_shift_engine
Definition: xor_shift_engine.h:32
beast::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(aged_set, container, beast)
beast::LexicalCast_test::testEntireRange
void testEntireRange()
Definition: LexicalCast_test.cpp:226
std::numeric_limits
beast
Definition: base_uint.h:582