diff options
Diffstat (limited to 'libc/test/src')
-rw-r--r-- | libc/test/src/__support/FPUtil/comparison_operations_test.cpp | 27 | ||||
-rw-r--r-- | libc/test/src/math/generic/CMakeLists.txt | 1 | ||||
-rw-r--r-- | libc/test/src/math/smoke/CMakeLists.txt | 13 | ||||
-rw-r--r-- | libc/test/src/math/smoke/fabsbf16_test.cpp | 14 | ||||
-rw-r--r-- | libc/test/src/sched/CMakeLists.txt | 27 | ||||
-rw-r--r-- | libc/test/src/sched/affinity_test.cpp | 3 | ||||
-rw-r--r-- | libc/test/src/sched/cpu_count_test.cpp | 5 | ||||
-rw-r--r-- | libc/test/src/sched/get_priority_test.cpp | 2 | ||||
-rw-r--r-- | libc/test/src/sched/getcpu_test.cpp | 30 | ||||
-rw-r--r-- | libc/test/src/sched/param_and_scheduler_test.cpp | 3 | ||||
-rw-r--r-- | libc/test/src/sched/sched_rr_get_interval_test.cpp | 3 | ||||
-rw-r--r-- | libc/test/src/wchar/CMakeLists.txt | 47 | ||||
-rw-r--r-- | libc/test/src/wchar/mbsnrtowcs_test.cpp | 212 | ||||
-rw-r--r-- | libc/test/src/wchar/mbsrtowcs_test.cpp | 185 | ||||
-rw-r--r-- | libc/test/src/wchar/mbstowcs_test.cpp | 171 | ||||
-rw-r--r-- | libc/test/src/wchar/wcstok_test.cpp | 8 |
16 files changed, 718 insertions, 33 deletions
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp index 04a3321..05b8f68 100644 --- a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp +++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp @@ -25,28 +25,15 @@ template <typename T> class ComparisonOperationsTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { DECLARE_SPECIAL_CONSTANTS(T) - // TODO: Make these constexpr once quick_get_round is made constexpr. - T normal1; - T neg_normal1; - T normal2; - T small; - T neg_small; - T large; - T neg_large; + static constexpr T normal1 = T(3.14); + static constexpr T neg_normal1 = T(-3.14); + static constexpr T normal2 = T(2.71); + static constexpr T small = T(0.1); + static constexpr T neg_small = T(-0.1); + static constexpr T large = T(10000.0); + static constexpr T neg_large = T(-10000.0); public: - void SetUp() override { - with_fenv_preserved([this]() { - normal1 = T(3.14); - neg_normal1 = T(-3.14); - normal2 = T(2.71); - small = T(0.1); - neg_small = T(-0.1); - large = T(10000.0); - neg_large = T(-10000.0); - }); - } - void test_equals() { EXPECT_TRUE(equals(neg_zero, neg_zero)); EXPECT_TRUE(equals(zero, neg_zero)); diff --git a/libc/test/src/math/generic/CMakeLists.txt b/libc/test/src/math/generic/CMakeLists.txt index 1fe7801..a9d54d6 100644 --- a/libc/test/src/math/generic/CMakeLists.txt +++ b/libc/test/src/math/generic/CMakeLists.txt @@ -30,4 +30,3 @@ add_fp_unittest( DEPENDS libc.src.math.generic.ceill ) - diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index ec4c09c..40b7a342 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -221,6 +221,19 @@ add_fp_unittest( ) add_fp_unittest( + fabsbf16_test + SUITE + libc-math-smoke-tests + SRCS + fabsbf16_test.cpp + HDRS + FAbsTest.h + DEPENDS + libc.src.__support.FPUtil.bfloat16 + libc.src.math.fabsbf16 +) + +add_fp_unittest( fadd_test SUITE libc-math-smoke-tests diff --git a/libc/test/src/math/smoke/fabsbf16_test.cpp b/libc/test/src/math/smoke/fabsbf16_test.cpp new file mode 100644 index 0000000..611050a --- /dev/null +++ b/libc/test/src/math/smoke/fabsbf16_test.cpp @@ -0,0 +1,14 @@ +//===-- Unittests for fabsbf16 --------------------------------------------===// +// +// 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 "FAbsTest.h" + +#include "src/__support/FPUtil/bfloat16.h" +#include "src/math/fabsbf16.h" + +LIST_FABS_TESTS(bfloat16, LIBC_NAMESPACE::fabsbf16) diff --git a/libc/test/src/sched/CMakeLists.txt b/libc/test/src/sched/CMakeLists.txt index 9dda4ea..362c526 100644 --- a/libc/test/src/sched/CMakeLists.txt +++ b/libc/test/src/sched/CMakeLists.txt @@ -7,7 +7,8 @@ add_libc_unittest( SRCS affinity_test.cpp DEPENDS - libc.include.sched + libc.hdr.types.cpu_set_t + libc.hdr.types.pid_t libc.include.sys_syscall libc.src.__support.OSUtil.osutil libc.src.errno.errno @@ -34,20 +35,33 @@ add_libc_unittest( SRCS get_priority_test.cpp DEPENDS - libc.include.sched + libc.hdr.sched_macros libc.src.errno.errno libc.src.sched.sched_get_priority_min libc.src.sched.sched_get_priority_max ) add_libc_unittest( + getcpu_test + SUITE + libc_sched_unittests + SRCS + getcpu_test.cpp + DEPENDS + libc.src.errno.errno + libc.src.sched.getcpu + libc.test.UnitTest.ErrnoCheckingTest +) + +add_libc_unittest( scheduler_test SUITE libc_sched_unittests SRCS param_and_scheduler_test.cpp DEPENDS - libc.include.sched + libc.hdr.sched_macros + libc.hdr.types.struct_sched_param libc.src.errno.errno libc.src.sched.sched_getscheduler libc.src.sched.sched_setscheduler @@ -65,7 +79,8 @@ add_libc_unittest( SRCS sched_rr_get_interval_test.cpp DEPENDS - libc.include.sched + libc.hdr.sched_macros + libc.hdr.types.struct_timespec libc.src.errno.errno libc.src.sched.sched_getscheduler libc.src.sched.sched_setscheduler @@ -81,7 +96,9 @@ add_libc_unittest( SRCS cpu_count_test.cpp DEPENDS - libc.include.sched + libc.hdr.sched_macros + libc.hdr.types.cpu_set_t + libc.hdr.types.pid_t libc.include.sys_syscall libc.src.__support.OSUtil.osutil libc.src.errno.errno diff --git a/libc/test/src/sched/affinity_test.cpp b/libc/test/src/sched/affinity_test.cpp index b77f22f..1c8599b 100644 --- a/libc/test/src/sched/affinity_test.cpp +++ b/libc/test/src/sched/affinity_test.cpp @@ -12,7 +12,8 @@ #include "src/sched/sched_setaffinity.h" #include "test/UnitTest/ErrnoSetterMatcher.h" -#include <sched.h> +#include "hdr/types/cpu_set_t.h" +#include "hdr/types/pid_t.h" #include <sys/syscall.h> TEST(LlvmLibcSchedAffinityTest, SmokeTest) { diff --git a/libc/test/src/sched/cpu_count_test.cpp b/libc/test/src/sched/cpu_count_test.cpp index 919f147..06e4fff 100644 --- a/libc/test/src/sched/cpu_count_test.cpp +++ b/libc/test/src/sched/cpu_count_test.cpp @@ -12,8 +12,9 @@ #include "src/sched/sched_getcpucount.h" #include "test/UnitTest/ErrnoSetterMatcher.h" -#include <sched.h> -#include <sys/syscall.h> +#include "hdr/sched_macros.h" +#include "hdr/types/cpu_set_t.h" +#include "hdr/types/pid_t.h" TEST(LlvmLibcSchedCpuCountTest, SmokeTest) { cpu_set_t mask; diff --git a/libc/test/src/sched/get_priority_test.cpp b/libc/test/src/sched/get_priority_test.cpp index bb41dc0b..bf4fca8 100644 --- a/libc/test/src/sched/get_priority_test.cpp +++ b/libc/test/src/sched/get_priority_test.cpp @@ -11,7 +11,7 @@ #include "src/sched/sched_get_priority_min.h" #include "test/UnitTest/Test.h" -#include <sched.h> +#include "hdr/sched_macros.h" TEST(LlvmLibcSchedGetPriorityTest, HandleBadPolicyTest) { diff --git a/libc/test/src/sched/getcpu_test.cpp b/libc/test/src/sched/getcpu_test.cpp new file mode 100644 index 0000000..fc4ada8 --- /dev/null +++ b/libc/test/src/sched/getcpu_test.cpp @@ -0,0 +1,30 @@ +//===-- Unittests for getcpu ----------------------------------------------===// +// +// 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/__support/OSUtil/syscall.h" +#include "src/__support/libc_errno.h" +#include "src/sched/getcpu.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" + +using LlvmLibcSchedGetCpuTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcSchedGetCpuTest, SmokeTest) { + unsigned int current_cpu; + unsigned int current_node; + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; + ASSERT_THAT(LIBC_NAMESPACE::getcpu(¤t_cpu, ¤t_node), Succeeds(0)); +} + +TEST_F(LlvmLibcSchedGetCpuTest, BadPointer) { + unsigned int current_cpu; + unsigned int *current_node = reinterpret_cast<unsigned int *>(-1); + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; + ASSERT_THAT(LIBC_NAMESPACE::getcpu(¤t_cpu, current_node), + Fails(EFAULT)); +} diff --git a/libc/test/src/sched/param_and_scheduler_test.cpp b/libc/test/src/sched/param_and_scheduler_test.cpp index 4f2b6e4..b8ee123 100644 --- a/libc/test/src/sched/param_and_scheduler_test.cpp +++ b/libc/test/src/sched/param_and_scheduler_test.cpp @@ -16,7 +16,8 @@ #include "src/unistd/getuid.h" #include "test/UnitTest/Test.h" -#include <sched.h> +#include "hdr/sched_macros.h" +#include "hdr/types/struct_sched_param.h" // We Test: // SCHED_OTHER, SCHED_FIFO, SCHED_RR diff --git a/libc/test/src/sched/sched_rr_get_interval_test.cpp b/libc/test/src/sched/sched_rr_get_interval_test.cpp index a0fe5ed..e5dc4e3 100644 --- a/libc/test/src/sched/sched_rr_get_interval_test.cpp +++ b/libc/test/src/sched/sched_rr_get_interval_test.cpp @@ -14,7 +14,8 @@ #include "src/unistd/getuid.h" #include "test/UnitTest/Test.h" -#include <sched.h> +#include "hdr/sched_macros.h" +#include "hdr/types/struct_timespec.h" TEST(LlvmLibcSchedRRGetIntervalTest, SmokeTest) { libc_errno = 0; diff --git a/libc/test/src/wchar/CMakeLists.txt b/libc/test/src/wchar/CMakeLists.txt index fad89dc..d1a0684 100644 --- a/libc/test/src/wchar/CMakeLists.txt +++ b/libc/test/src/wchar/CMakeLists.txt @@ -76,6 +76,19 @@ add_libc_test( ) add_libc_test( + mbstowcs_test + SUITE + libc_wchar_unittests + SRCS + mbstowcs_test.cpp + DEPENDS + libc.src.__support.libc_errno + libc.src.wchar.mbstowcs + libc.hdr.types.wchar_t + libc.test.UnitTest.ErrnoCheckingTest +) + +add_libc_test( mblen_test SUITE libc_wchar_unittests @@ -88,6 +101,22 @@ add_libc_test( ) add_libc_test( + mbsrtowcs_test + SUITE + libc_wchar_unittests + SRCS + mbsrtowcs_test.cpp + DEPENDS + libc.src.__support.libc_errno + libc.src.__support.wchar.mbstate + libc.src.string.memset + libc.src.wchar.mbsrtowcs + libc.hdr.types.mbstate_t + libc.hdr.types.wchar_t + libc.test.UnitTest.ErrnoCheckingTest +) + +add_libc_test( mbrlen_test SUITE libc_wchar_unittests @@ -97,7 +126,23 @@ add_libc_test( libc.src.__support.libc_errno libc.src.__support.wchar.mbstate libc.src.string.memset - libc.src.wchar.mbrlen + libc.src.wchar.mbsrlen + libc.hdr.types.mbstate_t + libc.hdr.types.wchar_t + libc.test.UnitTest.ErrnoCheckingTest +) + +add_libc_test( + mbsnrtowcs_test + SUITE + libc_wchar_unittests + SRCS + mbsnrtowcs_test.cpp + DEPENDS + libc.src.__support.libc_errno + libc.src.__support.wchar.mbstate + libc.src.string.memset + libc.src.wchar.mbsnrtowcs libc.hdr.types.mbstate_t libc.hdr.types.wchar_t libc.test.UnitTest.ErrnoCheckingTest diff --git a/libc/test/src/wchar/mbsnrtowcs_test.cpp b/libc/test/src/wchar/mbsnrtowcs_test.cpp new file mode 100644 index 0000000..a3de68f --- /dev/null +++ b/libc/test/src/wchar/mbsnrtowcs_test.cpp @@ -0,0 +1,212 @@ +//===-- Unittests for mbsetowcs -------------------------------------------===// +// +// 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 "hdr/types/mbstate_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/null_check.h" +#include "src/__support/wchar/mbstate.h" +#include "src/string/memset.h" +#include "src/wchar/mbsnrtowcs.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcMBSNRToWCSTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcMBSNRToWCSTest, OneByteOneChar) { + const char *ch = "A"; + const char *original = ch; + wchar_t dest[2]; + mbstate_t mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &ch, 1, 1, &mb); + ASSERT_EQ(static_cast<char>(*dest), 'A'); + ASSERT_EQ(static_cast<int>(n), 1); + // Should point to null terminator now + ASSERT_EQ(ch, original + 1); + ASSERT_ERRNO_SUCCESS(); + + n = LIBC_NAMESPACE::mbsnrtowcs(dest + 1, &ch, 1, 1, &mb); + ASSERT_EQ(static_cast<char>(dest[1]), '\0'); + // Should not include null terminator + ASSERT_EQ(static_cast<int>(n), 0); + // Should now be a nullptr + ASSERT_EQ(ch, nullptr); + ASSERT_ERRNO_SUCCESS(); +} + +TEST_F(LlvmLibcMBSNRToWCSTest, FourByteOneChar) { + const char *src = "\xf0\x9f\x98\xb9"; // laughing cat emoji 😹 + const char *original = src; + wchar_t dest[2]; + mbstate_t mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + // Not enough bytes for the full character + size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 3, 2, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(n), 0); + ASSERT_EQ(src, original + 3); + // Needs 2 more bytes (last byte of cat + null terminator) + n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 2, 2, &mb); + ASSERT_ERRNO_SUCCESS(); + // Does not include null terminator + ASSERT_EQ(static_cast<int>(n), 1); + ASSERT_EQ(src, nullptr); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_TRUE(dest[1] == L'\0'); +} + +TEST_F(LlvmLibcMBSNRToWCSTest, MixedNumberOfBytes) { + // 'A', sigma symbol 'Σ', recycling symbol 'â™»', laughing cat emoji '😹' + const char *src = "A\xce\xa3\xe2\x99\xbb\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5]; + mbstate_t mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + + // Read 'A' + size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 1, 1, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<char>(dest[0]), 'A'); + ASSERT_EQ(static_cast<int>(n), 1); + ASSERT_EQ(src, original + 1); + + // Read sigma 'Σ' + n = LIBC_NAMESPACE::mbsnrtowcs(dest + 1, &src, 2, 1, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(dest[1]), 931); + ASSERT_EQ(static_cast<int>(n), 1); + ASSERT_EQ(src, original + 3); + + // Read recycling 'â™»' + n = LIBC_NAMESPACE::mbsnrtowcs(dest + 2, &src, 2, 5, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(n), 0); + ASSERT_EQ(src, original + 5); + n = LIBC_NAMESPACE::mbsnrtowcs(dest + 2, &src, 1, 1, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(n), 1); + ASSERT_EQ(src, original + 6); + ASSERT_EQ(static_cast<int>(dest[2]), 9851); + + // Read laughing cat emoji '😹' + n = LIBC_NAMESPACE::mbsnrtowcs(dest + 3, &src, 4, 5, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(n), 1); + ASSERT_EQ(src, original + 10); + ASSERT_EQ(static_cast<int>(dest[3]), 128569); + + n = LIBC_NAMESPACE::mbsnrtowcs(dest + 4, &src, 4, 4, nullptr); + ASSERT_TRUE(dest[4] == L'\0'); + ASSERT_ERRNO_SUCCESS(); + // Should not count null terminator in number + ASSERT_EQ(static_cast<int>(n), 0); + // Should now be a nullptr + ASSERT_EQ(src, nullptr); +} + +TEST_F(LlvmLibcMBSNRToWCSTest, ReadLessThanStringLength) { + // Four laughing cat emojis "😹😹😹😹" + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5] = {L'a', L'b', L'c', L'd', L'e'}; + size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 100, 3, nullptr); + ASSERT_ERRNO_SUCCESS(); + // Should have read 3 emojis + ASSERT_EQ(static_cast<int>(n), 3); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_EQ(static_cast<int>(dest[1]), 128569); + ASSERT_EQ(static_cast<int>(dest[2]), 128569); + ASSERT_TRUE(dest[3] == L'd'); + ASSERT_TRUE(dest[4] == L'e'); + // Read three laughing cat emojis, 12 bytes + ASSERT_EQ(src, original + 12); +} + +TEST_F(LlvmLibcMBSNRToWCSTest, InvalidFirstByte) { + // 0x80 is invalid first byte of mb character + const char *src = + "\x80\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[3]; + size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 88, 88, nullptr); + // Should return error and set errno + ASSERT_EQ(static_cast<int>(n), -1); + ASSERT_ERRNO_EQ(EILSEQ); + // Should not update pointer + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSNRToWCSTest, InvalidMiddleByte) { + // The 7th byte is invalid for a 4 byte character + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\xf0\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[3]; + mbstate_t mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + // Successfully read one character and first byte of the second character + size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 5, 88, &mb); + ASSERT_EQ(static_cast<int>(n), 1); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(src, original + 5); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + + n = LIBC_NAMESPACE::mbsnrtowcs(dest + 1, &src, 5, 88, &mb); + // Should return error, set errno, and not update the pointer + ASSERT_EQ(static_cast<int>(n), -1); + ASSERT_ERRNO_EQ(EILSEQ); + ASSERT_EQ(src, original + 5); +} + +TEST_F(LlvmLibcMBSNRToWCSTest, NullDestination) { + // Four laughing cat emojis "😹😹😹😹" + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + size_t n = LIBC_NAMESPACE::mbsnrtowcs(nullptr, &src, 88, 88, nullptr); + ASSERT_ERRNO_SUCCESS(); + // Null destination should ignore len and read till end of string + ASSERT_EQ(static_cast<int>(n), 4); + // It should also not change the src pointer + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSNRToWCSTest, ErrnoChecks) { + // Two laughing cat emojis and invalid 3rd mb char (3rd byte of it) + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\xf0\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5]; + mbstate_t mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + // First two bytes are valid --> should not set errno + size_t n = LIBC_NAMESPACE::mbsnrtowcs(dest, &src, 80, 2, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(n), 2); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_EQ(static_cast<int>(dest[1]), 128569); + ASSERT_EQ(src, original + 8); + + // Trying to read the 3rd byte should set errno + n = LIBC_NAMESPACE::mbsnrtowcs(dest + 2, &src, 4, 2, &mb); + ASSERT_ERRNO_EQ(EILSEQ); + ASSERT_EQ(static_cast<int>(n), -1); + // Should not move the pointer + ASSERT_EQ(src, original + 8); +} + +#if defined(LIBC_ADD_NULL_CHECKS) +TEST(LlvmLibcMBSNRToWCSTest, NullptrCrash) { + // Passing in a nullptr should crash the program. + EXPECT_DEATH( + [] { LIBC_NAMESPACE::mbsnrtowcs(nullptr, nullptr, 1, 1, nullptr); }, + WITH_SIGNAL(-1)); +} +#endif // LIBC_ADD_NULL_CHECKS diff --git a/libc/test/src/wchar/mbsrtowcs_test.cpp b/libc/test/src/wchar/mbsrtowcs_test.cpp new file mode 100644 index 0000000..59efc0d --- /dev/null +++ b/libc/test/src/wchar/mbsrtowcs_test.cpp @@ -0,0 +1,185 @@ +//===-- Unittests for mbsetowcs -------------------------------------------===// +// +// 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 "hdr/types/mbstate_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/null_check.h" +#include "src/__support/wchar/mbstate.h" +#include "src/string/memset.h" +#include "src/wchar/mbsrtowcs.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcMBSRToWCSTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcMBSRToWCSTest, OneByteOneChar) { + const char *ch = "A"; + const char *original = ch; + wchar_t dest[2]; + mbstate_t mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &ch, 1, &mb); + ASSERT_EQ(static_cast<char>(*dest), 'A'); + ASSERT_EQ(static_cast<int>(n), 1); + // Should point to null terminator now + ASSERT_EQ(ch, original + 1); + ASSERT_ERRNO_SUCCESS(); + + n = LIBC_NAMESPACE::mbsrtowcs(dest + 1, &ch, 1, &mb); + ASSERT_EQ(static_cast<char>(dest[1]), '\0'); + // Should not include null terminator + ASSERT_EQ(static_cast<int>(n), 0); + // Should now be a nullptr + ASSERT_EQ(ch, nullptr); + ASSERT_ERRNO_SUCCESS(); +} + +TEST_F(LlvmLibcMBSRToWCSTest, FourByteOneChar) { + const char *src = "\xf0\x9f\x98\xb9"; // laughing cat emoji 😹 + wchar_t dest[2]; + mbstate_t mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 2, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_TRUE(dest[1] == L'\0'); + // Should not count null terminator in number + ASSERT_EQ(static_cast<int>(n), 1); + // Should now be a nullptr + ASSERT_EQ(src, nullptr); +} + +TEST_F(LlvmLibcMBSRToWCSTest, MultiByteTwoCharacters) { + // Two laughing cat emojis "😹😹" + const char *src = "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + wchar_t dest[3]; + mbstate_t mb; + LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t)); + size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 3, &mb); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_EQ(static_cast<int>(dest[1]), 128569); + ASSERT_TRUE(dest[2] == L'\0'); + // Should not count null terminator in number + ASSERT_EQ(static_cast<int>(n), 2); + // Should now be a nullptr + ASSERT_EQ(src, nullptr); +} + +TEST_F(LlvmLibcMBSRToWCSTest, MixedNumberOfBytes) { + // 'A', sigma symbol 'Σ', recycling symbol 'â™»', laughing cat emoji '😹' + const char *src = "A\xce\xa3\xe2\x99\xbb\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5]; + size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 4, nullptr); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<char>(dest[0]), 'A'); + ASSERT_EQ(static_cast<int>(dest[1]), 931); + ASSERT_EQ(static_cast<int>(dest[2]), 9851); + ASSERT_EQ(static_cast<int>(dest[3]), 128569); + // Should point to null terminator (byte at 10th index) + ASSERT_EQ(src, original + 10); + ASSERT_EQ(static_cast<int>(n), 4); + n = LIBC_NAMESPACE::mbsrtowcs(dest + 4, &src, 4, nullptr); + ASSERT_TRUE(dest[4] == L'\0'); + ASSERT_ERRNO_SUCCESS(); + // Should not count null terminator in number + ASSERT_EQ(static_cast<int>(n), 0); + // Should now be a nullptr + ASSERT_EQ(src, nullptr); +} + +TEST_F(LlvmLibcMBSRToWCSTest, ReadLessThanStringLength) { + // Four laughing cat emojis "😹😹😹😹" + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5] = {L'a', L'b', L'c', L'd', L'e'}; + size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 3, nullptr); + ASSERT_ERRNO_SUCCESS(); + // Should have read 3 emojis + ASSERT_EQ(static_cast<int>(n), 3); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_EQ(static_cast<int>(dest[1]), 128569); + ASSERT_EQ(static_cast<int>(dest[2]), 128569); + ASSERT_TRUE(dest[3] == L'd'); + ASSERT_TRUE(dest[4] == L'e'); + // Read three laughing cat emojis, 12 bytes + ASSERT_EQ(src, original + 12); +} + +TEST_F(LlvmLibcMBSRToWCSTest, InvalidFirstByte) { + // 0x80 is invalid first byte of mb character + const char *src = + "\x80\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[3]; + size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 3, nullptr); + // Should return error and set errno + ASSERT_EQ(static_cast<int>(n), -1); + ASSERT_ERRNO_EQ(EILSEQ); + // Should not update pointer + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSRToWCSTest, InvalidMiddleByte) { + // The 7th byte is invalid for a 4 byte character + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\xf0\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[3]; + size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 5, nullptr); + // Should return error, set errno, and not update the pointer + ASSERT_EQ(static_cast<int>(n), -1); + ASSERT_ERRNO_EQ(EILSEQ); + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSRToWCSTest, NullDestination) { + // Four laughing cat emojis "😹😹😹😹" + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + size_t n = LIBC_NAMESPACE::mbsrtowcs(nullptr, &src, 2, nullptr); + ASSERT_ERRNO_SUCCESS(); + // Null destination should ignore len and read till end of string + ASSERT_EQ(static_cast<int>(n), 4); + // It should also not change the src pointer + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSRToWCSTest, ErrnoChecks) { + // Two laughing cat emojis and invalid 3rd mb char (3rd byte of it) + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\xf0\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5]; + // First two bytes are valid --> should not set errno + size_t n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 2, nullptr); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(n), 2); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_EQ(static_cast<int>(dest[1]), 128569); + ASSERT_EQ(src, original + 8); + + // Trying to read the 3rd byte should set errno + n = LIBC_NAMESPACE::mbsrtowcs(dest, &src, 2, nullptr); + ASSERT_ERRNO_EQ(EILSEQ); + ASSERT_EQ(static_cast<int>(n), -1); + // Should not move the pointer + ASSERT_EQ(src, original + 8); +} + +#if defined(LIBC_ADD_NULL_CHECKS) +TEST(LlvmLibcMBSRToWCSTest, NullptrCrash) { + // Passing in a nullptr should crash the program. + EXPECT_DEATH([] { LIBC_NAMESPACE::mbsrtowcs(nullptr, nullptr, 1, nullptr); }, + WITH_SIGNAL(-1)); +} +#endif // LIBC_ADD_NULL_CHECKS diff --git a/libc/test/src/wchar/mbstowcs_test.cpp b/libc/test/src/wchar/mbstowcs_test.cpp new file mode 100644 index 0000000..f0396e0 --- /dev/null +++ b/libc/test/src/wchar/mbstowcs_test.cpp @@ -0,0 +1,171 @@ +//===-- Unittests for mbstowcs --------------------------------------------===// +// +// 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 "hdr/types/wchar_t.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/null_check.h" +#include "src/wchar/mbstowcs.h" +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcMBSToWCSTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST_F(LlvmLibcMBSToWCSTest, OneByteOneChar) { + const char *ch = "A"; + const char *original = ch; + wchar_t dest[2]; + size_t n = LIBC_NAMESPACE::mbstowcs(dest, ch, 1); + ASSERT_EQ(static_cast<char>(*dest), 'A'); + ASSERT_EQ(static_cast<int>(n), 1); + // Making sure the pointer is not getting updated + ASSERT_EQ(ch, original); + ASSERT_ERRNO_SUCCESS(); + + n = LIBC_NAMESPACE::mbstowcs(dest + 1, ch + 1, 1); + ASSERT_EQ(static_cast<char>(dest[1]), '\0'); + // Should not include null terminator + ASSERT_EQ(static_cast<int>(n), 0); + // Making sure the pointer is not getting updated + ASSERT_EQ(ch, original); + ASSERT_ERRNO_SUCCESS(); +} + +TEST_F(LlvmLibcMBSToWCSTest, FourByteOneChar) { + const char *src = "\xf0\x9f\x98\xb9"; // laughing cat emoji 😹 + const char *original = src; + wchar_t dest[2]; + size_t n = LIBC_NAMESPACE::mbstowcs(dest, src, 2); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_TRUE(dest[1] == L'\0'); + // Should not count null terminator in number + ASSERT_EQ(static_cast<int>(n), 1); + // Making sure the pointer is not getting updated + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSToWCSTest, MultiByteTwoCharacters) { + // Two laughing cat emojis "😹😹" + const char *src = "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[3]; + size_t n = LIBC_NAMESPACE::mbstowcs(dest, src, 3); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_EQ(static_cast<int>(dest[1]), 128569); + ASSERT_TRUE(dest[2] == L'\0'); + // Should not count null terminator in number + ASSERT_EQ(static_cast<int>(n), 2); + // Making sure the pointer is not getting updated + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSToWCSTest, MixedNumberOfBytes) { + // 'A', sigma symbol 'Σ', recycling symbol 'â™»', laughing cat emoji '😹' + const char *src = "A\xce\xa3\xe2\x99\xbb\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5]; + size_t n = LIBC_NAMESPACE::mbstowcs(dest, src, 5); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<char>(dest[0]), 'A'); + ASSERT_EQ(static_cast<int>(dest[1]), 931); + ASSERT_EQ(static_cast<int>(dest[2]), 9851); + ASSERT_EQ(static_cast<int>(dest[3]), 128569); + ASSERT_TRUE(dest[4] == L'\0'); + // Should not count null terminator in number + ASSERT_EQ(static_cast<int>(n), 4); + // Making sure the pointer is not getting updated + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSToWCSTest, ReadLessThanStringLength) { + // Four laughing cat emojis "😹😹😹😹" + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5] = {L'a', L'b', L'c', L'd', L'e'}; + size_t n = LIBC_NAMESPACE::mbstowcs(dest, src, 3); + ASSERT_ERRNO_SUCCESS(); + // Should have read 3 emojis + ASSERT_EQ(static_cast<int>(n), 3); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_EQ(static_cast<int>(dest[1]), 128569); + ASSERT_EQ(static_cast<int>(dest[2]), 128569); + ASSERT_TRUE(dest[3] == L'd'); + ASSERT_TRUE(dest[4] == L'e'); + // Making sure the pointer is not getting updated + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSToWCSTest, InvalidFirstByte) { + // 0x80 is invalid first byte of mb character + const char *src = + "\x80\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + wchar_t dest[3]; + size_t n = LIBC_NAMESPACE::mbstowcs(dest, src, 3); + // Should return error and set errno + ASSERT_EQ(static_cast<int>(n), -1); + ASSERT_ERRNO_EQ(EILSEQ); +} + +TEST_F(LlvmLibcMBSToWCSTest, InvalidMiddleByte) { + // The 7th byte is invalid for a 4 byte character + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\xf0\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[3]; + size_t n = LIBC_NAMESPACE::mbstowcs(dest, src, 5); + // Should return error and set errno + ASSERT_EQ(static_cast<int>(n), -1); + ASSERT_ERRNO_EQ(EILSEQ); + // Making sure the pointer is not getting updated + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSToWCSTest, NullDestination) { + // Four laughing cat emojis "😹😹😹😹" + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + size_t n = LIBC_NAMESPACE::mbstowcs(nullptr, src, 2); + ASSERT_ERRNO_SUCCESS(); + // Null destination should ignore len and read till end of string + ASSERT_EQ(static_cast<int>(n), 4); + // Making sure the pointer is not getting updated + ASSERT_EQ(src, original); +} + +TEST_F(LlvmLibcMBSToWCSTest, ErrnoChecks) { + // Two laughing cat emojis and invalid 3rd mb char (3rd byte of it) + const char *src = + "\xf0\x9f\x98\xb9\xf0\x9f\x98\xb9\xf0\x9f\xf0\xb9\xf0\x9f\x98\xb9"; + const char *original = src; + wchar_t dest[5]; + // First two bytes are valid --> should not set errno + size_t n = LIBC_NAMESPACE::mbstowcs(dest, src, 2); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(static_cast<int>(n), 2); + ASSERT_EQ(static_cast<int>(dest[0]), 128569); + ASSERT_EQ(static_cast<int>(dest[1]), 128569); + // Making sure the pointer is not getting updated + ASSERT_EQ(src, original); + // Trying to read the 3rd byte should set errno + n = LIBC_NAMESPACE::mbstowcs(dest, src + 2, 2); + ASSERT_ERRNO_EQ(EILSEQ); + ASSERT_EQ(static_cast<int>(n), -1); + // Making sure the pointer is not getting updated + ASSERT_EQ(src, original); +} + +#if defined(LIBC_ADD_NULL_CHECKS) +TEST(LlvmLibcMBSToWCSTest, NullptrCrash) { + // Passing in a nullptr should crash the program. + EXPECT_DEATH([] { LIBC_NAMESPACE::mbstowcs(nullptr, nullptr, 1); }, + WITH_SIGNAL(-1)); +} +#endif // LIBC_ADD_NULL_CHECKS diff --git a/libc/test/src/wchar/wcstok_test.cpp b/libc/test/src/wchar/wcstok_test.cpp index 7106e9f..3bb1014 100644 --- a/libc/test/src/wchar/wcstok_test.cpp +++ b/libc/test/src/wchar/wcstok_test.cpp @@ -19,6 +19,8 @@ TEST(LlvmLibcWCSTokReentrantTest, NoTokenFound) { // Another call to ensure that 'reserve' is not in a bad state. ASSERT_EQ(LIBC_NAMESPACE::wcstok(empty, L"", &reserve), nullptr); ASSERT_EQ(LIBC_NAMESPACE::wcstok(nullptr, L"", &reserve), nullptr); + // Subsequent searches still return nullptr. + ASSERT_EQ(LIBC_NAMESPACE::wcstok(nullptr, L"", &reserve), nullptr); } { // Empty source and single character delimiter string. wchar_t empty[] = L""; @@ -27,6 +29,8 @@ TEST(LlvmLibcWCSTokReentrantTest, NoTokenFound) { // Another call to ensure that 'reserve' is not in a bad state. ASSERT_EQ(LIBC_NAMESPACE::wcstok(empty, L"_", &reserve), nullptr); ASSERT_EQ(LIBC_NAMESPACE::wcstok(nullptr, L"_", &reserve), nullptr); + // Subsequent searches still return nullptr. + ASSERT_EQ(LIBC_NAMESPACE::wcstok(nullptr, L"_", &reserve), nullptr); } { // Same character source and delimiter string. wchar_t single[] = L"_"; @@ -35,6 +39,8 @@ TEST(LlvmLibcWCSTokReentrantTest, NoTokenFound) { // Another call to ensure that 'reserve' is not in a bad state. ASSERT_EQ(LIBC_NAMESPACE::wcstok(single, L"_", &reserve), nullptr); ASSERT_EQ(LIBC_NAMESPACE::wcstok(nullptr, L"_", &reserve), nullptr); + // Subsequent searches still return nullptr. + ASSERT_EQ(LIBC_NAMESPACE::wcstok(nullptr, L"_", &reserve), nullptr); } { // Multiple character source and single character delimiter string. wchar_t multiple[] = L"1,2"; @@ -51,6 +57,8 @@ TEST(LlvmLibcWCSTokReentrantTest, NoTokenFound) { ASSERT_TRUE(tok[2] == L'2'); ASSERT_TRUE(tok[3] == L'\0'); ASSERT_EQ(LIBC_NAMESPACE::wcstok(nullptr, L":", &reserve), nullptr); + // Subsequent searches still return nullptr. + ASSERT_EQ(LIBC_NAMESPACE::wcstok(nullptr, L":", &reserve), nullptr); } } |