289 changes: 289 additions & 0 deletions libc/test/src/stdlib/strtol_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
//===-- Unittests for strtol ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdlib/strtol.h"

#include "utils/UnitTest/Test.h"

#include <errno.h>
#include <limits.h>

TEST(LlvmLibcStrToLTest, InvalidBase) {
const char *ten = "10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(ten, nullptr, -1), 0l);
ASSERT_EQ(errno, EINVAL);
}

TEST(LlvmLibcStrToLTest, CleanBaseTenDecode) {
char *str_end = nullptr;

const char *ten = "10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(ten, &str_end, 10), 10l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - ten, 2l);
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(ten, nullptr, 10), 10l);
ASSERT_EQ(errno, 0);

const char *hundred = "100";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(hundred, &str_end, 10), 100l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - hundred, 3l);

const char *negative = "-100";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(negative, &str_end, 10), -100l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - negative, 4l);

const char *big_number = "123456789012345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(big_number, &str_end, 10), 123456789012345l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - big_number, 15l);

const char *big_negative_number = "-123456789012345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(big_negative_number, &str_end, 10),
-123456789012345l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - big_negative_number, 16l);

const char *too_big_number = "123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(too_big_number, &str_end, 10), LONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - too_big_number, 21l);

const char *too_big_negative_number = "-123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(too_big_negative_number, &str_end, 10),
LONG_MIN);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - too_big_negative_number, 22l);

const char *long_number_range_test =
"10000000000000000000000000000000000000000000000000";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(long_number_range_test, &str_end, 10),
LONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - long_number_range_test, 50l);
}

TEST(LlvmLibcStrToLTest, MessyBaseTenDecode) {
char *str_end = nullptr;

const char *spaces_before = " 10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(spaces_before, &str_end, 10), 10l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - spaces_before, 7l);

const char *spaces_after = "10 ";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(spaces_after, &str_end, 10), 10l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - spaces_after, 2l);

const char *word_before = "word10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(word_before, &str_end, 10), 0l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - word_before, 0l);

const char *word_after = "10word";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(word_after, &str_end, 10), 10l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - word_after, 2l);

const char *two_numbers = "10 999";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(two_numbers, &str_end, 10), 10l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - two_numbers, 2l);

const char *two_signs = "--10 999";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(two_signs, &str_end, 10), 0l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - two_signs, 1l);

const char *sign_before = "+2=4";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(sign_before, &str_end, 10), 2l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - sign_before, 2l);

const char *sign_after = "2+2=4";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(sign_after, &str_end, 10), 2l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - sign_after, 1l);

const char *tab_before = "\t10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(tab_before, &str_end, 10), 10l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - tab_before, 3l);

const char *all_together = "\t -12345and+67890";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(all_together, &str_end, 10), -12345l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - all_together, 9l);
}

static char int_to_b36_char(int input) {
if (input < 0 || input > 36)
return '0';
if (input < 10)
return '0' + input;
return 'A' + input - 10;
}

TEST(LlvmLibcStrToLTest, DecodeInOtherBases) {
char small_string[4] = {'\0', '\0', '\0', '\0'};
for (unsigned int base = 2; base <= 36; ++base) {
for (long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
if (first_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base), 0l);
ASSERT_EQ(errno, 0);
}
}
}

for (unsigned int base = 2; base <= 36; ++base) {
for (long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (long second_digit = 0; second_digit <= 36; ++second_digit) {
small_string[1] = int_to_b36_char(second_digit);
if (first_digit < base && second_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
second_digit + (first_digit * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base), 0l);
ASSERT_EQ(errno, 0);
}
}
}
}

