xref: /aosp_15_r20/external/cronet/net/base/parse_number_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2016 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/base/parse_number.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <limits>
8*6777b538SAndroid Build Coastguard Worker #include <sstream>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
11*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker namespace net {
14*6777b538SAndroid Build Coastguard Worker namespace {
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker // Returns a decimal string that is one larger than the maximum value that type
17*6777b538SAndroid Build Coastguard Worker // T can represent.
18*6777b538SAndroid Build Coastguard Worker template <typename T>
CreateOverflowString()19*6777b538SAndroid Build Coastguard Worker std::string CreateOverflowString() {
20*6777b538SAndroid Build Coastguard Worker   const T value = std::numeric_limits<T>::max();
21*6777b538SAndroid Build Coastguard Worker   std::string result = base::NumberToString(value);
22*6777b538SAndroid Build Coastguard Worker   EXPECT_NE('9', result.back());
23*6777b538SAndroid Build Coastguard Worker   result.back()++;
24*6777b538SAndroid Build Coastguard Worker   return result;
25*6777b538SAndroid Build Coastguard Worker }
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker // Returns a decimal string that is one less than the minimum value that
28*6777b538SAndroid Build Coastguard Worker // (signed) type T can represent.
29*6777b538SAndroid Build Coastguard Worker template <typename T>
CreateUnderflowString()30*6777b538SAndroid Build Coastguard Worker std::string CreateUnderflowString() {
31*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(std::numeric_limits<T>::is_signed);
32*6777b538SAndroid Build Coastguard Worker   const T value = std::numeric_limits<T>::min();
33*6777b538SAndroid Build Coastguard Worker   std::string result = base::NumberToString(value);
34*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ('-', result.front());
35*6777b538SAndroid Build Coastguard Worker   EXPECT_NE('9', result.back());
36*6777b538SAndroid Build Coastguard Worker   result.back()++;
37*6777b538SAndroid Build Coastguard Worker   return result;
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker 
40*6777b538SAndroid Build Coastguard Worker // These are potentially valid inputs, along with whether they're non-negative
41*6777b538SAndroid Build Coastguard Worker // or "strict" (minimal representations).
42*6777b538SAndroid Build Coastguard Worker const struct {
43*6777b538SAndroid Build Coastguard Worker   const char* input;
44*6777b538SAndroid Build Coastguard Worker   int expected_output;
45*6777b538SAndroid Build Coastguard Worker   bool is_non_negative;
46*6777b538SAndroid Build Coastguard Worker   bool is_strict;
47*6777b538SAndroid Build Coastguard Worker } kAnnotatedTests[] = {
48*6777b538SAndroid Build Coastguard Worker     {"0", 0, /*is_non_negative=*/true, /*is_strict=*/true},
49*6777b538SAndroid Build Coastguard Worker     {"10", 10, /*is_non_negative=*/true, /*is_strict=*/true},
50*6777b538SAndroid Build Coastguard Worker     {"1234566", 1234566, /*is_non_negative=*/true, /*is_strict=*/true},
51*6777b538SAndroid Build Coastguard Worker     {"00", 0, /*is_non_negative=*/true, /*is_strict=*/false},
52*6777b538SAndroid Build Coastguard Worker     {"010", 10, /*is_non_negative=*/true, /*is_strict=*/false},
53*6777b538SAndroid Build Coastguard Worker     {"0010", 10, /*is_non_negative=*/true, /*is_strict=*/false},
54*6777b538SAndroid Build Coastguard Worker     {"-10", -10, /*is_non_negative=*/false, /*is_strict=*/true},
55*6777b538SAndroid Build Coastguard Worker     {"-1234566", -1234566, /*is_non_negative=*/false, /*is_strict=*/true},
56*6777b538SAndroid Build Coastguard Worker     {"-0", 0, /*is_non_negative=*/false, /*is_strict=*/false},
57*6777b538SAndroid Build Coastguard Worker     {"-00", 0, /*is_non_negative=*/false, /*is_strict=*/false},
58*6777b538SAndroid Build Coastguard Worker     {"-010", -10, /*is_non_negative=*/false, /*is_strict=*/false},
59*6777b538SAndroid Build Coastguard Worker     {"-0000000000000000000000000000000000001234566", -1234566,
60*6777b538SAndroid Build Coastguard Worker      /*is_non_negative=*/false, /*is_strict=*/false},
61*6777b538SAndroid Build Coastguard Worker };
62*6777b538SAndroid Build Coastguard Worker 
63*6777b538SAndroid Build Coastguard Worker // These are invalid inputs that can not be parsed regardless of the format
64*6777b538SAndroid Build Coastguard Worker // used (they are neither valid negative or non-negative values).
65*6777b538SAndroid Build Coastguard Worker const char* kInvalidParseTests[] = {
66*6777b538SAndroid Build Coastguard Worker     "",       "-",      "--",    "23-",  "134-34", "- ",   "    ",  "+42",
67*6777b538SAndroid Build Coastguard Worker     " 123",   "123 ",   "123\n", "0xFF", "-0xFF",  "0x11", "-0x11", "x11",
68*6777b538SAndroid Build Coastguard Worker     "-x11",   "F11",    "-F11",  "AF",   "-AF",    "0AF",  "0.0",   "13.",
69*6777b538SAndroid Build Coastguard Worker     "13,000", "13.000", "13/5",  "Inf",  "NaN",    "null", "dog",
70*6777b538SAndroid Build Coastguard Worker };
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker // This wrapper calls func() and expects the result to match |expected_output|.
73*6777b538SAndroid Build Coastguard Worker template <typename OutputType, typename ParseFunc, typename ExpectationType>
ExpectParseIntSuccess(ParseFunc func,std::string_view input,ParseIntFormat format,ExpectationType expected_output)74*6777b538SAndroid Build Coastguard Worker void ExpectParseIntSuccess(ParseFunc func,
75*6777b538SAndroid Build Coastguard Worker                            std::string_view input,
76*6777b538SAndroid Build Coastguard Worker                            ParseIntFormat format,
77*6777b538SAndroid Build Coastguard Worker                            ExpectationType expected_output) {
78*6777b538SAndroid Build Coastguard Worker   // Try parsing without specifying an error output - expecting success.
79*6777b538SAndroid Build Coastguard Worker   OutputType parsed_number1;
80*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(func(input, format, &parsed_number1, nullptr))
81*6777b538SAndroid Build Coastguard Worker       << "Failed to parse: " << input;
82*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number1);
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   // Try parsing with an error output - expecting success.
85*6777b538SAndroid Build Coastguard Worker   ParseIntError kBogusError = static_cast<ParseIntError>(19);
86*6777b538SAndroid Build Coastguard Worker   ParseIntError error = kBogusError;
87*6777b538SAndroid Build Coastguard Worker   OutputType parsed_number2;
88*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(func(input, format, &parsed_number2, &error))
89*6777b538SAndroid Build Coastguard Worker       << "Failed to parse: " << input;
90*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(static_cast<OutputType>(expected_output), parsed_number2);
91*6777b538SAndroid Build Coastguard Worker   // Check that the error output was not written to.
92*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kBogusError, error);
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker // This wrapper calls func() and expects the failure to match |expected_error|.
96*6777b538SAndroid Build Coastguard Worker template <typename OutputType, typename ParseFunc>
ExpectParseIntFailure(ParseFunc func,std::string_view input,ParseIntFormat format,ParseIntError expected_error)97*6777b538SAndroid Build Coastguard Worker void ExpectParseIntFailure(ParseFunc func,
98*6777b538SAndroid Build Coastguard Worker                            std::string_view input,
99*6777b538SAndroid Build Coastguard Worker                            ParseIntFormat format,
100*6777b538SAndroid Build Coastguard Worker                            ParseIntError expected_error) {
101*6777b538SAndroid Build Coastguard Worker   const OutputType kBogusOutput(23614);
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker   // Try parsing without specifying an error output - expecting failure.
104*6777b538SAndroid Build Coastguard Worker   OutputType parsed_number1 = kBogusOutput;
105*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(func(input, format, &parsed_number1, nullptr))
106*6777b538SAndroid Build Coastguard Worker       << "Succeded parsing: " << input;
107*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kBogusOutput, parsed_number1)
108*6777b538SAndroid Build Coastguard Worker       << "Modified output when failed parsing";
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker   // Try parsing with an error output - expecting failure.
111*6777b538SAndroid Build Coastguard Worker   OutputType parsed_number2 = kBogusOutput;
112*6777b538SAndroid Build Coastguard Worker   ParseIntError error;
113*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(func(input, format, &parsed_number2, &error))
114*6777b538SAndroid Build Coastguard Worker       << "Succeded parsing: " << input;
115*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kBogusOutput, parsed_number2)
116*6777b538SAndroid Build Coastguard Worker       << "Modified output when failed parsing";
117*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_error, error);
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker // Common tests for both ParseInt*() and ParseUint*()
121*6777b538SAndroid Build Coastguard Worker //
122*6777b538SAndroid Build Coastguard Worker // When testing ParseUint*() the |format| parameter is not applicable and
123*6777b538SAndroid Build Coastguard Worker // should be passed as NON_NEGATIVE.
124*6777b538SAndroid Build Coastguard Worker template <typename T, typename ParseFunc>
TestParseIntUsingFormat(ParseFunc func,ParseIntFormat format)125*6777b538SAndroid Build Coastguard Worker void TestParseIntUsingFormat(ParseFunc func, ParseIntFormat format) {
126*6777b538SAndroid Build Coastguard Worker   bool is_format_non_negative = format == ParseIntFormat::NON_NEGATIVE ||
127*6777b538SAndroid Build Coastguard Worker                                 format == ParseIntFormat::STRICT_NON_NEGATIVE;
128*6777b538SAndroid Build Coastguard Worker   bool is_format_strict = format == ParseIntFormat::STRICT_NON_NEGATIVE ||
129*6777b538SAndroid Build Coastguard Worker                           format == ParseIntFormat::STRICT_OPTIONALLY_NEGATIVE;
130*6777b538SAndroid Build Coastguard Worker   // Test annotated inputs, some of which may not be valid inputs when parsed
131*6777b538SAndroid Build Coastguard Worker   // using `format`.
132*6777b538SAndroid Build Coastguard Worker   for (const auto& test : kAnnotatedTests) {
133*6777b538SAndroid Build Coastguard Worker     SCOPED_TRACE(test.input);
134*6777b538SAndroid Build Coastguard Worker     if ((test.is_non_negative || !is_format_non_negative) &&
135*6777b538SAndroid Build Coastguard Worker         (test.is_strict || !is_format_strict)) {
136*6777b538SAndroid Build Coastguard Worker       ExpectParseIntSuccess<T>(func, test.input, format, test.expected_output);
137*6777b538SAndroid Build Coastguard Worker     } else {
138*6777b538SAndroid Build Coastguard Worker       ExpectParseIntFailure<T>(func, test.input, format,
139*6777b538SAndroid Build Coastguard Worker                                ParseIntError::FAILED_PARSE);
140*6777b538SAndroid Build Coastguard Worker     }
141*6777b538SAndroid Build Coastguard Worker   }
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker   // Test invalid inputs (invalid regardless of parsing format)
144*6777b538SAndroid Build Coastguard Worker   for (auto* input : kInvalidParseTests) {
145*6777b538SAndroid Build Coastguard Worker     ExpectParseIntFailure<T>(func, input, format, ParseIntError::FAILED_PARSE);
146*6777b538SAndroid Build Coastguard Worker   }
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker   // Test parsing the largest possible value for output type.
149*6777b538SAndroid Build Coastguard Worker   {
150*6777b538SAndroid Build Coastguard Worker     const T value = std::numeric_limits<T>::max();
151*6777b538SAndroid Build Coastguard Worker     ExpectParseIntSuccess<T>(func, base::NumberToString(value), format, value);
152*6777b538SAndroid Build Coastguard Worker   }
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker   // Test parsing a number one larger than the output type can accomodate
155*6777b538SAndroid Build Coastguard Worker   // (overflow).
156*6777b538SAndroid Build Coastguard Worker   ExpectParseIntFailure<T>(func, CreateOverflowString<T>(), format,
157*6777b538SAndroid Build Coastguard Worker                            ParseIntError::FAILED_OVERFLOW);
158*6777b538SAndroid Build Coastguard Worker 
159*6777b538SAndroid Build Coastguard Worker   // Test parsing a number at least as large as the output allows AND contains
160*6777b538SAndroid Build Coastguard Worker   // garbage at the end. This exercises an interesting internal quirk of
161*6777b538SAndroid Build Coastguard Worker   // base::StringToInt*(), in that its result cannot distinguish this case
162*6777b538SAndroid Build Coastguard Worker   // from overflow.
163*6777b538SAndroid Build Coastguard Worker   ExpectParseIntFailure<T>(
164*6777b538SAndroid Build Coastguard Worker       func, base::NumberToString(std::numeric_limits<T>::max()) + " ", format,
165*6777b538SAndroid Build Coastguard Worker       ParseIntError::FAILED_PARSE);
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   ExpectParseIntFailure<T>(func, CreateOverflowString<T>() + " ", format,
168*6777b538SAndroid Build Coastguard Worker                            ParseIntError::FAILED_PARSE);
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker   // Test parsing the smallest possible value for output type. Don't do the
171*6777b538SAndroid Build Coastguard Worker   // test for unsigned types since the smallest number 0 is tested elsewhere.
172*6777b538SAndroid Build Coastguard Worker   if (std::numeric_limits<T>::is_signed) {
173*6777b538SAndroid Build Coastguard Worker     const T value = std::numeric_limits<T>::min();
174*6777b538SAndroid Build Coastguard Worker     std::string str_value = base::NumberToString(value);
175*6777b538SAndroid Build Coastguard Worker 
176*6777b538SAndroid Build Coastguard Worker     // The minimal value is necessarily negative, since this function is
177*6777b538SAndroid Build Coastguard Worker     // testing only signed output types.
178*6777b538SAndroid Build Coastguard Worker     if (is_format_non_negative) {
179*6777b538SAndroid Build Coastguard Worker       ExpectParseIntFailure<T>(func, str_value, format,
180*6777b538SAndroid Build Coastguard Worker                                ParseIntError::FAILED_PARSE);
181*6777b538SAndroid Build Coastguard Worker     } else {
182*6777b538SAndroid Build Coastguard Worker       ExpectParseIntSuccess<T>(func, str_value, format, value);
183*6777b538SAndroid Build Coastguard Worker     }
184*6777b538SAndroid Build Coastguard Worker   }
185*6777b538SAndroid Build Coastguard Worker 
186*6777b538SAndroid Build Coastguard Worker   // Test parsing a number one less than the output type can accomodate
187*6777b538SAndroid Build Coastguard Worker   // (underflow).
188*6777b538SAndroid Build Coastguard Worker   if (!is_format_non_negative) {
189*6777b538SAndroid Build Coastguard Worker     ExpectParseIntFailure<T>(func, CreateUnderflowString<T>(), format,
190*6777b538SAndroid Build Coastguard Worker                              ParseIntError::FAILED_UNDERFLOW);
191*6777b538SAndroid Build Coastguard Worker   }
192*6777b538SAndroid Build Coastguard Worker 
193*6777b538SAndroid Build Coastguard Worker   // Test parsing a string that contains a valid number followed by a NUL
194*6777b538SAndroid Build Coastguard Worker   // character.
195*6777b538SAndroid Build Coastguard Worker   ExpectParseIntFailure<T>(func, std::string_view("123\0", 4), format,
196*6777b538SAndroid Build Coastguard Worker                            ParseIntError::FAILED_PARSE);
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker 
199*6777b538SAndroid Build Coastguard Worker // Common tests to run for each of the versions of ParseInt*().
200*6777b538SAndroid Build Coastguard Worker //
201*6777b538SAndroid Build Coastguard Worker // The `func` parameter should be a function pointer to the particular
202*6777b538SAndroid Build Coastguard Worker // ParseInt*() function to test.
203*6777b538SAndroid Build Coastguard Worker template <typename T, typename ParseFunc>
TestParseInt(ParseFunc func)204*6777b538SAndroid Build Coastguard Worker void TestParseInt(ParseFunc func) {
205*6777b538SAndroid Build Coastguard Worker   // Test using each of the possible formats.
206*6777b538SAndroid Build Coastguard Worker   ParseIntFormat kFormats[] = {ParseIntFormat::NON_NEGATIVE,
207*6777b538SAndroid Build Coastguard Worker                                ParseIntFormat::OPTIONALLY_NEGATIVE,
208*6777b538SAndroid Build Coastguard Worker                                ParseIntFormat::STRICT_NON_NEGATIVE,
209*6777b538SAndroid Build Coastguard Worker                                ParseIntFormat::STRICT_OPTIONALLY_NEGATIVE};
210*6777b538SAndroid Build Coastguard Worker 
211*6777b538SAndroid Build Coastguard Worker   for (const auto& format : kFormats) {
212*6777b538SAndroid Build Coastguard Worker     TestParseIntUsingFormat<T>(func, format);
213*6777b538SAndroid Build Coastguard Worker   }
214*6777b538SAndroid Build Coastguard Worker }
215*6777b538SAndroid Build Coastguard Worker 
216*6777b538SAndroid Build Coastguard Worker // Common tests to run for each of the versions of ParseUint*().
217*6777b538SAndroid Build Coastguard Worker //
218*6777b538SAndroid Build Coastguard Worker // The `func` parameter should be a function pointer to the particular
219*6777b538SAndroid Build Coastguard Worker // ParseUint*() function to test.
220*6777b538SAndroid Build Coastguard Worker template <typename T, typename ParseFunc>
TestParseUint(ParseFunc func)221*6777b538SAndroid Build Coastguard Worker void TestParseUint(ParseFunc func) {
222*6777b538SAndroid Build Coastguard Worker   // Test using each of the possible formats.
223*6777b538SAndroid Build Coastguard Worker   ParseIntFormat kFormats[] = {
224*6777b538SAndroid Build Coastguard Worker       ParseIntFormat::NON_NEGATIVE,
225*6777b538SAndroid Build Coastguard Worker       ParseIntFormat::STRICT_NON_NEGATIVE,
226*6777b538SAndroid Build Coastguard Worker   };
227*6777b538SAndroid Build Coastguard Worker 
228*6777b538SAndroid Build Coastguard Worker   for (const auto& format : kFormats) {
229*6777b538SAndroid Build Coastguard Worker     TestParseIntUsingFormat<T>(func, format);
230*6777b538SAndroid Build Coastguard Worker   }
231*6777b538SAndroid Build Coastguard Worker }
232*6777b538SAndroid Build Coastguard Worker 
TEST(ParseNumberTest,ParseInt32)233*6777b538SAndroid Build Coastguard Worker TEST(ParseNumberTest, ParseInt32) {
234*6777b538SAndroid Build Coastguard Worker   TestParseInt<int32_t>(ParseInt32);
235*6777b538SAndroid Build Coastguard Worker }
236*6777b538SAndroid Build Coastguard Worker 
TEST(ParseNumberTest,ParseInt64)237*6777b538SAndroid Build Coastguard Worker TEST(ParseNumberTest, ParseInt64) {
238*6777b538SAndroid Build Coastguard Worker   TestParseInt<int64_t>(ParseInt64);
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker 
TEST(ParseNumberTest,ParseUint32)241*6777b538SAndroid Build Coastguard Worker TEST(ParseNumberTest, ParseUint32) {
242*6777b538SAndroid Build Coastguard Worker   TestParseUint<uint32_t>(ParseUint32);
243*6777b538SAndroid Build Coastguard Worker }
244*6777b538SAndroid Build Coastguard Worker 
TEST(ParseNumberTest,ParseUint64)245*6777b538SAndroid Build Coastguard Worker TEST(ParseNumberTest, ParseUint64) {
246*6777b538SAndroid Build Coastguard Worker   TestParseUint<uint64_t>(ParseUint64);
247*6777b538SAndroid Build Coastguard Worker }
248*6777b538SAndroid Build Coastguard Worker 
249*6777b538SAndroid Build Coastguard Worker }  // namespace
250*6777b538SAndroid Build Coastguard Worker }  // namespace net
251