Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/parse_number.h" | 5 #include "net/base/parse_number.h" |
| 6 | 6 |
| 7 #include <limits> | |
| 8 | |
| 9 #include "base/strings/string_number_conversions.h" | |
| 7 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
| 8 | 11 |
| 9 namespace net { | 12 namespace net { |
| 10 namespace { | 13 namespace { |
| 11 | 14 |
| 12 TEST(ParseNumberTest, IntValidInputs) { | 15 // Increments the final character in a string by 1. Used as a simplistic way to |
| 16 // increment a numeric string (flawed, but good enough for use case). | |
| 17 std::string IncrementLastChar(std::string value) { | |
| 18 value[value.size() - 1]++; | |
| 19 return value; | |
| 20 } | |
| 21 | |
| 22 // Common tests to run for each of the overloaded versions of | |
| 23 // ParseIntegerBase10(). Most checks are the same, however there | |
| 24 // are differences based on the signedness of the output type T, | |
| 25 // and its range. | |
| 26 template <typename T> | |
| 27 void TestParseIntegerBase10() { | |
| 28 bool kAllowNegativeChoices[] = {true /*Allow negatives*/, | |
| 29 false /*Don't allow negatives*/}; | |
| 30 | |
| 31 // Arbitrary constant, used to test if failure modifies the output parameter. | |
| 32 const T kFailResult = T(23614); | |
| 33 | |
| 34 // ------------------------------------ | |
| 35 // Valid (non-negative) inputs | |
| 36 // ------------------------------------ | |
| 13 const struct { | 37 const struct { |
| 14 const char* input; | 38 const char* input; |
| 15 int output; | 39 T output; |
|
mmenke
2016/03/25 15:31:50
output -> expected_output (For all of these)?
eroman
2016/03/25 19:04:30
Done.
| |
| 16 } kTests[] = { | 40 } kValidTests[] = { |
| 17 {"0", 0}, {"00000", 0}, {"003", 3}, {"003", 3}, {"1234566", 1234566}, | 41 {"0", 0}, {"00000", 0}, {"003", 3}, {"003", 3}, {"1234566", 1234566}, |
| 18 {"987", 987}, {"010", 10}, | 42 {"987", 987}, {"010", 10}, |
| 19 }; | 43 }; |
| 20 | 44 |
| 21 for (const auto& test : kTests) { | 45 for (const auto& allow_negative : kAllowNegativeChoices) { |
| 22 int result; | 46 for (const auto& test : kValidTests) { |
| 23 ASSERT_TRUE(ParseNonNegativeDecimalInt(test.input, &result)) | 47 T result; |
| 24 << "Failed to parse: " << test.input; | 48 |
| 25 EXPECT_EQ(result, test.output) << "Failed to parse: " << test.input; | 49 EXPECT_TRUE( |
| 26 } | 50 ParseIntegerBase10(test.input, allow_negative, &result, nullptr)) |
| 27 } | 51 << "Failed to parse: " << test.input; |
|
mmenke
2016/03/25 15:31:49
I'm paranoid. Call it with a non-NULL 4th argumen
eroman
2016/03/25 19:04:30
Good idea, done.
In fact having those helpers sim
| |
| 28 | 52 |
| 29 TEST(ParseNumberTest, IntInvalidInputs) { | 53 EXPECT_EQ(result, test.output) << "Failed to parse: " << test.input; |
|
mmenke
2016/03/25 15:31:50
Expected should be first
eroman
2016/03/25 19:04:30
Done.
| |
| 30 const char* kTests[] = { | 54 } |
| 31 "", | 55 } |
| 32 "-23", | 56 |
| 33 "+42", | 57 // ------------------------------------ |
| 34 " 123", | 58 // Invalid inputs (regardless of sign policy) |
| 35 "123 ", | 59 // ------------------------------------ |
| 36 "123\n", | 60 |
| 37 "0xFF", | 61 const char* kInvalidParseTests[] = { |
| 38 "0x11", | 62 "", "-", "--", "23-", "134-34", "- ", " ", "+42", |
| 39 "x11", | 63 " 123", "123 ", "123\n", "0xFF", "-0xFF", "0x11", "-0x11", "x11", |
| 40 "F11", | 64 "-x11", "F11", "-F11", "AF", "-AF", "0AF", "0.0", "13.", |
| 41 "AF", | 65 "13,000", "13.000", "13/5", "Inf", "NaN", "null", "dog", |
| 42 "0AF", | |
| 43 "0.0", | |
| 44 "13.", | |
| 45 "13,000", | |
| 46 "13.000", | |
| 47 "13/5", | |
| 48 "9999999999999999999999999999999999999999999999999999999999999999", | |
| 49 "Inf", | |
| 50 "NaN", | |
| 51 "null", | |
| 52 "dog", | |
| 53 }; | 66 }; |
| 54 | 67 |
| 55 for (const auto& input : kTests) { | 68 for (const auto& allow_negative : kAllowNegativeChoices) { |
| 56 int result = 0xDEAD; | 69 for (const auto& input : kInvalidParseTests) { |
| 57 ASSERT_FALSE(ParseNonNegativeDecimalInt(input, &result)) | 70 T result = kFailResult; |
| 58 << "Succeeded to parse: " << input; | 71 |
| 59 EXPECT_EQ(0xDEAD, result) << "Modified output for failed parsing"; | 72 ParseIntegerError error; |
| 60 } | 73 EXPECT_FALSE(ParseIntegerBase10(input, allow_negative, &result, &error)); |
|
mmenke
2016/03/25 15:31:50
Similar to comment above, we should have failure t
eroman
2016/03/25 19:04:30
Done (the latter)
| |
| 61 } | 74 EXPECT_EQ(ParseIntegerError::FAILED_PARSE, error) |
| 62 | 75 << "Unexpected error parsing: " << input; |
| 63 TEST(ParseNumberTest, IntInvalidInputsContainsNul) { | 76 |
| 64 int result = 0xDEAD; | 77 // On failure the output should not have been changed. |
| 65 ASSERT_FALSE( | 78 EXPECT_EQ(kFailResult, result) << "Modified output for failed parsing"; |
| 66 ParseNonNegativeDecimalInt(base::StringPiece("123\0", 4), &result)); | 79 } |
| 67 EXPECT_EQ(0xDEAD, result); | 80 } |
| 81 | |
| 82 // ------------------------------------ | |
| 83 // Valid negative inputs. | |
| 84 // ------------------------------------ | |
| 85 | |
| 86 const struct { | |
| 87 const char* input; | |
| 88 int output; // Using |int| rather than T because T may be unsigned. | |
| 89 } kValidNegativeTests[] = { | |
| 90 {"-0", 0}, {"-0001", -1}, {"-134", -134}, {"-4135", -4135}, | |
| 91 }; | |
| 92 | |
| 93 for (const auto& allow_negative : kAllowNegativeChoices) { | |
| 94 for (const auto& test : kValidNegativeTests) { | |
| 95 T result = kFailResult; | |
| 96 ParseIntegerError error; | |
| 97 bool success = | |
| 98 ParseIntegerBase10(test.input, allow_negative, &result, &error); | |
| 99 | |
| 100 // The result depends on the sign policy, and the signedness of the | |
| 101 // output type. | |
| 102 if (allow_negative == false) { | |
| 103 // If non-negative numbers were requested, should result in parse | |
| 104 // failure (even for "-0" which is in some sense non-negative). | |
| 105 EXPECT_FALSE(success); | |
| 106 EXPECT_EQ(ParseIntegerError::FAILED_PARSE, error); | |
| 107 EXPECT_EQ(kFailResult, result); | |
| 108 } else if (!std::numeric_limits<T>::is_signed) { | |
| 109 // If the output type was unsigned but the the input was negative, | |
| 110 // can't have succeeded. | |
| 111 // TODO(eroman): This applies even to "-0" even though it technically | |
| 112 // could have been parsed without "underflow". This is a consequence of | |
| 113 // how base::StringToIntXXX() works for unsigned types. Meh. | |
| 114 EXPECT_FALSE(success); | |
| 115 EXPECT_EQ(ParseIntegerError::FAILED_UNDERFLOW, error); | |
| 116 EXPECT_EQ(kFailResult, result); | |
| 117 } else { | |
| 118 // Otherwise success. | |
| 119 EXPECT_TRUE(success); | |
| 120 EXPECT_EQ(test.output, static_cast<int>(result)); | |
| 121 } | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 // ------------------------------------ | |
| 126 // Parse maximal value | |
| 127 // ------------------------------------ | |
| 128 | |
| 129 for (const auto& allow_negative : kAllowNegativeChoices) { | |
| 130 const T value = std::numeric_limits<T>::max(); | |
| 131 T result; | |
| 132 EXPECT_TRUE(ParseIntegerBase10(std::to_string(value), allow_negative, | |
| 133 &result, nullptr)); | |
| 134 EXPECT_EQ(value, result); | |
| 135 } | |
| 136 | |
| 137 // ------------------------------------ | |
| 138 // Parse one beyond maximal value (overflow) | |
| 139 // ------------------------------------ | |
| 140 | |
| 141 for (const auto& allow_negative : kAllowNegativeChoices) { | |
| 142 const T value = std::numeric_limits<T>::max(); | |
| 143 T result = kFailResult; | |
| 144 ParseIntegerError error; | |
| 145 EXPECT_FALSE(ParseIntegerBase10(IncrementLastChar(std::to_string(value)), | |
| 146 allow_negative, &result, &error)); | |
| 147 EXPECT_EQ(ParseIntegerError::FAILED_OVERFLOW, error); | |
| 148 EXPECT_EQ(kFailResult, result); | |
| 149 } | |
| 150 | |
| 151 // ------------------------------------ | |
| 152 // Parse maximal value with trailing whitespace | |
| 153 // ------------------------------------ | |
| 154 | |
| 155 // base::StringToIntXXX() has weird quirks dealing with whitespace. This | |
| 156 // exercises an incorrect way to detect overflow from base::StringToInt(). | |
| 157 | |
| 158 for (const auto& allow_negative : kAllowNegativeChoices) { | |
| 159 const T value = std::numeric_limits<T>::max(); | |
| 160 T result = kFailResult; | |
| 161 ParseIntegerError error; | |
| 162 EXPECT_FALSE(ParseIntegerBase10(std::to_string(value) + " ", allow_negative, | |
| 163 &result, &error)); | |
| 164 EXPECT_EQ(ParseIntegerError::FAILED_PARSE, error); | |
| 165 EXPECT_EQ(kFailResult, result); | |
| 166 } | |
| 167 | |
| 168 // ------------------------------------ | |
| 169 // Parse minimal value | |
| 170 // ------------------------------------ | |
| 171 | |
| 172 for (const auto& allow_negative : kAllowNegativeChoices) { | |
| 173 const T value = std::numeric_limits<T>::min(); | |
| 174 T result = kFailResult; | |
| 175 ParseIntegerError error; | |
| 176 auto success = ParseIntegerBase10(std::to_string(value), allow_negative, | |
| 177 &result, &error); | |
| 178 | |
| 179 if (std::numeric_limits<T>::is_signed && !allow_negative) { | |
| 180 EXPECT_FALSE(success); | |
| 181 EXPECT_EQ(ParseIntegerError::FAILED_PARSE, error); | |
| 182 EXPECT_EQ(kFailResult, result); | |
| 183 } else { | |
| 184 EXPECT_TRUE(success); | |
| 185 EXPECT_EQ(value, result); | |
|
mmenke
2016/03/25 15:31:49
Tests in this case just seems weird...I'd skip thi
eroman
2016/03/25 19:04:30
Done.
While I was at it, I also removed duplicati
| |
| 186 } | |
| 187 } | |
| 188 | |
| 189 // ------------------------------------ | |
| 190 // Parse one less than minimal value | |
| 191 // ------------------------------------ | |
| 192 { | |
| 193 std::string value_str; | |
| 194 | |
| 195 if (std::numeric_limits<T>::is_signed) { | |
| 196 value_str = | |
| 197 IncrementLastChar(std::to_string(std::numeric_limits<T>::min())); | |
| 198 } else { | |
| 199 value_str = "-1"; | |
| 200 } | |
| 201 | |
| 202 T result = kFailResult; | |
| 203 ParseIntegerError error; | |
| 204 EXPECT_FALSE(ParseIntegerBase10(value_str, true, &result, &error)); | |
| 205 EXPECT_EQ(ParseIntegerError::FAILED_UNDERFLOW, error); | |
| 206 EXPECT_EQ(kFailResult, result); | |
| 207 } | |
| 208 | |
| 209 // ------------------------------------ | |
| 210 // Parse a value containing embedded NUL | |
| 211 // ------------------------------------ | |
| 212 | |
| 213 for (const auto& allow_negative : kAllowNegativeChoices) { | |
| 214 T result = kFailResult; | |
| 215 ParseIntegerError error; | |
| 216 ASSERT_FALSE(ParseIntegerBase10(base::StringPiece("123\0", 4), | |
| 217 allow_negative, &result, &error)); | |
| 218 EXPECT_EQ(kFailResult, result); | |
| 219 EXPECT_EQ(ParseIntegerError::FAILED_PARSE, error); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 TEST(ParseNumberTest, ParseIntegerBase10Int32) { | |
|
mmenke
2016/03/25 15:31:49
I guess TEST_P can't handle templates?
eroman
2016/03/25 19:04:29
I couldn't figure out how to make TEST_P handle th
| |
| 224 TestParseIntegerBase10<int32_t>(); | |
| 225 } | |
| 226 | |
| 227 TEST(ParseNumberTest, ParseIntegerBase10Uint32) { | |
| 228 TestParseIntegerBase10<uint32_t>(); | |
| 229 } | |
| 230 | |
| 231 TEST(ParseNumberTest, ParseIntegerBase10Int64) { | |
| 232 TestParseIntegerBase10<int64_t>(); | |
| 233 } | |
| 234 | |
| 235 TEST(ParseNumberTest, ParseIntegerBase10Uint64) { | |
| 236 TestParseIntegerBase10<uint64_t>(); | |
| 68 } | 237 } |
| 69 | 238 |
| 70 } // namespace | 239 } // namespace |
| 71 } // namespace net | 240 } // namespace net |
| OLD | NEW |