for (unsigned int base = 2; base <= 36; ++base) {
for (long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (long second_digit = 0; second_digit <= 36; ++second_digit) {
small_string[1] = int_to_b36_char(second_digit);
for (long third_digit = 0; third_digit <= 36; ++third_digit) {
small_string[2] = int_to_b36_char(third_digit);

if (first_digit < base && second_digit < base && third_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
third_digit + (second_digit * base) +
(first_digit * base * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base && second_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
second_digit + (first_digit * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base) {
// if the base is 16 there is a special case for the prefix 0X.
// The number is treated as a one digit hexadecimal.
if (base == 16 && first_digit == 0 && second_digit == 33) {
if (third_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
third_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base), 0l);
ASSERT_EQ(errno, 0);
}
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
}
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base), 0l);
ASSERT_EQ(errno, 0);
}
}
}
}
}
}

TEST(LlvmLibcStrToLTest, CleanBaseSixteenDecode) {
char *str_end = nullptr;

const char *no_prefix = "123abc";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(no_prefix, &str_end, 16), 0x123abcl);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - no_prefix, 6l);

const char *yes_prefix = "0x456def";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(yes_prefix, &str_end, 16), 0x456defl);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - yes_prefix, 8l);
}

TEST(LlvmLibcStrToLTest, AutomaticBaseSelection) {
char *str_end = nullptr;

const char *base_ten = "12345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(base_ten, &str_end, 0), 12345l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_ten, 5l);

const char *base_sixteen_no_prefix = "123abc";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(base_sixteen_no_prefix, &str_end, 0), 123l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_sixteen_no_prefix, 3l);

const char *base_sixteen_with_prefix = "0x456def";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(base_sixteen_with_prefix, &str_end, 0),
0x456defl);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_sixteen_with_prefix, 8l);

const char *base_eight_with_prefix = "012345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtol(base_eight_with_prefix, &str_end, 0), 012345l);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_eight_with_prefix, 6l);
}
41 changes: 36 additions & 5 deletions libc/test/src/stdlib/strtoll_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,49 @@ TEST(LlvmLibcStrToLLTest, CleanBaseTenDecode) {
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - big_negative_number, 16l);

const char *long_long_max_number = "9223372036854775807";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoll(long_long_max_number, &str_end, 10),
9223372036854775807ll);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - long_long_max_number, 19l);

const char *long_long_min_number = "-9223372036854775808";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoll(long_long_min_number, &str_end, 10),
-9223372036854775807ll - 1ll);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - long_long_min_number, 20l);

const char *too_big_number = "123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoll(too_big_number, &str_end, 10), LLONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - too_big_number, 19l);
EXPECT_EQ(str_end - too_big_number, 21l);

const char *too_big_negative_number = "-123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoll(too_big_negative_number, &str_end, 10),
LLONG_MIN);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - too_big_negative_number, 20l);
EXPECT_EQ(str_end - too_big_negative_number, 22l);

const char *long_number_range_test =
"10000000000000000000000000000000000000000000000000";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoll(long_number_range_test, &str_end, 10),
LLONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - long_number_range_test, 50l);

const char *long_long_max_number_with_numbers_after =
"9223372036854775807123";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoll(long_long_max_number_with_numbers_after,
&str_end, 10),
LLONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - long_long_max_number_with_numbers_after, 22l);
}

