1#include <xrpl/beast/core/LexicalCast.h>
3#include <xrpl/beast/xor_shift_engine.h>
5#include <gtest/gtest.h>
20[[nodiscard]]
constexpr bool
21parses(std::string_view text)
28[[nodiscard]]
constexpr T
29parsed(std::string_view text)
42constexpr T kUnderMax = kMax<T> - 1;
45constexpr T kOverMin = kMin<T> + 1;
48constexpr auto kNearMax32 = kMax<uint32_t> - 5;
49constexpr auto kNearMin32 = kMin<int32_t> + 4;
50constexpr auto kUnderInt64Max = uint64_t{kMax<int64_t>} - 1;
51constexpr auto kInRangeInt16 = int16_t{-5711};
54constexpr auto kAboveUint64Max =
"18446744073709551616";
55constexpr auto kBelowInt64Min =
"-9223372036854775809";
58constexpr auto kTwentyNines =
"99999999999999999999";
59constexpr auto kNegativeTwentyNines =
"-99999999999999999999";
62constexpr auto kAboveUint16Max =
"75821";
63constexpr auto kBelowInt16Min =
"-75821";
64constexpr auto kAboveInt32Max =
"5294967295";
65constexpr auto kAboveInt16Max =
"66666";
67constexpr auto kPositiveInt32 = int32_t{42};
68constexpr auto kNegativeInt32 = int32_t{-42};
70constexpr auto kPositiveInt32Text =
"+42";
71constexpr auto kNegativeInt32Text =
"-42";
73constexpr auto kNegativeOne =
"-1";
74constexpr auto kNegativeZero =
"-0";
75constexpr auto kBareZero =
"0";
76constexpr auto kPositiveZero =
"+0";
79constexpr std::string_view kFullWidthDigits =
"\xef\xbc\x91\xef\xbc\x90";
85 std::array<char, 24> buffer{};
88 constexpr explicit ToString(T value)
90 auto const result =
std::to_chars(buffer.data(), buffer.data() + buffer.size(), value);
91 length =
static_cast<std::size_t
>(result.ptr - buffer.data());
95 operator std::string_view()
const
97 return {buffer.data(), length};
102constexpr auto kMaxText = ToString{kMax<T>};
105constexpr auto kUnderMaxText = ToString{kUnderMax<T>};
107template <
class T,
class W
ider>
108constexpr auto kOverMaxText = ToString{Wider{kMax<T>} + 1};
111constexpr auto kMinText = ToString{kMin<T>};
114constexpr auto kOverMinText = ToString{kOverMin<T>};
116template <
class T,
class W
ider>
117constexpr auto kUnderMinText = ToString{Wider{kMin<T>} - 1};
119constexpr auto kOverUint32MaxText = ToString{uint64_t{kMax<uint32_t>} + 5};
120constexpr auto kNegatedOverUint32MaxText = ToString{-(int64_t{kMax<uint32_t>} + 5)};
124template <
class T,
class Value>
125[[nodiscard]]
constexpr T
126castThrow(Value value)
133roundTrips(std::string_view text)
141expectRoundTrip(T value)
143 SCOPED_TRACE(::testing::Message() <<
"value: " << value);
148 auto decoded =
static_cast<T
>(~value);
150 EXPECT_EQ(decoded, value);
190 static constexpr auto kSampleCount = 1000uz;
194 for (
auto i = 0uz; i < kSampleCount; ++i)
195 expectRoundTrip(
static_cast<TypeParam
>(r()));
204TEST(LexicalCast, round_trips_every_int16_value)
206 for (int32_t i = kMin<int16_t>; i <= kMax<int16_t>; ++i)
208 auto const value =
static_cast<int16_t
>(i);
217TEST(LexicalCast, rejects_overflow)
219 static_assert(not parses<uint32_t>(kOverUint32MaxText));
220 static_assert(not parses<uint64_t>(kTwentyNines));
221 static_assert(not parses<uint16_t>(kAboveUint16Max));
224TEST(LexicalCast, rejects_underflow)
226 static_assert(not parses<uint32_t>(kNegativeOne));
227 static_assert(not parses<int32_t>(kNegatedOverUint32MaxText));
228 static_assert(not parses<int64_t>(kNegativeTwentyNines));
229 static_assert(not parses<int16_t>(kBelowInt16Min));
232TEST(LexicalCast, accepts_up_to_the_maximum)
234 static_assert(parsed<uint16_t>(kUnderMaxText<uint16_t>) == kUnderMax<uint16_t>);
235 static_assert(parsed<uint16_t>(kMaxText<uint16_t>) == kMax<uint16_t>);
236 static_assert(not parses<uint16_t>(kOverMaxText<uint16_t, uint32_t>));
238 static_assert(parsed<int16_t>(kUnderMaxText<int16_t>) == kUnderMax<int16_t>);
239 static_assert(parsed<int16_t>(kMaxText<int16_t>) == kMax<int16_t>);
240 static_assert(not parses<int16_t>(kOverMaxText<int16_t, int32_t>));
242 static_assert(parsed<uint32_t>(kUnderMaxText<uint32_t>) == kUnderMax<uint32_t>);
243 static_assert(parsed<uint32_t>(kMaxText<uint32_t>) == kMax<uint32_t>);
244 static_assert(not parses<uint32_t>(kOverMaxText<uint32_t, uint64_t>));
246 static_assert(parsed<int32_t>(kUnderMaxText<int32_t>) == kUnderMax<int32_t>);
247 static_assert(parsed<int32_t>(kMaxText<int32_t>) == kMax<int32_t>);
248 static_assert(not parses<int32_t>(kOverMaxText<int32_t, int64_t>));
250 static_assert(parsed<int64_t>(kUnderMaxText<int64_t>) == kUnderMax<int64_t>);
251 static_assert(parsed<int64_t>(kMaxText<int64_t>) == kMax<int64_t>);
252 static_assert(not parses<int64_t>(kOverMaxText<int64_t, uint64_t>));
254 static_assert(parsed<uint64_t>(kUnderMaxText<uint64_t>) == kUnderMax<uint64_t>);
255 static_assert(parsed<uint64_t>(kMaxText<uint64_t>) == kMax<uint64_t>);
256 static_assert(not parses<uint64_t>(kAboveUint64Max));
259TEST(LexicalCast, accepts_down_to_the_minimum)
261 static_assert(parsed<int16_t>(kOverMinText<int16_t>) == kOverMin<int16_t>);
262 static_assert(parsed<int16_t>(kMinText<int16_t>) == kMin<int16_t>);
263 static_assert(not parses<int16_t>(kUnderMinText<int16_t, int32_t>));
265 static_assert(parsed<int32_t>(kOverMinText<int32_t>) == kOverMin<int32_t>);
266 static_assert(parsed<int32_t>(kMinText<int32_t>) == kMin<int32_t>);
267 static_assert(not parses<int32_t>(kUnderMinText<int32_t, int64_t>));
269 static_assert(parsed<int64_t>(kOverMinText<int64_t>) == kOverMin<int64_t>);
270 static_assert(parsed<int64_t>(kMinText<int64_t>) == kMin<int64_t>);
271 static_assert(not parses<int64_t>(kBelowInt64Min));
274TEST(LexicalCast, limits_round_trip_through_to_string)
276 EXPECT_TRUE(roundTrips<uint64_t>(kMaxText<uint64_t>));
277 EXPECT_TRUE(roundTrips<int64_t>(kMaxText<int64_t>));
278 EXPECT_TRUE(roundTrips<int64_t>(kMinText<int64_t>));
279 EXPECT_TRUE(roundTrips<uint32_t>(kMaxText<uint32_t>));
280 EXPECT_TRUE(roundTrips<int32_t>(kMinText<int32_t>));
281 EXPECT_TRUE(roundTrips<uint16_t>(kMaxText<uint16_t>));
282 EXPECT_TRUE(roundTrips<int16_t>(kMinText<int16_t>));
285TEST(LexicalCast, accepts_signed_zero_in_every_form)
287 static_assert(parsed<int32_t>(kNegativeZero) == 0);
288 static_assert(parsed<int32_t>(kBareZero) == 0);
289 static_assert(parsed<int32_t>(kPositiveZero) == 0);
292TEST(LexicalCast, rejects_negative_zero_when_unsigned)
294 static_assert(not parses<uint32_t>(kNegativeZero));
295 static_assert(parsed<uint32_t>(kBareZero) == 0);
296 static_assert(parsed<uint32_t>(kPositiveZero) == 0);
299TEST(LexicalCast, accepts_char_pointer_and_std_string_input)
301 int32_t fromLiteral = 0;
303 EXPECT_EQ(fromLiteral, kPositiveInt32);
305 int32_t fromString = 0;
307 EXPECT_EQ(fromString, kNegativeInt32);
310TEST(LexicalCast, throwing_cast_returns_in_range_values)
312 static_assert(castThrow<uint64_t>(kUnderInt64Max) == kUnderInt64Max);
313 static_assert(castThrow<uint32_t>(kNearMax32) == kNearMax32);
314 static_assert(castThrow<int32_t>(kNearMin32) == kNearMin32);
315 static_assert(castThrow<int16_t>(kInRangeInt16) == kInRangeInt16);
318TEST(LexicalCast, throwing_cast_throws_on_out_of_range)
323 for (
auto const scale : {10, 100, 1000})
325 auto const tooBig = ToString{uint64_t{kNearMax32} * scale};
334TEST(LexicalCast, throwing_cast_throws_on_utf8_digits)
detail::XorShiftEngine<> xor_shift_engine
XOR-shift Generator.
constexpr Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
TEST(LexicalCast, round_trips_every_int16_value)
constexpr bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
TYPED_TEST_SUITE(LexicalCastIntegers, IntegerTypes, IntegerTypeNames)
constexpr Out lexicalCast(In in, Out defaultValue=Out())
Convert from one type to another.
::testing::Types< int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t > IntegerTypes
TYPED_TEST(LexicalCastIntegers, round_trips_random_values)
Thrown when a conversion is not possible with LexicalCast.
static std::string GetName(int)