| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/base/parse_number.h" |
| |
| #include <limits> |
| #include <sstream> |
| |
| #include "base/strings/string_number_conversions.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace net { |
| namespace { |
| |
| // Returns a decimal string that is one larger than the maximum value that type |
| // T can represent. |
| template <typename T> |
| std::string CreateOverflowString() { |
| const T value = std::numeric_limits<T>::max(); |
| std::string result = base::NumberToString(value); |
| EXPECT_NE('9', result.back()); |
| result.back()++; |
| return result; |
| } |
| |
| // Returns a decimal string that is one less than the minimum value that |
| // (signed) type T can represent. |
| template <typename T> |
| std::string CreateUnderflowString() { |
| EXPECT_TRUE(std::numeric_limits<T>::is_signed); |
| const T value = std::numeric_limits<T>::min(); |
| std::string result = base::NumberToString(value); |
| EXPECT_EQ('-', result.front()); |
| EXPECT_NE('9', result.back()); |
| result.back()++; |
| return result; |
| } |
| |
| // These are potentially valid inputs, along with whether they're non-negative |
| // or "strict" (minimal representations). |
| const struct { |
| const char* input; |
| int expected_output; |
| bool is_non_negative; |
| bool is_strict; |
| } kAnnotatedTests[] = { |
| {"0", 0, /*is_non_negative=*/true, /*is_strict=*/true}, |
| {"10", 10, /*is_non_negative=*/true, /*is_strict=*/true}, |
| {"1234566", 1234566, /*is_non_negative=*/true, /*is_strict=*/true}, |
| {"00", 0, /*is_non_negative=*/true, /*is_strict=*/false}, |
| {"010", 10, /*is_non_negative=*/true, /*is_strict=*/false}, |
| {"0010", 10, /*is_non_negative=*/true, /*is_strict=*/false}, |
| {"-10", -10, /*is_non_negative=*/false, /*is_strict=*/true}, |
| {"-1234566", -1234566, /*is_non_negative=*/false, /*is_strict=*/true}, |
| {"-0", 0, /*is_non_negative=*/false, /*is_strict=*/false}, |
| {"-00", 0, /*is_non_negative=*/false, /*is_strict=*/false}, |
| {"-010", -10, /*is_non_negative=*/false, /*is_strict=*/false}, |
| {"-0000000000000000000000000000000000001234566", -1234566, |
| /*is_non_negative=*/false, /*is_strict=*/false}, |
| }; |
| |
| // These are invalid inputs that can not be parsed regardless of the format |
| // used (they are neither valid negative or non-negative values). |
| const char* kInvalidParseTests[] = { |
| "", "-", "--", "23-", "134-34", "- ", " ", "+42", |
| " 123", "123 ", "123\n", "0xFF", "-0xFF", "0x11", "-0x11", "x11", |
| "-x11", "F11", "-F11", "AF", "-AF", "0AF", "0.0", "13.", |
| "13,000", "13.000", "13/5", "Inf", "NaN", "null", "dog", |
| }; |
| |
| // This wrapper calls func() and expects the result to match |expected_output|. |
| template <typename OutputType, typename ParseFunc, typename ExpectationType> |
| void ExpectParseIntSuccess(ParseFunc func, |
| base::StringPiece input, |
| ParseIntFormat format, |
| ExpectationType expected_output) { |
| // Try parsing without specifying an error output - expecting success. |
| OutputType parsed_number1; |
| EXPECT_TRUE(func(input, format, &parsed_number1, nullptr)) |
| << "Failed to parse: " << input; |
| EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number1); |
| |
| // Try parsing with an error output - expecting success. |
| ParseIntError kBogusError = static_cast<ParseIntError>(19); |
| ParseIntError error = kBogusError; |
| OutputType parsed_number2; |
| EXPECT_TRUE(func(input, format, &parsed_number2, &error)) |
| << "Failed to parse: " << input; |
| EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number2); |
| // Check that the error output was not written to. |
| EXPECT_EQ(kBogusError, error); |
| } |
| |
| // This wrapper calls func() and expects the failure to match |expected_error|. |
| template <typename OutputType, typename ParseFunc> |
| void ExpectParseIntFailure(ParseFunc func, |
| base::StringPiece input, |
| ParseIntFormat format, |
| ParseIntError expected_error) { |
| const OutputType kBogusOutput(23614); |
| |
| // Try parsing without specifying an error output - expecting failure. |
| OutputType parsed_number1 = kBogusOutput; |
| EXPECT_FALSE(func(input, format, &parsed_number1, nullptr)) |
| << "Succeded parsing: " << input; |
| EXPECT_EQ(kBogusOutput, parsed_number1) |
| << "Modified output when failed parsing"; |
| |
| // Try parsing with an error output - expecting failure. |
| OutputType parsed_number2 = kBogusOutput; |
| ParseIntError error; |
| EXPECT_FALSE(func(input, format, &parsed_number2, &error)) |
| << "Succeded parsing: " << input; |
| EXPECT_EQ(kBogusOutput, parsed_number2) |
| << "Modified output when failed parsing"; |
| EXPECT_EQ(expected_error, error); |
| } |
| |
| // Common tests for both ParseInt*() and ParseUint*() |
| // |
| // When testing ParseUint*() the |format| parameter is not applicable and |
| // should be passed as NON_NEGATIVE. |
| template <typename T, typename ParseFunc> |
| void TestParseIntUsingFormat(ParseFunc func, ParseIntFormat format) { |
| bool is_format_non_negative = format == ParseIntFormat::NON_NEGATIVE || |
| format == ParseIntFormat::STRICT_NON_NEGATIVE; |
| bool is_format_strict = format == ParseIntFormat::STRICT_NON_NEGATIVE || |
| format == ParseIntFormat::STRICT_OPTIONALLY_NEGATIVE; |
| // Test annotated inputs, some of which may not be valid inputs when parsed |
| // using `format`. |
| for (const auto& test : kAnnotatedTests) { |
| SCOPED_TRACE(test.input); |
| if ((test.is_non_negative || !is_format_non_negative) && |
| (test.is_strict || !is_format_strict)) { |
| ExpectParseIntSuccess<T>(func, test.input, format, test.expected_output); |
| } else { |
| ExpectParseIntFailure<T>(func, test.input, format, |
| ParseIntError::FAILED_PARSE); |
| } |
| } |
| |
| // Test invalid inputs (invalid regardless of parsing format) |
| for (auto* input : kInvalidParseTests) { |
| ExpectParseIntFailure<T>(func, input, format, ParseIntError::FAILED_PARSE); |
| } |
| |
| // Test parsing the largest possible value for output type. |
| { |
| const T value = std::numeric_limits<T>::max(); |
| ExpectParseIntSuccess<T>(func, base::NumberToString(value), format, value); |
| } |
| |
| // Test parsing a number one larger than the output type can accomodate |
| // (overflow). |
| ExpectParseIntFailure<T>(func, CreateOverflowString<T>(), format, |
| ParseIntError::FAILED_OVERFLOW); |
| |
| // Test parsing a number at least as large as the output allows AND contains |
| // garbage at the end. This exercises an interesting internal quirk of |
| // base::StringToInt*(), in that its result cannot distinguish this case |
| // from overflow. |
| ExpectParseIntFailure<T>( |
| func, base::NumberToString(std::numeric_limits<T>::max()) + " ", format, |
| ParseIntError::FAILED_PARSE); |
| |
| ExpectParseIntFailure<T>(func, CreateOverflowString<T>() + " ", format, |
| ParseIntError::FAILED_PARSE); |
| |
| // Test parsing the smallest possible value for output type. Don't do the |
| // test for unsigned types since the smallest number 0 is tested elsewhere. |
| if (std::numeric_limits<T>::is_signed) { |
| const T value = std::numeric_limits<T>::min(); |
| std::string str_value = base::NumberToString(value); |
| |
| // The minimal value is necessarily negative, since this function is |
| // testing only signed output types. |
| if (is_format_non_negative) { |
| ExpectParseIntFailure<T>(func, str_value, format, |
| ParseIntError::FAILED_PARSE); |
| } else { |
| ExpectParseIntSuccess<T>(func, str_value, format, value); |
| } |
| } |
| |
| // Test parsing a number one less than the output type can accomodate |
| // (underflow). |
| if (!is_format_non_negative) { |
| ExpectParseIntFailure<T>(func, CreateUnderflowString<T>(), format, |
| ParseIntError::FAILED_UNDERFLOW); |
| } |
| |
| // Test parsing a string that contains a valid number followed by a NUL |
| // character. |
| ExpectParseIntFailure<T>(func, base::StringPiece("123\0", 4), format, |
| ParseIntError::FAILED_PARSE); |
| } |
| |
| // Common tests to run for each of the versions of ParseInt*(). |
| // |
| // The `func` parameter should be a function pointer to the particular |
| // ParseInt*() function to test. |
| template <typename T, typename ParseFunc> |
| void TestParseInt(ParseFunc func) { |
| // Test using each of the possible formats. |
| ParseIntFormat kFormats[] = {ParseIntFormat::NON_NEGATIVE, |
| ParseIntFormat::OPTIONALLY_NEGATIVE, |
| ParseIntFormat::STRICT_NON_NEGATIVE, |
| ParseIntFormat::STRICT_OPTIONALLY_NEGATIVE}; |
| |
| for (const auto& format : kFormats) { |
| TestParseIntUsingFormat<T>(func, format); |
| } |
| } |
| |
| // Common tests to run for each of the versions of ParseUint*(). |
| // |
| // The `func` parameter should be a function pointer to the particular |
| // ParseUint*() function to test. |
| template <typename T, typename ParseFunc> |
| void TestParseUint(ParseFunc func) { |
| // Test using each of the possible formats. |
| ParseIntFormat kFormats[] = { |
| ParseIntFormat::NON_NEGATIVE, |
| ParseIntFormat::STRICT_NON_NEGATIVE, |
| }; |
| |
| for (const auto& format : kFormats) { |
| TestParseIntUsingFormat<T>(func, format); |
| } |
| } |
| |
| TEST(ParseNumberTest, ParseInt32) { |
| TestParseInt<int32_t>(ParseInt32); |
| } |
| |
| TEST(ParseNumberTest, ParseInt64) { |
| TestParseInt<int64_t>(ParseInt64); |
| } |
| |
| TEST(ParseNumberTest, ParseUint32) { |
| TestParseUint<uint32_t>(ParseUint32); |
| } |
| |
| TEST(ParseNumberTest, ParseUint64) { |
| TestParseUint<uint64_t>(ParseUint64); |
| } |
| |
| } // namespace |
| } // namespace net |