TEST(LlvmLibcStrToLLTest, MessyBaseTenDecode) {
Expand Down Expand Up @@ -145,7 +176,7 @@ static char int_to_b36_char(int input) {

TEST(LlvmLibcStrToLLTest, DecodeInOtherBases) {
char small_string[4] = {'\0', '\0', '\0', '\0'};
for (int base = 2; base <= 36; ++base) {
for (unsigned int base = 2; base <= 36; ++base) {
for (long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
if (first_digit < base) {
Expand All @@ -161,7 +192,7 @@ TEST(LlvmLibcStrToLLTest, DecodeInOtherBases) {
}
}

for (int base = 2; base <= 36; ++base) {
for (unsigned int base = 2; base <= 36; ++base) {
for (long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (long long second_digit = 0; second_digit <= 36; ++second_digit) {
Expand All @@ -185,7 +216,7 @@ TEST(LlvmLibcStrToLLTest, DecodeInOtherBases) {
}
}

for (int base = 2; base <= 36; ++base) {
for (unsigned int base = 2; base <= 36; ++base) {
for (long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (long long second_digit = 0; second_digit <= 36; ++second_digit) {
Expand Down
284 changes: 284 additions & 0 deletions libc/test/src/stdlib/strtoul_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
//===-- Unittests for strtoul ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdlib/strtoul.h"

#include "utils/UnitTest/Test.h"

#include <errno.h>
#include <limits.h>

TEST(LlvmLibcStrToULTest, InvalidBase) {
const char *ten = "10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(ten, nullptr, -1), 0ul);
ASSERT_EQ(errno, EINVAL);
}

TEST(LlvmLibcStrToULTest, CleanBaseTenDecode) {
char *str_end = nullptr;

const char *ten = "10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(ten, &str_end, 10), 10ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - ten, 2l);
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(ten, nullptr, 10), 10ul);
ASSERT_EQ(errno, 0);

const char *hundred = "100";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(hundred, &str_end, 10), 100ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - hundred, 3l);

const char *negative = "-100";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(negative, &str_end, 10), -(100ul));
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - negative, 4l);

const char *big_number = "123456789012345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(big_number, &str_end, 10), 123456789012345ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - big_number, 15l);

const char *too_big_number = "123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(too_big_number, &str_end, 10), ULONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - too_big_number, 21l);

const char *too_big_negative_number = "-123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(too_big_negative_number, &str_end, 10),
ULONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - too_big_negative_number, 22l);

const char *long_number_range_test =
"10000000000000000000000000000000000000000000000000";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(long_number_range_test, &str_end, 10),
ULONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - long_number_range_test, 50l);
}

TEST(LlvmLibcStrToULTest, MessyBaseTenDecode) {
char *str_end = nullptr;

const char *spaces_before = " 10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(spaces_before, &str_end, 10), 10ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - spaces_before, 7l);

const char *spaces_after = "10 ";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(spaces_after, &str_end, 10), 10ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - spaces_after, 2l);

const char *word_before = "word10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(word_before, &str_end, 10), 0ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - word_before, 0l);

const char *word_after = "10word";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(word_after, &str_end, 10), 10ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - word_after, 2l);

const char *two_numbers = "10 999";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(two_numbers, &str_end, 10), 10ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - two_numbers, 2l);

const char *two_signs = "--10 999";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(two_signs, &str_end, 10), 0ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - two_signs, 1l);

const char *sign_before = "+2=4";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(sign_before, &str_end, 10), 2ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - sign_before, 2l);

const char *sign_after = "2+2=4";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(sign_after, &str_end, 10), 2ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - sign_after, 1l);

const char *tab_before = "\t10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(tab_before, &str_end, 10), 10ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - tab_before, 3l);

const char *all_together = "\t -12345and+67890";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(all_together, &str_end, 10), -(12345ul));
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - all_together, 9l);
}

static char int_to_b36_char(int input) {
if (input < 0 || input > 36)
return '0';
if (input < 10)
return '0' + input;
return 'A' + input - 10;
}

TEST(LlvmLibcStrToULTest, DecodeInOtherBases) {
char small_string[4] = {'\0', '\0', '\0', '\0'};
for (unsigned int base = 2; base <= 36; ++base) {
for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
if (first_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
ASSERT_EQ(errno, 0);
}
}
}

for (unsigned int base = 2; base <= 36; ++base) {
for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (unsigned long second_digit = 0; second_digit <= 36; ++second_digit) {
small_string[1] = int_to_b36_char(second_digit);
if (first_digit < base && second_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
second_digit + (first_digit * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
ASSERT_EQ(errno, 0);
}
}
}
}

