1 //===-- A template class for testing ato* functions -------------*- C++ -*-===// 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/__support/CPP/limits.h" // INT_MAX, INT_MIN, LLONG_MAX, LLONG_MIN 10 #include "src/__support/CPP/type_traits.h" 11 #include "test/UnitTest/Test.h" 12 13 using LIBC_NAMESPACE::cpp::is_same_v; 14 15 template <typename ReturnT> 16 struct AtoTest : public LIBC_NAMESPACE::testing::Test { 17 using FunctionT = ReturnT (*)(const char *); 18 validNumbersAtoTest19 void validNumbers(FunctionT func) { 20 const char *zero = "0"; 21 ASSERT_EQ(func(zero), static_cast<ReturnT>(0)); 22 23 const char *ten = "10"; 24 ASSERT_EQ(func(ten), static_cast<ReturnT>(10)); 25 26 const char *negative_hundred = "-100"; 27 ASSERT_EQ(func(negative_hundred), static_cast<ReturnT>(-100)); 28 29 const char *positive_thousand = "+1000"; 30 ASSERT_EQ(func(positive_thousand), static_cast<ReturnT>(1000)); 31 32 const char *spaces_before = " 12345"; 33 ASSERT_EQ(func(spaces_before), static_cast<ReturnT>(12345)); 34 35 const char *tabs_before = "\t\t\t\t67890"; 36 ASSERT_EQ(func(tabs_before), static_cast<ReturnT>(67890)); 37 38 const char *letters_after = "123abc"; 39 ASSERT_EQ(func(letters_after), static_cast<ReturnT>(123)); 40 41 const char *letters_between = "456def789"; 42 ASSERT_EQ(func(letters_between), static_cast<ReturnT>(456)); 43 44 const char *all_together = "\t 110 times 5 = 550"; 45 ASSERT_EQ(func(all_together), static_cast<ReturnT>(110)); 46 47 const char *biggest_int = "2147483647"; 48 ASSERT_EQ(func(biggest_int), static_cast<ReturnT>(INT_MAX)); 49 50 const char *smallest_int = "-2147483648"; 51 ASSERT_EQ(func(smallest_int), static_cast<ReturnT>(INT_MIN)); 52 53 if constexpr (sizeof(ReturnT) >= 8) { 54 const char *biggest_long_long = "9223372036854775807"; 55 ASSERT_EQ(func(biggest_long_long), static_cast<ReturnT>(LLONG_MAX)); 56 57 const char *smallest_long_long = "-9223372036854775808"; 58 ASSERT_EQ(func(smallest_long_long), static_cast<ReturnT>(LLONG_MIN)); 59 } 60 61 // If this is atoi and the size of int is less than the size of long, then 62 // we parse as long and cast to int to match existing behavior. This only 63 // matters for cases where the result would be outside of the int range, and 64 // those cases are undefined, so we can choose whatever output value we 65 // want. In this case we have chosen to cast since that matches existing 66 // implementations and makes differential fuzzing easier, but no user should 67 // rely on this behavior. 68 if constexpr (is_same_v<ReturnT, int> && sizeof(ReturnT) < sizeof(long)) { 69 70 static_assert(sizeof(int) == 4); 71 72 const char *bigger_than_biggest_int = "2147483649"; 73 ASSERT_EQ(func(bigger_than_biggest_int), 74 static_cast<ReturnT>(2147483649)); 75 76 const char *smaller_than_smallest_int = "-2147483649"; 77 ASSERT_EQ(func(smaller_than_smallest_int), 78 static_cast<ReturnT>(-2147483649)); 79 } 80 } 81 nonBaseTenWholeNumbersAtoTest82 void nonBaseTenWholeNumbers(FunctionT func) { 83 const char *hexadecimal = "0x10"; 84 ASSERT_EQ(func(hexadecimal), static_cast<ReturnT>(0)); 85 86 const char *octal = "010"; 87 ASSERT_EQ(func(octal), static_cast<ReturnT>(10)); 88 89 const char *decimal_point = "5.9"; 90 ASSERT_EQ(func(decimal_point), static_cast<ReturnT>(5)); 91 } 92 notNumbersAtoTest93 void notNumbers(FunctionT func) { 94 const char *ten_as_word = "ten"; 95 ASSERT_EQ(func(ten_as_word), static_cast<ReturnT>(0)); 96 97 const char *lots_of_letters = 98 "wtragsdhfgjykutjdyfhgnchgmjhkyurktfgjhlu;po7urtdjyfhgklyk"; 99 ASSERT_EQ(func(lots_of_letters), static_cast<ReturnT>(0)); 100 } 101 }; 102 103 template <typename ReturnType> 104 AtoTest(ReturnType (*)(const char *)) -> AtoTest<ReturnType>; 105 106 #define ATOI_TEST(name, func) \ 107 using LlvmLibc##name##Test = AtoTest<decltype(func(""))>; \ 108 TEST_F(LlvmLibc##name##Test, ValidNumbers) { validNumbers(func); } \ 109 TEST_F(LlvmLibc##name##Test, NonBaseTenWholeNumbers) { \ 110 nonBaseTenWholeNumbers(func); \ 111 } \ 112 TEST_F(LlvmLibc##name##Test, NotNumbers) { notNumbers(func); } 113