1 //===-- Unittests for strtoul ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/stdlib/strtoul.h"
10 
11 #include "utils/UnitTest/Test.h"
12 
13 #include <errno.h>
14 #include <limits.h>
15 
16 TEST(LlvmLibcStrToULTest, InvalidBase) {
17   const char *ten = "10";
18   errno = 0;
19   ASSERT_EQ(__llvm_libc::strtoul(ten, nullptr, -1), 0ul);
20   ASSERT_EQ(errno, EINVAL);
21 }
22 
23 TEST(LlvmLibcStrToULTest, CleanBaseTenDecode) {
24   char *str_end = nullptr;
25 
26   const char *ten = "10";
27   errno = 0;
28   ASSERT_EQ(__llvm_libc::strtoul(ten, &str_end, 10), 10ul);
29   ASSERT_EQ(errno, 0);
30   EXPECT_EQ(str_end - ten, 2l);
31   errno = 0;
32   ASSERT_EQ(__llvm_libc::strtoul(ten, nullptr, 10), 10ul);
33   ASSERT_EQ(errno, 0);
34 
35   const char *hundred = "100";
36   errno = 0;
37   ASSERT_EQ(__llvm_libc::strtoul(hundred, &str_end, 10), 100ul);
38   ASSERT_EQ(errno, 0);
39   EXPECT_EQ(str_end - hundred, 3l);
40 
41   const char *negative = "-100";
42   errno = 0;
43   ASSERT_EQ(__llvm_libc::strtoul(negative, &str_end, 10), -(100ul));
44   ASSERT_EQ(errno, 0);
45   EXPECT_EQ(str_end - negative, 4l);
46 
47   const char *big_number = "123456789012345";
48   errno = 0;
49   ASSERT_EQ(__llvm_libc::strtoul(big_number, &str_end, 10), 123456789012345ul);
50   ASSERT_EQ(errno, 0);
51   EXPECT_EQ(str_end - big_number, 15l);
52 
53   const char *too_big_number = "123456789012345678901";
54   errno = 0;
55   ASSERT_EQ(__llvm_libc::strtoul(too_big_number, &str_end, 10), ULONG_MAX);
56   ASSERT_EQ(errno, ERANGE);
57   EXPECT_EQ(str_end - too_big_number, 21l);
58 
59   const char *too_big_negative_number = "-123456789012345678901";
60   errno = 0;
61   ASSERT_EQ(__llvm_libc::strtoul(too_big_negative_number, &str_end, 10),
62             ULONG_MAX);
63   ASSERT_EQ(errno, ERANGE);
64   EXPECT_EQ(str_end - too_big_negative_number, 22l);
65 
66   const char *long_number_range_test =
67       "10000000000000000000000000000000000000000000000000";
68   errno = 0;
69   ASSERT_EQ(__llvm_libc::strtoul(long_number_range_test, &str_end, 10),
70             ULONG_MAX);
71   ASSERT_EQ(errno, ERANGE);
72   EXPECT_EQ(str_end - long_number_range_test, 50l);
73 }
74 
75 TEST(LlvmLibcStrToULTest, MessyBaseTenDecode) {
76   char *str_end = nullptr;
77 
78   const char *spaces_before = "     10";
79   errno = 0;
80   ASSERT_EQ(__llvm_libc::strtoul(spaces_before, &str_end, 10), 10ul);
81   ASSERT_EQ(errno, 0);
82   EXPECT_EQ(str_end - spaces_before, 7l);
83 
84   const char *spaces_after = "10      ";
85   errno = 0;
86   ASSERT_EQ(__llvm_libc::strtoul(spaces_after, &str_end, 10), 10ul);
87   ASSERT_EQ(errno, 0);
88   EXPECT_EQ(str_end - spaces_after, 2l);
89 
90   const char *word_before = "word10";
91   errno = 0;
92   ASSERT_EQ(__llvm_libc::strtoul(word_before, &str_end, 10), 0ul);
93   ASSERT_EQ(errno, 0);
94   EXPECT_EQ(str_end - word_before, 0l);
95 
96   const char *word_after = "10word";
97   errno = 0;
98   ASSERT_EQ(__llvm_libc::strtoul(word_after, &str_end, 10), 10ul);
99   ASSERT_EQ(errno, 0);
100   EXPECT_EQ(str_end - word_after, 2l);
101 
102   const char *two_numbers = "10 999";
103   errno = 0;
104   ASSERT_EQ(__llvm_libc::strtoul(two_numbers, &str_end, 10), 10ul);
105   ASSERT_EQ(errno, 0);
106   EXPECT_EQ(str_end - two_numbers, 2l);
107 
108   const char *two_signs = "--10 999";
109   errno = 0;
110   ASSERT_EQ(__llvm_libc::strtoul(two_signs, &str_end, 10), 0ul);
111   ASSERT_EQ(errno, 0);
112   EXPECT_EQ(str_end - two_signs, 1l);
113 
114   const char *sign_before = "+2=4";
115   errno = 0;
116   ASSERT_EQ(__llvm_libc::strtoul(sign_before, &str_end, 10), 2ul);
117   ASSERT_EQ(errno, 0);
118   EXPECT_EQ(str_end - sign_before, 2l);
119 
120   const char *sign_after = "2+2=4";
121   errno = 0;
122   ASSERT_EQ(__llvm_libc::strtoul(sign_after, &str_end, 10), 2ul);
123   ASSERT_EQ(errno, 0);
124   EXPECT_EQ(str_end - sign_after, 1l);
125 
126   const char *tab_before = "\t10";
127   errno = 0;
128   ASSERT_EQ(__llvm_libc::strtoul(tab_before, &str_end, 10), 10ul);
129   ASSERT_EQ(errno, 0);
130   EXPECT_EQ(str_end - tab_before, 3l);
131 
132   const char *all_together = "\t  -12345and+67890";
133   errno = 0;
134   ASSERT_EQ(__llvm_libc::strtoul(all_together, &str_end, 10), -(12345ul));
135   ASSERT_EQ(errno, 0);
136   EXPECT_EQ(str_end - all_together, 9l);
137 }
138 
139 static char int_to_b36_char(int input) {
140   if (input < 0 || input > 36)
141     return '0';
142   if (input < 10)
143     return '0' + input;
144   return 'A' + input - 10;
145 }
146 
147 TEST(LlvmLibcStrToULTest, DecodeInOtherBases) {
148   char small_string[4] = {'\0', '\0', '\0', '\0'};
149   for (unsigned int base = 2; base <= 36; ++base) {
150     for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
151       small_string[0] = int_to_b36_char(first_digit);
152       if (first_digit < base) {
153         errno = 0;
154         ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
155                   first_digit);
156         ASSERT_EQ(errno, 0);
157       } else {
158         errno = 0;
159         ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
160         ASSERT_EQ(errno, 0);
161       }
162     }
163   }
164 
165   for (unsigned int base = 2; base <= 36; ++base) {
166     for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
167       small_string[0] = int_to_b36_char(first_digit);
168       for (unsigned long second_digit = 0; second_digit <= 36; ++second_digit) {
169         small_string[1] = int_to_b36_char(second_digit);
170         if (first_digit < base && second_digit < base) {
171           errno = 0;
172           ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
173                     second_digit + (first_digit * base));
174           ASSERT_EQ(errno, 0);
175         } else if (first_digit < base) {
176           errno = 0;
177           ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
178                     first_digit);
179           ASSERT_EQ(errno, 0);
180         } else {
181           errno = 0;
182           ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
183           ASSERT_EQ(errno, 0);
184         }
185       }
186     }
187   }
188 
189   for (unsigned int base = 2; base <= 36; ++base) {
190     for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
191       small_string[0] = int_to_b36_char(first_digit);
192       for (unsigned long second_digit = 0; second_digit <= 36; ++second_digit) {
193         small_string[1] = int_to_b36_char(second_digit);
194         for (unsigned long third_digit = 0; third_digit <= 36; ++third_digit) {
195           small_string[2] = int_to_b36_char(third_digit);
196 
197           if (first_digit < base && second_digit < base && third_digit < base) {
198             errno = 0;
199             ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
200                       third_digit + (second_digit * base) +
201                           (first_digit * base * base));
202             ASSERT_EQ(errno, 0);
203           } else if (first_digit < base && second_digit < base) {
204             errno = 0;
205             ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
206                       second_digit + (first_digit * base));
207             ASSERT_EQ(errno, 0);
208           } else if (first_digit < base) {
209             // if the base is 16 there is a special case for the prefix 0X.
210             // The number is treated as a one digit hexadecimal.
211             if (base == 16 && first_digit == 0 && second_digit == 33) {
212               if (third_digit < base) {
213                 errno = 0;
214                 ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
215                           third_digit);
216                 ASSERT_EQ(errno, 0);
217               } else {
218                 errno = 0;
219                 ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
220                           0ul);
221                 ASSERT_EQ(errno, 0);
222               }
223             } else {
224               errno = 0;
225               ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
226                         first_digit);
227               ASSERT_EQ(errno, 0);
228             }
229           } else {
230             errno = 0;
231             ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
232             ASSERT_EQ(errno, 0);
233           }
234         }
235       }
236     }
237   }
238 }
239 
240 TEST(LlvmLibcStrToULTest, CleanBaseSixteenDecode) {
241   char *str_end = nullptr;
242 
243   const char *no_prefix = "123abc";
244   errno = 0;
245   ASSERT_EQ(__llvm_libc::strtoul(no_prefix, &str_end, 16), 0x123abcul);
246   ASSERT_EQ(errno, 0);
247   EXPECT_EQ(str_end - no_prefix, 6l);
248 
249   const char *yes_prefix = "0x456def";
250   errno = 0;
251   ASSERT_EQ(__llvm_libc::strtoul(yes_prefix, &str_end, 16), 0x456deful);
252   ASSERT_EQ(errno, 0);
253   EXPECT_EQ(str_end - yes_prefix, 8l);
254 }
255 
256 TEST(LlvmLibcStrToULTest, AutomaticBaseSelection) {
257   char *str_end = nullptr;
258 
259   const char *base_ten = "12345";
260   errno = 0;
261   ASSERT_EQ(__llvm_libc::strtoul(base_ten, &str_end, 0), 12345ul);
262   ASSERT_EQ(errno, 0);
263   EXPECT_EQ(str_end - base_ten, 5l);
264 
265   const char *base_sixteen_no_prefix = "123abc";
266   errno = 0;
267   ASSERT_EQ(__llvm_libc::strtoul(base_sixteen_no_prefix, &str_end, 0), 123ul);
268   ASSERT_EQ(errno, 0);
269   EXPECT_EQ(str_end - base_sixteen_no_prefix, 3l);
270 
271   const char *base_sixteen_with_prefix = "0x456def";
272   errno = 0;
273   ASSERT_EQ(__llvm_libc::strtoul(base_sixteen_with_prefix, &str_end, 0),
274             0x456deful);
275   ASSERT_EQ(errno, 0);
276   EXPECT_EQ(str_end - base_sixteen_with_prefix, 8l);
277 
278   const char *base_eight_with_prefix = "012345";
279   errno = 0;
280   ASSERT_EQ(__llvm_libc::strtoul(base_eight_with_prefix, &str_end, 0),
281             012345ul);
282   ASSERT_EQ(errno, 0);
283   EXPECT_EQ(str_end - base_eight_with_prefix, 6l);
284 }
285