for (unsigned int base = 2; base <= 36; ++base) {
for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (unsigned long second_digit = 0; second_digit <= 36; ++second_digit) {
small_string[1] = int_to_b36_char(second_digit);
for (unsigned long third_digit = 0; third_digit <= 36; ++third_digit) {
small_string[2] = int_to_b36_char(third_digit);

if (first_digit < base && second_digit < base && third_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
third_digit + (second_digit * base) +
(first_digit * base * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base && second_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
second_digit + (first_digit * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base) {
// if the base is 16 there is a special case for the prefix 0X.
// The number is treated as a one digit hexadecimal.
if (base == 16 && first_digit == 0 && second_digit == 33) {
if (third_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
third_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
0ul);
ASSERT_EQ(errno, 0);
}
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
}
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
ASSERT_EQ(errno, 0);
}
}
}
}
}
}

TEST(LlvmLibcStrToULTest, CleanBaseSixteenDecode) {
char *str_end = nullptr;

const char *no_prefix = "123abc";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(no_prefix, &str_end, 16), 0x123abcul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - no_prefix, 6l);

const char *yes_prefix = "0x456def";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(yes_prefix, &str_end, 16), 0x456deful);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - yes_prefix, 8l);
}

TEST(LlvmLibcStrToULTest, AutomaticBaseSelection) {
char *str_end = nullptr;

const char *base_ten = "12345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(base_ten, &str_end, 0), 12345ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_ten, 5l);

const char *base_sixteen_no_prefix = "123abc";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(base_sixteen_no_prefix, &str_end, 0), 123ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_sixteen_no_prefix, 3l);

const char *base_sixteen_with_prefix = "0x456def";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(base_sixteen_with_prefix, &str_end, 0),
0x456deful);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_sixteen_with_prefix, 8l);

const char *base_eight_with_prefix = "012345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoul(base_eight_with_prefix, &str_end, 0),
012345ul);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_eight_with_prefix, 6l);
}
295 changes: 295 additions & 0 deletions libc/test/src/stdlib/strtoull_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
//===-- Unittests for strtoull --------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/stdlib/strtoull.h"

#include "utils/UnitTest/Test.h"

#include <errno.h>
#include <limits.h>

TEST(LlvmLibcStrToULLTest, InvalidBase) {
const char *ten = "10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(ten, nullptr, -1), 0ull);
ASSERT_EQ(errno, EINVAL);
}

TEST(LlvmLibcStrToULLTest, CleanBaseTenDecode) {
char *str_end = nullptr;

const char *ten = "10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(ten, &str_end, 10), 10ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - ten, 2l);
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(ten, nullptr, 10), 10ull);
ASSERT_EQ(errno, 0);

const char *hundred = "100";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(hundred, &str_end, 10), 100ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - hundred, 3l);

const char *negative = "-100";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(negative, &str_end, 10), -(100ull));
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - negative, 4l);

const char *big_number = "123456789012345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(big_number, &str_end, 10),
123456789012345ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - big_number, 15l);

const char *unsigned_long_long_max_number = "18446744073709551615";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(unsigned_long_long_max_number, &str_end, 10),
18446744073709551615ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - unsigned_long_long_max_number, 20l);

const char *too_big_number = "123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(too_big_number, &str_end, 10), ULLONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - too_big_number, 21l);

const char *too_big_negative_number = "-123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(too_big_negative_number, &str_end, 10),
ULLONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - too_big_negative_number, 22l);

const char *long_number_range_test =
"10000000000000000000000000000000000000000000000000";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(long_number_range_test, &str_end, 10),
ULLONG_MAX);
ASSERT_EQ(errno, ERANGE);
EXPECT_EQ(str_end - long_number_range_test, 50l);
}

TEST(LlvmLibcStrToULLTest, MessyBaseTenDecode) {
char *str_end = nullptr;

const char *spaces_before = " 10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(spaces_before, &str_end, 10), 10ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - spaces_before, 7l);

const char *spaces_after = "10 ";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(spaces_after, &str_end, 10), 10ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - spaces_after, 2l);

