#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 {
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;
}
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;
}
const struct {
const char* input;
int expected_output;
bool is_non_negative;
bool is_strict;
} kAnnotatedTests[] = {
{"0", 0, true, true},
{"10", 10, true, true},
{"1234566", 1234566, true, true},
{"00", 0, true, false},
{"010", 10, true, false},
{"0010", 10, true, false},
{"-10", -10, false, true},
{"-1234566", -1234566, false, true},
{"-0", 0, false, false},
{"-00", 0, false, false},
{"-010", -10, false, false},
{"-0000000000000000000000000000000000001234566", -1234566,
false, false},
};
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",
};
template <typename OutputType, typename ParseFunc, typename ExpectationType>
void ExpectParseIntSuccess(ParseFunc func,
base::StringPiece input,
ParseIntFormat format,
ExpectationType expected_output) {
OutputType parsed_number1;
EXPECT_TRUE(func(input, format, &parsed_number1, nullptr))
<< "Failed to parse: " << input;
EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number1);
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);
EXPECT_EQ(kBogusError, error);
}
template <typename OutputType, typename ParseFunc>
void ExpectParseIntFailure(ParseFunc func,
base::StringPiece input,
ParseIntFormat format,
ParseIntError expected_error) {
const OutputType kBogusOutput(23614);
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";
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);
}
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;
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);
}
}
for (auto* input : kInvalidParseTests) {
ExpectParseIntFailure<T>(func, input, format, ParseIntError::FAILED_PARSE);
}
{
const T value = std::numeric_limits<T>::max();
ExpectParseIntSuccess<T>(func, base::NumberToString(value), format, value);
}
ExpectParseIntFailure<T>(func, CreateOverflowString<T>(), format,
ParseIntError::FAILED_OVERFLOW);
ExpectParseIntFailure<T>(
func, base::NumberToString(std::numeric_limits<T>::max()) + " ", format,
ParseIntError::FAILED_PARSE);
ExpectParseIntFailure<T>(func, CreateOverflowString<T>() + " ", format,
ParseIntError::FAILED_PARSE);
if (std::numeric_limits<T>::is_signed) {
const T value = std::numeric_limits<T>::min();
std::string str_value = base::NumberToString(value);
if (is_format_non_negative) {
ExpectParseIntFailure<T>(func, str_value, format,
ParseIntError::FAILED_PARSE);
} else {
ExpectParseIntSuccess<T>(func, str_value, format, value);
}
}
if (!is_format_non_negative) {
ExpectParseIntFailure<T>(func, CreateUnderflowString<T>(), format,
ParseIntError::FAILED_UNDERFLOW);
}
ExpectParseIntFailure<T>(func, base::StringPiece("123\0", 4), format,
ParseIntError::FAILED_PARSE);
}
template <typename T, typename ParseFunc>
void TestParseInt(ParseFunc func) {
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);
}
}
template <typename T, typename ParseFunc>
void TestParseUint(ParseFunc func) {
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);
}
}
}