#include #include #include #include #include #include #include namespace beast { class LexicalCast_test : public unit_test::suite { public: template static IntType nextRandomInt(xor_shift_engine& r) { return static_cast(r()); } template void testInteger(IntType in) { std::string s; IntType out = static_cast(~in); // Ensure out != in expect(lexicalCastChecked(s, in)); expect(lexicalCastChecked(out, s)); expect(out == in); } template 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(r)); testInteger(value); } } { std::stringstream ss; ss << "numeric_limits <" << typeid(IntType).name() << ">"; testcase(ss.str()); testInteger(std::numeric_limits::min()); testInteger(std::numeric_limits::max()); } } void testPathologies() { testcase("pathologies"); try { lexicalCastThrow("\xef\xbc\x91\xef\xbc\x90"); // utf-8 encoded } catch (BadLexicalCast const&) { pass(); } } template void tryBadConvert(std::string const& s) { T out; expect(!lexicalCastChecked(out, s), s); } void testConversionOverflows() { testcase("conversion overflows"); tryBadConvert("99999999999999999999"); tryBadConvert("4294967300"); tryBadConvert("75821"); } void testConversionUnderflows() { testcase("conversion underflows"); tryBadConvert("-1"); tryBadConvert("-99999999999999999999"); tryBadConvert("-4294967300"); tryBadConvert("-75821"); } template 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("18446744073709551614")); expect(tryEdgeCase("18446744073709551615")); expect(!tryEdgeCase("18446744073709551616")); expect(tryEdgeCase("9223372036854775806")); expect(tryEdgeCase("9223372036854775807")); expect(!tryEdgeCase("9223372036854775808")); expect(tryEdgeCase("-9223372036854775807")); expect(tryEdgeCase("-9223372036854775808")); expect(!tryEdgeCase("-9223372036854775809")); expect(tryEdgeCase("4294967294")); expect(tryEdgeCase("4294967295")); expect(!tryEdgeCase("4294967296")); expect(tryEdgeCase("2147483646")); expect(tryEdgeCase("2147483647")); expect(!tryEdgeCase("2147483648")); expect(tryEdgeCase("-2147483647")); expect(tryEdgeCase("-2147483648")); expect(!tryEdgeCase("-2147483649")); expect(tryEdgeCase("65534")); expect(tryEdgeCase("65535")); expect(!tryEdgeCase("65536")); expect(tryEdgeCase("32766")); expect(tryEdgeCase("32767")); expect(!tryEdgeCase("32768")); expect(tryEdgeCase("-32767")); expect(tryEdgeCase("-32768")); expect(!tryEdgeCase("-32769")); } template void testThrowConvert(std::string const& s, bool success) { bool result = !success; T out; try { out = lexicalCastThrow(s); result = true; } catch (BadLexicalCast const&) { result = false; } expect(result == success, s); } void testThrowingConversions() { testcase("throwing conversion"); testThrowConvert("99999999999999999999", false); testThrowConvert("9223372036854775806", true); testThrowConvert("4294967290", true); testThrowConvert("42949672900", false); testThrowConvert("429496729000", false); testThrowConvert("4294967290000", false); testThrowConvert("5294967295", false); testThrowConvert("-2147483644", true); testThrowConvert("66666", false); testThrowConvert("-5711", true); } void testZero() { testcase("zero conversion"); { std::int32_t out = 0; expect(lexicalCastChecked(out, "-0"), "0"); expect(lexicalCastChecked(out, "0"), "0"); expect(lexicalCastChecked(out, "+0"), "0"); } { std::uint32_t out = 0; 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::min(); std::string const empty; while (i <= std::numeric_limits::max()) { std::int16_t const j = static_cast(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(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(r); testIntegers(r); testIntegers(r); testIntegers(r); testIntegers(r); testIntegers(r); testIntegers(r); testIntegers(r); testPathologies(); testConversionOverflows(); testConversionUnderflows(); testThrowingConversions(); testZero(); testEdgeCases(); testEntireRange(); } }; BEAST_DEFINE_TESTSUITE(LexicalCast, beast, beast); } // namespace beast