const char *word_before = "word10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(word_before, &str_end, 10), 0ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - word_before, 0l);

const char *word_after = "10word";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(word_after, &str_end, 10), 10ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - word_after, 2l);

const char *two_numbers = "10 999";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(two_numbers, &str_end, 10), 10ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - two_numbers, 2l);

const char *two_signs = "--10 999";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(two_signs, &str_end, 10), 0ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - two_signs, 1l);

const char *sign_before = "+2=4";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(sign_before, &str_end, 10), 2ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - sign_before, 2l);

const char *sign_after = "2+2=4";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(sign_after, &str_end, 10), 2ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - sign_after, 1l);

const char *tab_before = "\t10";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(tab_before, &str_end, 10), 10ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - tab_before, 3l);

const char *all_together = "\t -12345and+67890";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(all_together, &str_end, 10), -(12345ull));
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - all_together, 9l);
}

static char int_to_b36_char(int input) {
if (input < 0 || input > 36)
return '0';
if (input < 10)
return '0' + input;
return 'A' + input - 10;
}

TEST(LlvmLibcStrToULLTest, DecodeInOtherBases) {
char small_string[4] = {'\0', '\0', '\0', '\0'};
for (unsigned int base = 2; base <= 36; ++base) {
for (unsigned long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
if (first_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base), 0ull);
ASSERT_EQ(errno, 0);
}
}
}

for (unsigned int base = 2; base <= 36; ++base) {
for (unsigned long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (unsigned long long second_digit = 0; second_digit <= 36;
++second_digit) {
small_string[1] = int_to_b36_char(second_digit);
if (first_digit < base && second_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
second_digit + (first_digit * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base), 0ull);
ASSERT_EQ(errno, 0);
}
}
}
}

for (unsigned int base = 2; base <= 36; ++base) {
for (unsigned long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (unsigned long long second_digit = 0; second_digit <= 36;
++second_digit) {
small_string[1] = int_to_b36_char(second_digit);
for (unsigned long long third_digit = 0; third_digit <= 36;
++third_digit) {
small_string[2] = int_to_b36_char(third_digit);

if (first_digit < base && second_digit < base && third_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
third_digit + (second_digit * base) +
(first_digit * base * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base && second_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
second_digit + (first_digit * base));
ASSERT_EQ(errno, 0);
} else if (first_digit < base) {
// if the base is 16 there is a special case for the prefix 0X.
// The number is treated as a one digit hexadecimal.
if (base == 16 && first_digit == 0 && second_digit == 33) {
if (third_digit < base) {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
third_digit);
ASSERT_EQ(errno, 0);
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
0ull);
ASSERT_EQ(errno, 0);
}
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
first_digit);
ASSERT_EQ(errno, 0);
}
} else {
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base), 0ull);
ASSERT_EQ(errno, 0);
}
}
}
}
}
}

TEST(LlvmLibcStrToULLTest, CleanBaseSixteenDecode) {
char *str_end = nullptr;

const char *no_prefix = "123abc";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(no_prefix, &str_end, 16), 0x123abcull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - no_prefix, 6l);

const char *yes_prefix = "0x456def";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(yes_prefix, &str_end, 16), 0x456defull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - yes_prefix, 8l);
}

TEST(LlvmLibcStrToULLTest, AutomaticBaseSelection) {
char *str_end = nullptr;

const char *base_ten = "12345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(base_ten, &str_end, 0), 12345ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_ten, 5l);

const char *base_sixteen_no_prefix = "123abc";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(base_sixteen_no_prefix, &str_end, 0), 123ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_sixteen_no_prefix, 3l);

const char *base_sixteen_with_prefix = "0x456def";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(base_sixteen_with_prefix, &str_end, 0),
0x456defull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_sixteen_with_prefix, 8l);

const char *base_eight_with_prefix = "012345";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoull(base_eight_with_prefix, &str_end, 0),
012345ull);
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - base_eight_with_prefix, 6l);
}