diff options
author | Andy Schwerin <schwerin@10gen.com> | 2013-03-04 10:08:41 -0500 |
---|---|---|
committer | Andy Schwerin <schwerin@10gen.com> | 2013-03-11 13:40:23 -0400 |
commit | 3e77e29635c719fecec008c15542fee68d50a4ce (patch) | |
tree | 398dfb992bd55859c90a0b91e719a99239e419aa /src/mongo/base | |
parent | d36db8ac30a56d39f4af58e573ee417450798c96 (diff) | |
download | mongo-3e77e29635c719fecec008c15542fee68d50a4ce.tar.gz |
Implement parseNumberFromStringWithBase<double>().
Diffstat (limited to 'src/mongo/base')
-rw-r--r-- | src/mongo/base/parse_number.cpp | 31 | ||||
-rw-r--r-- | src/mongo/base/parse_number_test.cpp | 64 |
2 files changed, 95 insertions, 0 deletions
diff --git a/src/mongo/base/parse_number.cpp b/src/mongo/base/parse_number.cpp index 775727d7337..3c84845a788 100644 --- a/src/mongo/base/parse_number.cpp +++ b/src/mongo/base/parse_number.cpp @@ -15,6 +15,8 @@ #include "mongo/base/parse_number.h" +#include <cerrno> +#include <cstdlib> #include <limits> #include "mongo/platform/cstdint.h" @@ -181,5 +183,34 @@ namespace mongo { DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned int) DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(int8_t); DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(uint8_t); +#undef DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE + + template <> + Status parseNumberFromStringWithBase<double>(const StringData& stringValue, + int base, + double* result) { + if (base != 0) { + return Status(ErrorCodes::BadValue, + "Must pass 0 as base to parseNumberFromStringWithBase<double>."); + } + if (stringValue.empty()) + return Status(ErrorCodes::FailedToParse, "Empty string"); + + if (isspace(stringValue[0])) + return Status(ErrorCodes::FailedToParse, "Leading whitespace"); + + std::string str = stringValue.toString(); + const char* cStr = str.c_str(); + char* endp; + errno = 0; + double d = strtod(cStr, &endp); + int actualErrno = errno; + if (endp != stringValue.size() + cStr) + return Status(ErrorCodes::FailedToParse, "Did not consume whole number."); + if (actualErrno == ERANGE) + return Status(ErrorCodes::FailedToParse, "Out of range"); + *result = d; + return Status::OK(); + } } // namespace mongo diff --git a/src/mongo/base/parse_number_test.cpp b/src/mongo/base/parse_number_test.cpp index e18066b742d..3a775f1878a 100644 --- a/src/mongo/base/parse_number_test.cpp +++ b/src/mongo/base/parse_number_test.cpp @@ -222,5 +222,69 @@ namespace { ASSERT_PARSES(uint8_t, std::string(mongoutils::str::stream() << i), i); } + TEST(Double, TestRejectingBadBases) { + double ignored; + + // Only supported base for parseNumberFromStringWithBase<double> is 0. + ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", -1, &ignored)); + ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 1, &ignored)); + ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 8, &ignored)); + ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 10, &ignored)); + ASSERT_EQUALS(ErrorCodes::BadValue, parseNumberFromStringWithBase("0", 16, &ignored)); + } + + TEST(Double, TestParsingGarbage) { + double d; + CommonNumberParsingTests<double>::TestParsingGarbage(); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1.0.1", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1.0-1", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>(" 1.0", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1.0P4", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1e6 ", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>(" 1e6", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("1e6 ", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>(" 1e6", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString<double>("0xabcab.defPa", &d)); + } + + TEST(Double, TestParsingOverflow) { + double d; + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1e309", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-1e309", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("1e-309", &d)); + ASSERT_EQUALS(ErrorCodes::FailedToParse, parseNumberFromString("-1e-309", &d)); + } + + TEST(Double, TestParsingNan) { + double d = 0; + ASSERT_OK(parseNumberFromString("NaN", &d)); + ASSERT_TRUE(isnan(d)); + } + + TEST(Double, TestParsingInfinity) { + double d = 0; + ASSERT_OK(parseNumberFromString("infinity", &d)); + ASSERT_TRUE(isinf(d)); + d = 0; + ASSERT_OK(parseNumberFromString("-Infinity", &d)); + ASSERT_TRUE(isinf(d)); + } + + TEST(Double, TestParsingNormal) { + ASSERT_PARSES(double, "10", 10); + ASSERT_PARSES(double, "0", 0); + ASSERT_PARSES(double, "1", 1); + ASSERT_PARSES(double, "0xff", 0xff); + ASSERT_PARSES(double, "-10", -10); + ASSERT_PARSES(double, "-0xff", -0xff); + + ASSERT_PARSES(double, "1e8", 1e8); + ASSERT_PARSES(double, "1e-8", 1e-8); + ASSERT_PARSES(double, "12e-8", 12e-8); + ASSERT_PARSES(double, "-485.381e-8", -485.381e-8); + + ASSERT_PARSES(double, "0xabcab.defdefP-10", 0xabcab.defdefP-10); + } + } // namespace } // namespace mongo |