blob: 45d0adffb6345cae30f8825662aa48b469792fb2 [file] [log] [blame]
eroman94e42f52016-03-23 22:07:081// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/base/parse_number.h"
6
eromanae40d9ba2016-04-11 18:40:267#include <limits>
8#include <sstream>
9
10#include "base/strings/string_number_conversions.h"
eroman94e42f52016-03-23 22:07:0811#include "testing/gtest/include/gtest/gtest.h"
12
13namespace net {
14namespace {
15
eromanae40d9ba2016-04-11 18:40:2616template <typename T>
17std::string ToString(T number) {
18 // TODO(eroman): Just use std::to_string() instead (Currently chromium's
19 // C++11 guide hasn't taken a stance on it).
20 std::stringstream s;
21 s << number;
22 return s.str();
23}
eroman94e42f52016-03-23 22:07:0824
eromanae40d9ba2016-04-11 18:40:2625// Returns a decimal string that is one larger than the maximum value that type
26// T can represent.
27template <typename T>
28std::string CreateOverflowString() {
29 const T value = std::numeric_limits<T>::max();
30 std::string result = ToString(value);
31 EXPECT_NE('9', result.back());
32 result.back()++;
33 return result;
34}
35
36// Returns a decimal string that is one less than the minimum value that
37// (signed) type T can represent.
38template <typename T>
39std::string CreateUnderflowString() {
40 EXPECT_TRUE(std::numeric_limits<T>::is_signed);
41 const T value = std::numeric_limits<T>::min();
42 std::string result = ToString(value);
43 EXPECT_EQ('-', result.front());
44 EXPECT_NE('9', result.back());
45 result.back()++;
46 return result;
47}
48
49// These are valid inputs representing non-negative integers. Note that these
50// test inputs are re-used when constructing negative test cases, by simply
51// prepending a '-'.
52const struct {
53 const char* input;
54 int expected_output;
55} kValidNonNegativeTests[] = {
56 {"0", 0}, {"00000", 0}, {"003", 3}, {"003", 3}, {"1234566", 1234566},
57 {"987", 987}, {"010", 10},
58};
59
60// These are invalid inputs that can not be parsed regardless of the format
61// used (they are neither valid negative or non-negative values).
62const char* kInvalidParseTests[] = {
63 "", "-", "--", "23-", "134-34", "- ", " ", "+42",
64 " 123", "123 ", "123\n", "0xFF", "-0xFF", "0x11", "-0x11", "x11",
65 "-x11", "F11", "-F11", "AF", "-AF", "0AF", "0.0", "13.",
66 "13,000", "13.000", "13/5", "Inf", "NaN", "null", "dog",
67};
68
69// This wrapper calls func() and expects the result to match |expected_output|.
70template <typename OutputType, typename ParseFunc, typename ExpectationType>
71void ExpectParseIntSuccess(ParseFunc func,
72 const base::StringPiece& input,
73 ParseIntFormat format,
74 ExpectationType expected_output) {
75 // Try parsing without specifying an error output - expecting success.
76 OutputType parsed_number1;
77 EXPECT_TRUE(func(input, format, &parsed_number1, nullptr))
78 << "Failed to parse: " << input;
79 EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number1);
80
81 // Try parsing with an error output - expecting success.
82 ParseIntError kBogusError = static_cast<ParseIntError>(19);
83 ParseIntError error = kBogusError;
84 OutputType parsed_number2;
85 EXPECT_TRUE(func(input, format, &parsed_number2, &error))
86 << "Failed to parse: " << input;
87 EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number2);
88 // Check that the error output was not written to.
89 EXPECT_EQ(kBogusError, error);
90}
91
92// This wrapper calls func() and expects the failure to match |expected_error|.
93template <typename OutputType, typename ParseFunc>
94void ExpectParseIntFailure(ParseFunc func,
95 const base::StringPiece& input,
96 ParseIntFormat format,
97 ParseIntError expected_error) {
98 const OutputType kBogusOutput(23614);
99
100 // Try parsing without specifying an error output - expecting failure.
101 OutputType parsed_number1 = kBogusOutput;
102 EXPECT_FALSE(func(input, format, &parsed_number1, nullptr))
103 << "Succeded parsing: " << input;
104 EXPECT_EQ(kBogusOutput, parsed_number1)
105 << "Modified output when failed parsing";
106
107 // Try parsing with an error output - expecting failure.
108 OutputType parsed_number2 = kBogusOutput;
109 ParseIntError error;
110 EXPECT_FALSE(func(input, format, &parsed_number2, &error))
111 << "Succeded parsing: " << input;
112 EXPECT_EQ(kBogusOutput, parsed_number2)
113 << "Modified output when failed parsing";
114 EXPECT_EQ(expected_error, error);
115}
116
117// Common tests for both ParseInt*() and ParseUint*()
118//
119// When testing ParseUint*() the |format| parameter is not applicable and
120// should be passed as NON_NEGATIVE.
121template <typename T, typename ParseFunc>
122void TestParseIntUsingFormat(ParseFunc func, ParseIntFormat format) {
123 // Test valid non-negative inputs
124 for (const auto& test : kValidNonNegativeTests) {
125 ExpectParseIntSuccess<T>(func, test.input, format, test.expected_output);
126 }
127
128 // Test invalid inputs (invalid regardless of parsing format)
vmpstr6f21f242016-06-29 02:16:47129 for (auto* input : kInvalidParseTests) {
eromanae40d9ba2016-04-11 18:40:26130 ExpectParseIntFailure<T>(func, input, format, ParseIntError::FAILED_PARSE);
131 }
132
133 // Test valid negative inputs (constructed from the valid non-negative test
134 // cases).
135 for (const auto& test : kValidNonNegativeTests) {
136 std::string negative_input = std::string("-") + test.input;
137 int expected_negative_output = -test.expected_output;
138
139 // The result depends on the format.
140 if (format == ParseIntFormat::NON_NEGATIVE) {
141 ExpectParseIntFailure<T>(func, negative_input, format,
142 ParseIntError::FAILED_PARSE);
143 } else {
144 ExpectParseIntSuccess<T>(func, negative_input, format,
145 expected_negative_output);
146 }
147 }
148
149 // Test parsing the largest possible value for output type.
150 {
151 const T value = std::numeric_limits<T>::max();
152 ExpectParseIntSuccess<T>(func, ToString(value), format, value);
153 }
154
155 // Test parsing a number one larger than the output type can accomodate
156 // (overflow).
157 ExpectParseIntFailure<T>(func, CreateOverflowString<T>(), format,
158 ParseIntError::FAILED_OVERFLOW);
159
160 // Test parsing a number at least as large as the output allows AND contains
161 // garbage at the end. This exercises an interesting internal quirk of
162 // base::StringToInt*(), in that its result cannot distinguish this case
163 // from overflow.
164 ExpectParseIntFailure<T>(func, ToString(std::numeric_limits<T>::max()) + " ",
165 format, ParseIntError::FAILED_PARSE);
166
167 ExpectParseIntFailure<T>(func, CreateOverflowString<T>() + " ", format,
168 ParseIntError::FAILED_PARSE);
169
170 // Test parsing the smallest possible value for output type. Don't do the
171 // test for unsigned types since the smallest number 0 is tested elsewhere.
172 if (std::numeric_limits<T>::is_signed) {
173 const T value = std::numeric_limits<T>::min();
174 std::string str_value = ToString(value);
175
176 // The minimal value is necessarily negative, since this function is
177 // testing only signed output types.
178 if (format == ParseIntFormat::NON_NEGATIVE) {
179 ExpectParseIntFailure<T>(func, str_value, format,
180 ParseIntError::FAILED_PARSE);
181 } else {
182 ExpectParseIntSuccess<T>(func, str_value, format, value);
183 }
184 }
185
186 // Test parsing a number one less than the output type can accomodate
187 // (underflow).
188 if (format == ParseIntFormat::OPTIONALLY_NEGATIVE) {
189 ExpectParseIntFailure<T>(func, CreateUnderflowString<T>(),
190 ParseIntFormat::OPTIONALLY_NEGATIVE,
191 ParseIntError::FAILED_UNDERFLOW);
192 }
193
194 // Test parsing a string that contains a valid number followed by a NUL
195 // character.
196 ExpectParseIntFailure<T>(func, base::StringPiece("123\0", 4), format,
197 ParseIntError::FAILED_PARSE);
198}
199
200// Common tests to run for each of the versions of ParseInt*().
201//
202// The |func| parameter should be a function pointer to the particular
203// ParseInt*() function to test.
204template <typename T, typename ParseFunc>
205void TestParseInt(ParseFunc func) {
206 // Test using each of the possible formats.
207 ParseIntFormat kFormats[] = {ParseIntFormat::NON_NEGATIVE,
208 ParseIntFormat::OPTIONALLY_NEGATIVE};
209
210 for (const auto& format : kFormats) {
211 TestParseIntUsingFormat<T>(func, format);
eroman94e42f52016-03-23 22:07:08212 }
213}
214
eromanae40d9ba2016-04-11 18:40:26215// Common tests to run for each of the versions of ParseUint*().
216//
217// The |func| parameter should be a function pointer to the particular
218// ParseUint*() function to test.
219template <typename T, typename ParseFunc>
220void TestParseUint(ParseFunc func) {
221 // TestParseIntUsingFormat() expects a functor that has a |format|
222 // parameter. For ParseUint*() there is no such parameter. For all intents
223 // and purposes can just fix it to NON_NEGATIVE and re-use that test driver.
224 auto func_adapter = [&func](const base::StringPiece& input,
225 ParseIntFormat format, T* output,
226 ParseIntError* optional_error) {
227 EXPECT_EQ(ParseIntFormat::NON_NEGATIVE, format);
228 return func(input, output, optional_error);
eroman94e42f52016-03-23 22:07:08229 };
230
eromanae40d9ba2016-04-11 18:40:26231 TestParseIntUsingFormat<T>(func_adapter, ParseIntFormat::NON_NEGATIVE);
eroman94e42f52016-03-23 22:07:08232}
233
eromanae40d9ba2016-04-11 18:40:26234TEST(ParseNumberTest, ParseInt32) {
235 TestParseInt<int32_t>(ParseInt32);
236}
237
238TEST(ParseNumberTest, ParseInt64) {
239 TestParseInt<int64_t>(ParseInt64);
240}
241
242TEST(ParseNumberTest, ParseUint32) {
243 TestParseUint<uint32_t>(ParseUint32);
244}
245
246TEST(ParseNumberTest, ParseUint64) {
247 TestParseUint<uint64_t>(ParseUint64);
eroman94e42f52016-03-23 22:07:08248}
249
250} // namespace
251} // namespace net