Commit 45442498 authored by Kenton Varda's avatar Kenton Varda

Make string parse exceptions recoverable under -fno-exceptions.

parent f93ea92c
......@@ -222,8 +222,8 @@ KJ_TEST("decode all types") {
CASE(R"({"int64Field":9007199254740991})", root.getInt64Field() == 9007199254740991LL);
CASE(R"({"int64Field":"-9223372036854775808"})", root.getInt64Field() == -9223372036854775808ULL);
CASE(R"({"int64Field":"9223372036854775807"})", root.getInt64Field() == 9223372036854775807LL);
CASE_THROW(R"({"int64Field":"-9223372036854775809"})", "Value out-of-range");
CASE_THROW(R"({"int64Field":"9223372036854775808"})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"int64Field":"-9223372036854775809"})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"int64Field":"9223372036854775808"})", "Value out-of-range");
CASE(R"({"uInt8Field":255})", root.getUInt8Field() == 255);
CASE(R"({"uInt8Field":"0"})", root.getUInt8Field() == 0);
CASE_THROW_RECOVERABLE(R"({"uInt8Field":"256"})", "Value out-of-range");
......@@ -239,7 +239,7 @@ KJ_TEST("decode all types") {
CASE(R"({"uInt64Field":9007199254740991})", root.getUInt64Field() == 9007199254740991ULL);
CASE(R"({"uInt64Field":"18446744073709551615"})", root.getUInt64Field() == 18446744073709551615ULL);
CASE(R"({"uInt64Field":"0"})", root.getUInt64Field() == 0);
CASE_THROW(R"({"uInt64Field":"18446744073709551616"})", "Value out-of-range");
CASE_THROW_RECOVERABLE(R"({"uInt64Field":"18446744073709551616"})", "Value out-of-range");
CASE(R"({"float32Field":0})", root.getFloat32Field() == 0);
CASE(R"({"float32Field":4.5})", root.getFloat32Field() == 4.5);
CASE(R"({"float32Field":null})", kj::isNaN(root.getFloat32Field()));
......@@ -264,9 +264,9 @@ KJ_TEST("decode all types") {
CASE(R"({"structField":{"boolField":true}})", root.getStructField().getBoolField() == true);
CASE(R"({"enumField":"bar"})", root.getEnumField() == TestEnum::BAR);
CASE_THROW(R"({"int64Field":"177a"})", "String does not contain valid");
CASE_THROW(R"({"uInt64Field":"177a"})", "String does not contain valid");
CASE_THROW(R"({"float64Field":"177a"})", "String does not contain valid");
CASE_THROW_RECOVERABLE(R"({"int64Field":"177a"})", "String does not contain valid");
CASE_THROW_RECOVERABLE(R"({"uInt64Field":"177a"})", "String does not contain valid");
CASE_THROW_RECOVERABLE(R"({"float64Field":"177a"})", "String does not contain valid");
CASE(R"({})", root.hasBoolList() == false);
CASE(R"({"boolList":null})", root.hasBoolList() == false);
......@@ -315,6 +315,7 @@ KJ_TEST("decode all types") {
CASE(R"({"enumList":["bar"]})", root.getEnumList()[0] == TestEnum::BAR);
#undef CASE
#undef CASE_THROW
#undef CASE_THROW_RECOVERABLE
}
KJ_TEST("decode test message") {
......
......@@ -86,22 +86,22 @@ TEST(String, parseAs) {
EXPECT_TRUE(isNaN(StringPtr("nan").parseAs<double>()));
EXPECT_TRUE(isNaN(StringPtr("NAN").parseAs<double>()));
EXPECT_TRUE(isNaN(StringPtr("NaN").parseAs<double>()));
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("").parseAs<double>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("a").parseAs<double>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("1a").parseAs<double>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("+-1").parseAs<double>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("").parseAs<double>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("a").parseAs<double>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("1a").parseAs<double>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("+-1").parseAs<double>());
EXPECT_EQ(StringPtr("1").parseAs<float>(), 1.0);
EXPECT_EQ(StringPtr("1").parseAs<int64_t>(), 1);
EXPECT_EQ(StringPtr("9223372036854775807").parseAs<int64_t>(), 9223372036854775807LL);
EXPECT_EQ(StringPtr("-9223372036854775808").parseAs<int64_t>(), -9223372036854775808ULL);
KJ_EXPECT_THROW_MESSAGE("out-of-range", StringPtr("9223372036854775808").parseAs<int64_t>());
KJ_EXPECT_THROW_MESSAGE("out-of-range", StringPtr("-9223372036854775809").parseAs<int64_t>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("").parseAs<int64_t>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("a").parseAs<int64_t>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("1a").parseAs<int64_t>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("+-1").parseAs<int64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("9223372036854775808").parseAs<int64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("-9223372036854775809").parseAs<int64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("").parseAs<int64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("a").parseAs<int64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("1a").parseAs<int64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("+-1").parseAs<int64_t>());
EXPECT_EQ(StringPtr("010").parseAs<int64_t>(), 10);
EXPECT_EQ(StringPtr("0010").parseAs<int64_t>(), 10);
EXPECT_EQ(StringPtr("0x10").parseAs<int64_t>(), 16);
......@@ -113,24 +113,24 @@ TEST(String, parseAs) {
EXPECT_EQ(StringPtr("1").parseAs<uint64_t>(), 1);
EXPECT_EQ(StringPtr("0").parseAs<uint64_t>(), 0);
EXPECT_EQ(StringPtr("18446744073709551615").parseAs<uint64_t>(), 18446744073709551615ULL);
KJ_EXPECT_THROW_MESSAGE("out-of-range", StringPtr("-1").parseAs<uint64_t>());
KJ_EXPECT_THROW_MESSAGE("out-of-range", StringPtr("18446744073709551616").parseAs<uint64_t>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("").parseAs<uint64_t>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("a").parseAs<uint64_t>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("1a").parseAs<uint64_t>());
KJ_EXPECT_THROW_MESSAGE("not contain valid", StringPtr("+-1").parseAs<uint64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("-1").parseAs<uint64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("18446744073709551616").parseAs<uint64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("").parseAs<uint64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("a").parseAs<uint64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("1a").parseAs<uint64_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("+-1").parseAs<uint64_t>());
EXPECT_EQ(StringPtr("1").parseAs<int32_t>(), 1);
EXPECT_EQ(StringPtr("2147483647").parseAs<int32_t>(), 2147483647);
EXPECT_EQ(StringPtr("-2147483648").parseAs<int32_t>(), -2147483648);
KJ_EXPECT_THROW_MESSAGE("out-of-range", StringPtr("2147483648").parseAs<int32_t>());
KJ_EXPECT_THROW_MESSAGE("out-of-range", StringPtr("-2147483649").parseAs<int32_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("2147483648").parseAs<int32_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("-2147483649").parseAs<int32_t>());
EXPECT_EQ(StringPtr("1").parseAs<uint32_t>(), 1);
EXPECT_EQ(StringPtr("0").parseAs<uint32_t>(), 0U);
EXPECT_EQ(StringPtr("4294967295").parseAs<uint32_t>(), 4294967295U);
KJ_EXPECT_THROW_MESSAGE("out-of-range", StringPtr("-1").parseAs<uint32_t>());
KJ_EXPECT_THROW_MESSAGE("out-of-range", StringPtr("4294967296").parseAs<uint32_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("-1").parseAs<uint32_t>());
KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("4294967296").parseAs<uint32_t>());
EXPECT_EQ(StringPtr("1").parseAs<int16_t>(), 1);
EXPECT_EQ(StringPtr("1").parseAs<uint16_t>(), 1);
......
......@@ -40,25 +40,26 @@ bool isHex(const char *s) {
}
long long parseSigned(const StringPtr& s, long long min, long long max) {
KJ_REQUIRE(s != nullptr, "String does not contain valid number", s);
KJ_REQUIRE(s != nullptr, "String does not contain valid number", s) { return 0; }
char *endPtr;
errno = 0;
auto value = strtoll(s.begin(), &endPtr, isHex(s.cStr()) ? 16 : 10);
KJ_REQUIRE(endPtr == s.end(), "String does not contain valid number", s);
KJ_REQUIRE(errno != ERANGE, "Value out-of-range", s);
KJ_REQUIRE(value >= min && value <= max, "Value out-of-range", value, min, max);
KJ_REQUIRE(endPtr == s.end(), "String does not contain valid number", s) { return 0; }
KJ_REQUIRE(errno != ERANGE, "Value out-of-range", s) { return 0; }
KJ_REQUIRE(value >= min && value <= max, "Value out-of-range", value, min, max) { return 0; }
return value;
}
unsigned long long parseUnsigned(const StringPtr& s, unsigned long long max) {
KJ_REQUIRE(s != nullptr, "String does not contain valid number", s);
KJ_REQUIRE(s != nullptr, "String does not contain valid number", s) { return 0; }
char *endPtr;
errno = 0;
auto value = strtoull(s.begin(), &endPtr, isHex(s.cStr()) ? 16 : 10);
KJ_REQUIRE(endPtr == s.end(), "String does not contain valid number", s);
KJ_REQUIRE(errno != ERANGE, "Value out-of-range", s);
KJ_REQUIRE(value <= max, "Value out-of-range", value, max);
KJ_REQUIRE(s[0] != '-', "Value out-of-range", s); //strtoull("-1") does not fail with ERANGE
KJ_REQUIRE(endPtr == s.end(), "String does not contain valid number", s) { return 0; }
KJ_REQUIRE(errno != ERANGE, "Value out-of-range", s) { return 0; }
KJ_REQUIRE(value <= max, "Value out-of-range", value, max) { return 0; }
//strtoull("-1") does not fail with ERANGE
KJ_REQUIRE(s[0] != '-', "Value out-of-range", s) { return 0; }
return value;
}
......@@ -75,11 +76,11 @@ T parseInteger(const StringPtr& s) {
}
double parseDouble(const StringPtr& s) {
KJ_REQUIRE(s != nullptr, "String does not contain valid number", s);
KJ_REQUIRE(s != nullptr, "String does not contain valid number", s) { return 0; }
char *endPtr;
errno = 0;
auto value = strtod(s.begin(), &endPtr);
KJ_REQUIRE(endPtr == s.end(), "String does not contain valid floating number", s);
KJ_REQUIRE(endPtr == s.end(), "String does not contain valid floating number", s) { return 0; }
return value;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment