Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Side by Side Diff: net/base/parse_number_unittest.cc

Issue 1828103002: Extend net/base/parse_number.h for parsing of negative numbers, and determining if there was overflo (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@proxy_num
Patch Set: remove commentary on size_t... will shave that yak another time Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
13 const struct { 16 // increment a numeric string (flawed, but good enough for use case).
14 const char* input; 17 std::string IncrementLastChar(std::string value) {
15 int output; 18 value[value.size() - 1]++;
16 } kTests[] = { 19 return value;
17 {"0", 0}, {"00000", 0}, {"003", 3}, {"003", 3}, {"1234566", 1234566}, 20 }
18 {"987", 987}, {"010", 10}, 21
19 }; 22 // These are valid inputs representing non-negative integers. Note that these
20 23 // test inputs are re-used when constructing negative test cases, by simply
21 for (const auto& test : kTests) { 24 // prepending a '-'.
22 int result; 25 const struct {
23 ASSERT_TRUE(ParseNonNegativeDecimalInt(test.input, &result)) 26 const char* input;
24 << "Failed to parse: " << test.input; 27 int expected_output;
25 EXPECT_EQ(result, test.output) << "Failed to parse: " << test.input; 28 } kValidNonNegativeTests[] = {
26 } 29 {"0", 0}, {"00000", 0}, {"003", 3}, {"003", 3}, {"1234566", 1234566},
27 } 30 {"987", 987}, {"010", 10},
28 31 };
29 TEST(ParseNumberTest, IntInvalidInputs) { 32
30 const char* kTests[] = { 33 // These are invalid inputs that can not be parsed regardless of the format
31 "", 34 // used (they are neither valid negative or non-negative values).
32 "-23", 35 const char* kInvalidParseTests[] = {
33 "+42", 36 "", "-", "--", "23-", "134-34", "- ", " ", "+42",
34 " 123", 37 " 123", "123 ", "123\n", "0xFF", "-0xFF", "0x11", "-0x11", "x11",
35 "123 ", 38 "-x11", "F11", "-F11", "AF", "-AF", "0AF", "0.0", "13.",
36 "123\n", 39 "13,000", "13.000", "13/5", "Inf", "NaN", "null", "dog",
37 "0xFF", 40 };
38 "0x11", 41
39 "x11", 42 // This wrapper calls func() and expects the result to match |expected_output|.
40 "F11", 43 template <typename OutputType, typename ParseFunc, typename ExpectationType>
41 "AF", 44 void ExpectParseIntSuccess(ParseFunc func,
42 "0AF", 45 const base::StringPiece& input,
43 "0.0", 46 ParseIntFormat format,
44 "13.", 47 ExpectationType expected_output) {
45 "13,000", 48 // Try parsing without specifying an error output - expecting success.
46 "13.000", 49 OutputType parsed_number1;
47 "13/5", 50 EXPECT_TRUE(func(input, format, &parsed_number1, nullptr))
48 "9999999999999999999999999999999999999999999999999999999999999999", 51 << "Failed to parse: " << input;
49 "Inf", 52 EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number1);
50 "NaN", 53
51 "null", 54 // Try parsing with an error output - expecting success.
52 "dog", 55 ParseIntError kBogusError = static_cast<ParseIntError>(19);
53 }; 56 ParseIntError error = kBogusError;
54 57 OutputType parsed_number2;
55 for (const auto& input : kTests) { 58 EXPECT_TRUE(func(input, format, &parsed_number2, &error))
56 int result = 0xDEAD; 59 << "Failed to parse: " << input;
57 ASSERT_FALSE(ParseNonNegativeDecimalInt(input, &result)) 60 EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number2);
58 << "Succeeded to parse: " << input; 61 // Check that the error output was not written to.
59 EXPECT_EQ(0xDEAD, result) << "Modified output for failed parsing"; 62 EXPECT_EQ(kBogusError, error);
60 } 63 }
61 } 64
62 65 // This wrapper calls func() and expects the failure to match |expected_error|.
63 TEST(ParseNumberTest, IntInvalidInputsContainsNul) { 66 template <typename OutputType, typename ParseFunc>
64 int result = 0xDEAD; 67 void ExpectParseIntFailure(ParseFunc func,
65 ASSERT_FALSE( 68 const base::StringPiece& input,
66 ParseNonNegativeDecimalInt(base::StringPiece("123\0", 4), &result)); 69 ParseIntFormat format,
67 EXPECT_EQ(0xDEAD, result); 70 ParseIntError expected_error) {
71 const OutputType kBogusOutput = OutputType(23614);
mmenke 2016/04/07 20:42:53 Is the OutputType(...) needed? Not entirely sure
eroman 2016/04/08 18:57:32 Done.
72
73 // Try parsing without specifying an error output - expecting failure.
74 OutputType parsed_number1 = kBogusOutput;
75 EXPECT_FALSE(func(input, format, &parsed_number1, nullptr))
76 << "Succeded parsing: " << input;
77 EXPECT_EQ(kBogusOutput, parsed_number1)
78 << "Modified output when failed parsing";
79
80 // Try parsing with an error output - expecting failure.
81 OutputType parsed_number2 = kBogusOutput;
82 ParseIntError error;
83 EXPECT_FALSE(func(input, format, &parsed_number2, &error))
84 << "Succeded parsing: " << input;
85 EXPECT_EQ(kBogusOutput, parsed_number2)
86 << "Modified output when failed parsing";
87 EXPECT_EQ(expected_error, error);
88 }
89
90 // Common tests to run for each of the versions of ParseInt*().
91 template <typename T, typename ParseFunc>
92 void TestParseInt(ParseFunc func) {
93 ParseIntFormat kFormats[] = {ParseIntFormat::NON_NEGATIVE,
94 ParseIntFormat::OPTIONALLY_NEGATIVE};
95
96 // Test valid non-negative inputs
97
98 for (const auto& format : kFormats) {
99 for (const auto& test : kValidNonNegativeTests) {
100 ExpectParseIntSuccess<T>(func, test.input, format, test.expected_output);
101 }
102 }
103
104 // Test invalid inputs (invalid regardless of parsing format)
105
106 for (const auto& format : kFormats) {
107 for (const auto& input : kInvalidParseTests) {
108 ExpectParseIntFailure<T>(func, input, format,
109 ParseIntError::FAILED_PARSE);
110 }
111 }
112
113 // Test valid negative inputs (constructed from the valid non-negative test
114 // cases).
115
116 for (const auto& format : kFormats) {
117 for (const auto& test : kValidNonNegativeTests) {
118 std::string negative_input = std::string("-") + test.input;
119 int expected_negative_output = -test.expected_output;
120
121 // The result depends on the format.
122 if (format == ParseIntFormat::NON_NEGATIVE) {
123 ExpectParseIntFailure<T>(func, negative_input, format,
124 ParseIntError::FAILED_PARSE);
125 } else {
126 ExpectParseIntSuccess<T>(func, negative_input, format,
127 expected_negative_output);
128 }
129 }
130 }
131
132 // Test parsing the largest possible value for output type.
133
134 for (const auto& format : kFormats) {
135 const T value = std::numeric_limits<T>::max();
136 ExpectParseIntSuccess<T>(func, std::to_string(value), format, value);
137 }
138
139 // Test parsing a number one larger than the output type can accomodate
140 // (overflow).
141
142 for (const auto& format : kFormats) {
143 const T value = std::numeric_limits<T>::max();
144 ExpectParseIntFailure<T>(func, IncrementLastChar(std::to_string(value)),
mmenke 2016/04/07 20:42:53 Maybe worth a comment that this works because max(
eroman 2016/04/08 18:57:32 Extracted to a more specific function. And added a
145 format, ParseIntError::FAILED_OVERFLOW);
146 }
147
148 // Test parsing a number at least as large as the output allows AND contains
149 // garbage at the end. This exercises an interesting internal quirk of
150 // base::StringToInt*(), in that its result cannot distinguish this case
151 // from overflow.
152
153 for (const auto& format : kFormats) {
154 const T value = std::numeric_limits<T>::max();
mmenke 2016/04/07 20:42:53 Should we actually make this an overflow as well?
eroman 2016/04/08 18:57:33 Done.
155 ExpectParseIntFailure<T>(func, std::to_string(value) + " ", format,
156 ParseIntError::FAILED_PARSE);
157 }
158
159 // Test parsing the smallest possible value for output type.
160
161 for (const auto& format : kFormats) {
mmenke 2016/04/07 20:42:53 optional: Rather than all these loops over format
eroman 2016/04/08 18:57:32 Done. I also re-unified the tests so there isn't a
162 const T value = std::numeric_limits<T>::min();
163 auto str_value = std::to_string(value);
mmenke 2016/04/07 20:42:53 Think it's best to just remove the auto here - thi
mmenke 2016/04/07 20:42:53 Is std::to_string allowed C++0x11?
eroman 2016/04/08 18:57:32 Done. You are right, our C++11 guide hasn't taken
164
165 // The minimal value is necessarily negative, since this function is testing
166 // only signed output types.
167 if (format == ParseIntFormat::NON_NEGATIVE) {
168 ExpectParseIntFailure<T>(func, str_value, format,
169 ParseIntError::FAILED_PARSE);
170 } else {
171 ExpectParseIntSuccess<T>(func, str_value, format, value);
172 }
173 }
174
175 // Test parsing a number one less than the output type can accomodate
176 // (underflow).
177
178 {
179 std::string str_value =
180 IncrementLastChar(std::to_string(std::numeric_limits<T>::min()));
mmenke 2016/04/07 20:42:53 Again, there's a weird dependency here...
eroman 2016/04/08 18:57:32 No longer applicable.
181
182 ExpectParseIntFailure<T>(func, str_value,
183 ParseIntFormat::OPTIONALLY_NEGATIVE,
184 ParseIntError::FAILED_UNDERFLOW);
185 }
186
187 // Test parsing a string that contains a valid number followed by a NUL
188 // character.
189
190 for (const auto& format : kFormats) {
191 ExpectParseIntFailure<T>(func, base::StringPiece("123\0", 4), format,
192 ParseIntError::FAILED_PARSE);
193 }
194 }
195
196 // This wrapper calls func() and expects the result to match |expected_output|.
197 template <typename OutputType, typename ParseFunc, typename ExpectationType>
198 void ExpectParseUintSuccess(ParseFunc func,
199 const base::StringPiece& input,
200 ExpectationType expected_output) {
201 // Try parsing without specifying an error output - expecting success.
202 OutputType parsed_number1;
203 EXPECT_TRUE(func(input, &parsed_number1, nullptr)) << "Failed to parse: "
204 << input;
205 EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number1);
206
207 // Try parsing with an error output - expecting success.
208 ParseIntError kBogusError = static_cast<ParseIntError>(19);
209 ParseIntError error = kBogusError;
210 OutputType parsed_number2;
211 EXPECT_TRUE(func(input, &parsed_number2, &error)) << "Failed to parse: "
212 << input;
213 EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number2);
214 // Check that the error output was not written to.
215 EXPECT_EQ(kBogusError, error);
216 }
217
218 // This wrapper calls func() and expects the failure to match |expected_error|.
219 template <typename OutputType, typename ParseFunc>
220 void ExpectParseUintFailure(ParseFunc func,
221 const base::StringPiece& input,
222 ParseIntError expected_error) {
223 const OutputType kBogusOutput = OutputType(23614);
224
225 // Try parsing without specifying an error output - expecting failure.
226 OutputType parsed_number1 = kBogusOutput;
227 EXPECT_FALSE(func(input, &parsed_number1, nullptr)) << "Succeded parsing: "
228 << input;
229 EXPECT_EQ(kBogusOutput, parsed_number1)
230 << "Modified output when failed parsing";
231
232 // Try parsing with an error output - expecting failure.
233 OutputType parsed_number2 = kBogusOutput;
234 ParseIntError error;
235 EXPECT_FALSE(func(input, &parsed_number2, &error)) << "Succeded parsing: "
236 << input;
237 EXPECT_EQ(kBogusOutput, parsed_number2)
238 << "Modified output when failed parsing";
239 EXPECT_EQ(expected_error, error);
240 }
241
242 // Common tests to run for each of the versions of ParseUint*().
243 template <typename T, typename ParseFunc>
244 void TestParseUint(ParseFunc func) {
245 // Test valid non-negative inputs
246 for (const auto& test : kValidNonNegativeTests) {
247 ExpectParseUintSuccess<T>(func, test.input, test.expected_output);
248 }
249
250 // Test invalid inputs (invalid regardless of parsing format)
251 for (const auto& input : kInvalidParseTests) {
252 ExpectParseUintFailure<T>(func, input, ParseIntError::FAILED_PARSE);
253 }
254
255 // Test valid negative inputs (constructed from the valid non-negative test
256 // cases).
257 for (const auto& test : kValidNonNegativeTests) {
258 std::string negative_input = std::string("-") + test.input;
259
260 // The result depends on the format.
261 ExpectParseUintFailure<T>(func, negative_input,
262 ParseIntError::FAILED_PARSE);
263 }
264
265 // Test parsing the largest possible value for output type.
266 {
267 const T value = std::numeric_limits<T>::max();
268 ExpectParseUintSuccess<T>(func, std::to_string(value), value);
269 }
270
271 // Test parsing a number one larger than the output type can accomodate
272 // (overflow).
273 {
274 const T value = std::numeric_limits<T>::max();
275 ExpectParseUintFailure<T>(func, IncrementLastChar(std::to_string(value)),
276 ParseIntError::FAILED_OVERFLOW);
277 }
278
279 // Test parsing a number at least as large as the output allows AND contains
280 // garbage at the end. This exercises an interesting internal quirk of
281 // base::StringToInt*(), in that its result cannot distinguish this case
282 // from overflow.
283
284 {
285 const T value = std::numeric_limits<T>::max();
286 ExpectParseUintFailure<T>(func, std::to_string(value) + " ",
287 ParseIntError::FAILED_PARSE);
288 }
289
290 // Test parsing a string that contains a valid number followed by a NUL
291 // character.
292 ExpectParseUintFailure<T>(func, base::StringPiece("123\0", 4),
293 ParseIntError::FAILED_PARSE);
294 }
295
296 TEST(ParseNumberTest, ParseInt32) {
297 TestParseInt<int32_t>(ParseInt32);
298 }
299
300 TEST(ParseNumberTest, ParseInt64) {
301 TestParseInt<int64_t>(ParseInt64);
302 }
303
304 TEST(ParseNumberTest, ParseUint32) {
305 TestParseUint<uint32_t>(ParseUint32);
306 }
307
308 TEST(ParseNumberTest, ParseUint64) {
309 TestParseUint<uint64_t>(ParseUint64);
68 } 310 }
69 311
70 } // namespace 312 } // namespace
71 } // namespace net 313 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698