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 <errno.h>
12 #include <limits.h>
13 #include <stddef.h>
14 
15 #include "utils/UnitTest/Test.h"
16 
17 TEST(LlvmLibcStrToULTest, InvalidBase) {
18   const char *ten = "10";
19   errno = 0;
20   ASSERT_EQ(__llvm_libc::strtoul(ten, nullptr, -1), 0ul);
21   ASSERT_EQ(errno, EINVAL);
22 }
23 
24 TEST(LlvmLibcStrToULTest, CleanBaseTenDecode) {
25   char *str_end = nullptr;
26 
27   const char *ten = "10";
28   errno = 0;
29   ASSERT_EQ(__llvm_libc::strtoul(ten, &str_end, 10), 10ul);
30   ASSERT_EQ(errno, 0);
31   EXPECT_EQ(str_end - ten, ptrdiff_t(2));
32   errno = 0;
33   ASSERT_EQ(__llvm_libc::strtoul(ten, nullptr, 10), 10ul);
34   ASSERT_EQ(errno, 0);
35 
36   const char *hundred = "100";
37   errno = 0;
38   ASSERT_EQ(__llvm_libc::strtoul(hundred, &str_end, 10), 100ul);
39   ASSERT_EQ(errno, 0);
40   EXPECT_EQ(str_end - hundred, ptrdiff_t(3));
41 
42   const char *negative = "-100";
43   errno = 0;
44   ASSERT_EQ(__llvm_libc::strtoul(negative, &str_end, 10), -(100ul));
45   ASSERT_EQ(errno, 0);
46   EXPECT_EQ(str_end - negative, ptrdiff_t(4));
47 
48   const char *big_number = "1234567890";
49   errno = 0;
50   ASSERT_EQ(__llvm_libc::strtoul(big_number, &str_end, 10), 1234567890ul);
51   ASSERT_EQ(errno, 0);
52   EXPECT_EQ(str_end - big_number, ptrdiff_t(10));
53 
54   const char *too_big_number = "123456789012345678901";
55   errno = 0;
56   ASSERT_EQ(__llvm_libc::strtoul(too_big_number, &str_end, 10), ULONG_MAX);
57   ASSERT_EQ(errno, ERANGE);
58   EXPECT_EQ(str_end - too_big_number, ptrdiff_t(21));
59 
60   const char *too_big_negative_number = "-123456789012345678901";
61   errno = 0;
62   ASSERT_EQ(__llvm_libc::strtoul(too_big_negative_number, &str_end, 10),
63             ULONG_MAX);
64   ASSERT_EQ(errno, ERANGE);
65   EXPECT_EQ(str_end - too_big_negative_number, ptrdiff_t(22));
66 
67   const char *long_number_range_test =
68       "10000000000000000000000000000000000000000000000000";
69   errno = 0;
70   ASSERT_EQ(__llvm_libc::strtoul(long_number_range_test, &str_end, 10),
71             ULONG_MAX);
72   ASSERT_EQ(errno, ERANGE);
73   EXPECT_EQ(str_end - long_number_range_test, ptrdiff_t(50));
74 }
75 
76 TEST(LlvmLibcStrToULTest, MessyBaseTenDecode) {
77   char *str_end = nullptr;
78 
79   const char *spaces_before = "     10";
80   errno = 0;
81   ASSERT_EQ(__llvm_libc::strtoul(spaces_before, &str_end, 10), 10ul);
82   ASSERT_EQ(errno, 0);
83   EXPECT_EQ(str_end - spaces_before, ptrdiff_t(7));
84 
85   const char *spaces_after = "10      ";
86   errno = 0;
87   ASSERT_EQ(__llvm_libc::strtoul(spaces_after, &str_end, 10), 10ul);
88   ASSERT_EQ(errno, 0);
89   EXPECT_EQ(str_end - spaces_after, ptrdiff_t(2));
90 
91   const char *word_before = "word10";
92   errno = 0;
93   ASSERT_EQ(__llvm_libc::strtoul(word_before, &str_end, 10), 0ul);
94   ASSERT_EQ(errno, 0);
95   EXPECT_EQ(str_end - word_before, ptrdiff_t(0));
96 
97   const char *word_after = "10word";
98   errno = 0;
99   ASSERT_EQ(__llvm_libc::strtoul(word_after, &str_end, 10), 10ul);
100   ASSERT_EQ(errno, 0);
101   EXPECT_EQ(str_end - word_after, ptrdiff_t(2));
102 
103   const char *two_numbers = "10 999";
104   errno = 0;
105   ASSERT_EQ(__llvm_libc::strtoul(two_numbers, &str_end, 10), 10ul);
106   ASSERT_EQ(errno, 0);
107   EXPECT_EQ(str_end - two_numbers, ptrdiff_t(2));
108 
109   const char *two_signs = "--10 999";
110   errno = 0;
111   ASSERT_EQ(__llvm_libc::strtoul(two_signs, &str_end, 10), 0ul);
112   ASSERT_EQ(errno, 0);
113   EXPECT_EQ(str_end - two_signs, ptrdiff_t(0));
114 
115   const char *sign_before = "+2=4";
116   errno = 0;
117   ASSERT_EQ(__llvm_libc::strtoul(sign_before, &str_end, 10), 2ul);
118   ASSERT_EQ(errno, 0);
119   EXPECT_EQ(str_end - sign_before, ptrdiff_t(2));
120 
121   const char *sign_after = "2+2=4";
122   errno = 0;
123   ASSERT_EQ(__llvm_libc::strtoul(sign_after, &str_end, 10), 2ul);
124   ASSERT_EQ(errno, 0);
125   EXPECT_EQ(str_end - sign_after, ptrdiff_t(1));
126 
127   const char *tab_before = "\t10";
128   errno = 0;
129   ASSERT_EQ(__llvm_libc::strtoul(tab_before, &str_end, 10), 10ul);
130   ASSERT_EQ(errno, 0);
131   EXPECT_EQ(str_end - tab_before, ptrdiff_t(3));
132 
133   const char *all_together = "\t  -12345and+67890";
134   errno = 0;
135   ASSERT_EQ(__llvm_libc::strtoul(all_together, &str_end, 10), -(12345ul));
136   ASSERT_EQ(errno, 0);
137   EXPECT_EQ(str_end - all_together, ptrdiff_t(9));
138 
139   const char *just_spaces = "  ";
140   errno = 0;
141   ASSERT_EQ(__llvm_libc::strtoul(just_spaces, &str_end, 10), 0ul);
142   ASSERT_EQ(errno, 0);
143   EXPECT_EQ(str_end - just_spaces, ptrdiff_t(0));
144 
145   const char *just_space_and_sign = " +";
146   errno = 0;
147   ASSERT_EQ(__llvm_libc::strtoul(just_space_and_sign, &str_end, 10), 0ul);
148   ASSERT_EQ(errno, 0);
149   EXPECT_EQ(str_end - just_space_and_sign, ptrdiff_t(0));
150 }
151 
152 static char int_to_b36_char(int input) {
153   if (input < 0 || input > 36)
154     return '0';
155   if (input < 10)
156     return static_cast<char>('0' + input);
157   return static_cast<char>('A' + input - 10);
158 }
159 
160 TEST(LlvmLibcStrToULTest, DecodeInOtherBases) {
161   char small_string[4] = {'\0', '\0', '\0', '\0'};
162   for (int base = 2; base <= 36; ++base) {
163     for (int first_digit = 0; first_digit <= 36; ++first_digit) {
164       small_string[0] = int_to_b36_char(first_digit);
165       if (first_digit < base) {
166         errno = 0;
167         ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
168                   static_cast<unsigned long int>(first_digit));
169         ASSERT_EQ(errno, 0);
170       } else {
171         errno = 0;
172         ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
173         ASSERT_EQ(errno, 0);
174       }
175     }
176   }
177 
178   for (int base = 2; base <= 36; ++base) {
179     for (int first_digit = 0; first_digit <= 36; ++first_digit) {
180       small_string[0] = int_to_b36_char(first_digit);
181       for (int second_digit = 0; second_digit <= 36; ++second_digit) {
182         small_string[1] = int_to_b36_char(second_digit);
183         if (first_digit < base && second_digit < base) {
184           errno = 0;
185           ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
186                     static_cast<unsigned long int>(second_digit +
187                                                    (first_digit * base)));
188           ASSERT_EQ(errno, 0);
189         } else if (first_digit < base) {
190           errno = 0;
191           ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
192                     static_cast<unsigned long int>(first_digit));
193           ASSERT_EQ(errno, 0);
194         } else {
195           errno = 0;
196           ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
197           ASSERT_EQ(errno, 0);
198         }
199       }
200     }
201   }
202 
203   for (int base = 2; base <= 36; ++base) {
204     for (int first_digit = 0; first_digit <= 36; ++first_digit) {
205       small_string[0] = int_to_b36_char(first_digit);
206       for (int second_digit = 0; second_digit <= 36; ++second_digit) {
207         small_string[1] = int_to_b36_char(second_digit);
208         for (int third_digit = 0; third_digit <= 36; ++third_digit) {
209           small_string[2] = int_to_b36_char(third_digit);
210 
211           if (first_digit < base && second_digit < base && third_digit < base) {
212             errno = 0;
213             ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
214                       static_cast<unsigned long int>(
215                           third_digit + (second_digit * base) +
216                           (first_digit * base * base)));
217             ASSERT_EQ(errno, 0);
218           } else if (first_digit < base && second_digit < base) {
219             errno = 0;
220             ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
221                       static_cast<unsigned long int>(second_digit +
222                                                      (first_digit * base)));
223             ASSERT_EQ(errno, 0);
224           } else if (first_digit < base) {
225             // if the base is 16 there is a special case for the prefix 0X.
226             // The number is treated as a one digit hexadecimal.
227             if (base == 16 && first_digit == 0 && second_digit == 33) {
228               if (third_digit < base) {
229                 errno = 0;
230                 ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
231                           static_cast<unsigned long int>(third_digit));
232                 ASSERT_EQ(errno, 0);
233               } else {
234                 errno = 0;
235                 ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
236                           0ul);
237                 ASSERT_EQ(errno, 0);
238               }
239             } else {
240               errno = 0;
241               ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
242                         static_cast<unsigned long int>(first_digit));
243               ASSERT_EQ(errno, 0);
244             }
245           } else {
246             errno = 0;
247             ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
248             ASSERT_EQ(errno, 0);
249           }
250         }
251       }
252     }
253   }
254 }
255 
256 TEST(LlvmLibcStrToULTest, CleanBaseSixteenDecode) {
257   char *str_end = nullptr;
258 
259   const char *no_prefix = "123abc";
260   errno = 0;
261   ASSERT_EQ(__llvm_libc::strtoul(no_prefix, &str_end, 16), 0x123abcul);
262   ASSERT_EQ(errno, 0);
263   EXPECT_EQ(str_end - no_prefix, ptrdiff_t(6));
264 
265   const char *yes_prefix = "0x456def";
266   errno = 0;
267   ASSERT_EQ(__llvm_libc::strtoul(yes_prefix, &str_end, 16), 0x456deful);
268   ASSERT_EQ(errno, 0);
269   EXPECT_EQ(str_end - yes_prefix, ptrdiff_t(8));
270 
271   const char *letter_after_prefix = "0xabc123";
272   errno = 0;
273   ASSERT_EQ(__llvm_libc::strtoul(letter_after_prefix, &str_end, 16),
274             0xabc123ul);
275   ASSERT_EQ(errno, 0);
276   EXPECT_EQ(str_end - letter_after_prefix, ptrdiff_t(8));
277 }
278 
279 TEST(LlvmLibcStrToULTest, MessyBaseSixteenDecode) {
280   char *str_end = nullptr;
281 
282   const char *just_prefix = "0x";
283   errno = 0;
284   ASSERT_EQ(__llvm_libc::strtoul(just_prefix, &str_end, 16), 0ul);
285   ASSERT_EQ(errno, 0);
286   EXPECT_EQ(str_end - just_prefix, ptrdiff_t(1));
287 
288   errno = 0;
289   ASSERT_EQ(__llvm_libc::strtoul(just_prefix, &str_end, 0), 0ul);
290   ASSERT_EQ(errno, 0);
291   EXPECT_EQ(str_end - just_prefix, ptrdiff_t(1));
292 
293   const char *prefix_with_x_after = "0xx";
294   errno = 0;
295   ASSERT_EQ(__llvm_libc::strtoul(prefix_with_x_after, &str_end, 16), 0ul);
296   ASSERT_EQ(errno, 0);
297   EXPECT_EQ(str_end - prefix_with_x_after, ptrdiff_t(1));
298 
299   errno = 0;
300   ASSERT_EQ(__llvm_libc::strtoul(prefix_with_x_after, &str_end, 0), 0ul);
301   ASSERT_EQ(errno, 0);
302   EXPECT_EQ(str_end - prefix_with_x_after, ptrdiff_t(1));
303 }
304 
305 TEST(LlvmLibcStrToULTest, AutomaticBaseSelection) {
306   char *str_end = nullptr;
307 
308   const char *base_ten = "12345";
309   errno = 0;
310   ASSERT_EQ(__llvm_libc::strtoul(base_ten, &str_end, 0), 12345ul);
311   ASSERT_EQ(errno, 0);
312   EXPECT_EQ(str_end - base_ten, ptrdiff_t(5));
313 
314   const char *base_sixteen_no_prefix = "123abc";
315   errno = 0;
316   ASSERT_EQ(__llvm_libc::strtoul(base_sixteen_no_prefix, &str_end, 0), 123ul);
317   ASSERT_EQ(errno, 0);
318   EXPECT_EQ(str_end - base_sixteen_no_prefix, ptrdiff_t(3));
319 
320   const char *base_sixteen_with_prefix = "0x456def";
321   errno = 0;
322   ASSERT_EQ(__llvm_libc::strtoul(base_sixteen_with_prefix, &str_end, 0),
323             0x456deful);
324   ASSERT_EQ(errno, 0);
325   EXPECT_EQ(str_end - base_sixteen_with_prefix, ptrdiff_t(8));
326 
327   const char *base_eight_with_prefix = "012345";
328   errno = 0;
329   ASSERT_EQ(__llvm_libc::strtoul(base_eight_with_prefix, &str_end, 0),
330             012345ul);
331   ASSERT_EQ(errno, 0);
332   EXPECT_EQ(str_end - base_eight_with_prefix, ptrdiff_t(6));
333 
334   const char *just_zero = "0";
335   errno = 0;
336   ASSERT_EQ(__llvm_libc::strtoul(just_zero, &str_end, 0), 0ul);
337   ASSERT_EQ(errno, 0);
338   EXPECT_EQ(str_end - just_zero, ptrdiff_t(1));
339 
340   const char *just_zero_x = "0x";
341   errno = 0;
342   ASSERT_EQ(__llvm_libc::strtoul(just_zero_x, &str_end, 0), 0ul);
343   ASSERT_EQ(errno, 0);
344   EXPECT_EQ(str_end - just_zero_x, ptrdiff_t(1));
345 
346   const char *just_zero_eight = "08";
347   errno = 0;
348   ASSERT_EQ(__llvm_libc::strtoul(just_zero_eight, &str_end, 0), 0ul);
349   ASSERT_EQ(errno, 0);
350   EXPECT_EQ(str_end - just_zero_eight, ptrdiff_t(1));
351 }
352