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

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: improve comments 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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698