Files
rippled/src/test/beast/LexicalCast_test.cpp
Bart 1d42c4f6de refactor: Remove unnecessary copyright notices already covered by LICENSE.md (#5929)
Per XLS-0095, we are taking steps to rename ripple(d) to xrpl(d).

This change specifically removes all copyright notices referencing Ripple, XRPLF, and certain affiliated contributors upon mutual agreement, so the notice in the LICENSE.md file applies throughout. Copyright notices referencing external contributions remain as-is. Duplicate verbiage is also removed.
2025-11-04 08:33:42 +00:00

276 lines
7.1 KiB
C++

#include <xrpl/beast/core/LexicalCast.h>
#include <xrpl/beast/unit_test.h>
#include <xrpl/beast/xor_shift_engine.h>
namespace beast {
class LexicalCast_test : public unit_test::suite
{
public:
template <class IntType>
static IntType
nextRandomInt(xor_shift_engine& r)
{
return static_cast<IntType>(r());
}
template <class IntType>
void
testInteger(IntType in)
{
std::string s;
IntType out(in + 1);
expect(lexicalCastChecked(s, in));
expect(lexicalCastChecked(out, s));
expect(out == in);
}
template <class IntType>
void
testIntegers(xor_shift_engine& r)
{
{
std::stringstream ss;
ss << "random " << typeid(IntType).name();
testcase(ss.str());
for (int i = 0; i < 1000; ++i)
{
IntType const value(nextRandomInt<IntType>(r));
testInteger(value);
}
}
{
std::stringstream ss;
ss << "numeric_limits <" << typeid(IntType).name() << ">";
testcase(ss.str());
testInteger(std::numeric_limits<IntType>::min());
testInteger(std::numeric_limits<IntType>::max());
}
}
void
testPathologies()
{
testcase("pathologies");
try
{
lexicalCastThrow<int>("\xef\xbc\x91\xef\xbc\x90"); // utf-8 encoded
}
catch (BadLexicalCast const&)
{
pass();
}
}
template <class T>
void
tryBadConvert(std::string const& s)
{
T out;
expect(!lexicalCastChecked(out, s), s);
}
void
testConversionOverflows()
{
testcase("conversion overflows");
tryBadConvert<std::uint64_t>("99999999999999999999");
tryBadConvert<std::uint32_t>("4294967300");
tryBadConvert<std::uint16_t>("75821");
}
void
testConversionUnderflows()
{
testcase("conversion underflows");
tryBadConvert<std::uint32_t>("-1");
tryBadConvert<std::int64_t>("-99999999999999999999");
tryBadConvert<std::int32_t>("-4294967300");
tryBadConvert<std::int16_t>("-75821");
}
template <class T>
bool
tryEdgeCase(std::string const& s)
{
T ret;
bool const result = lexicalCastChecked(ret, s);
if (!result)
return false;
return s == std::to_string(ret);
}
void
testEdgeCases()
{
testcase("conversion edge cases");
expect(tryEdgeCase<std::uint64_t>("18446744073709551614"));
expect(tryEdgeCase<std::uint64_t>("18446744073709551615"));
expect(!tryEdgeCase<std::uint64_t>("18446744073709551616"));
expect(tryEdgeCase<std::int64_t>("9223372036854775806"));
expect(tryEdgeCase<std::int64_t>("9223372036854775807"));
expect(!tryEdgeCase<std::int64_t>("9223372036854775808"));
expect(tryEdgeCase<std::int64_t>("-9223372036854775807"));
expect(tryEdgeCase<std::int64_t>("-9223372036854775808"));
expect(!tryEdgeCase<std::int64_t>("-9223372036854775809"));
expect(tryEdgeCase<std::uint32_t>("4294967294"));
expect(tryEdgeCase<std::uint32_t>("4294967295"));
expect(!tryEdgeCase<std::uint32_t>("4294967296"));
expect(tryEdgeCase<std::int32_t>("2147483646"));
expect(tryEdgeCase<std::int32_t>("2147483647"));
expect(!tryEdgeCase<std::int32_t>("2147483648"));
expect(tryEdgeCase<std::int32_t>("-2147483647"));
expect(tryEdgeCase<std::int32_t>("-2147483648"));
expect(!tryEdgeCase<std::int32_t>("-2147483649"));
expect(tryEdgeCase<std::uint16_t>("65534"));
expect(tryEdgeCase<std::uint16_t>("65535"));
expect(!tryEdgeCase<std::uint16_t>("65536"));
expect(tryEdgeCase<std::int16_t>("32766"));
expect(tryEdgeCase<std::int16_t>("32767"));
expect(!tryEdgeCase<std::int16_t>("32768"));
expect(tryEdgeCase<std::int16_t>("-32767"));
expect(tryEdgeCase<std::int16_t>("-32768"));
expect(!tryEdgeCase<std::int16_t>("-32769"));
}
template <class T>
void
testThrowConvert(std::string const& s, bool success)
{
bool result = !success;
T out;
try
{
out = lexicalCastThrow<T>(s);
result = true;
}
catch (BadLexicalCast const&)
{
result = false;
}
expect(result == success, s);
}
void
testThrowingConversions()
{
testcase("throwing conversion");
testThrowConvert<std::uint64_t>("99999999999999999999", false);
testThrowConvert<std::uint64_t>("9223372036854775806", true);
testThrowConvert<std::uint32_t>("4294967290", true);
testThrowConvert<std::uint32_t>("42949672900", false);
testThrowConvert<std::uint32_t>("429496729000", false);
testThrowConvert<std::uint32_t>("4294967290000", false);
testThrowConvert<std::int32_t>("5294967295", false);
testThrowConvert<std::int32_t>("-2147483644", true);
testThrowConvert<std::int16_t>("66666", false);
testThrowConvert<std::int16_t>("-5711", true);
}
void
testZero()
{
testcase("zero conversion");
{
std::int32_t out;
expect(lexicalCastChecked(out, "-0"), "0");
expect(lexicalCastChecked(out, "0"), "0");
expect(lexicalCastChecked(out, "+0"), "0");
}
{
std::uint32_t out;
expect(!lexicalCastChecked(out, "-0"), "0");
expect(lexicalCastChecked(out, "0"), "0");
expect(lexicalCastChecked(out, "+0"), "0");
}
}
void
testEntireRange()
{
testcase("entire range");
std::int32_t i = std::numeric_limits<std::int16_t>::min();
std::string const empty("");
while (i <= std::numeric_limits<std::int16_t>::max())
{
std::int16_t j = static_cast<std::int16_t>(i);
auto actual = std::to_string(j);
auto result = lexicalCast(j, empty);
expect(result == actual, actual + " (string to integer)");
if (result == actual)
{
auto number = lexicalCast<std::int16_t>(result);
if (number != j)
expect(false, actual + " (integer to string)");
}
i++;
}
}
void
run() override
{
std::int64_t const seedValue = 50;
xor_shift_engine r(seedValue);
testIntegers<int>(r);
testIntegers<unsigned int>(r);
testIntegers<short>(r);
testIntegers<unsigned short>(r);
testIntegers<std::int32_t>(r);
testIntegers<std::uint32_t>(r);
testIntegers<std::int64_t>(r);
testIntegers<std::uint64_t>(r);
testPathologies();
testConversionOverflows();
testConversionUnderflows();
testThrowingConversions();
testZero();
testEdgeCases();
testEntireRange();
}
};
BEAST_DEFINE_TESTSUITE(LexicalCast, beast, beast);
} // namespace beast