aboutsummaryrefslogtreecommitdiff
path: root/libc/test
diff options
context:
space:
mode:
Diffstat (limited to 'libc/test')
-rw-r--r--libc/test/integration/src/pthread/CMakeLists.txt17
-rw-r--r--libc/test/integration/src/pthread/pthread_barrier_test.cpp117
-rw-r--r--libc/test/integration/src/stdlib/gpu/malloc_stress.cpp28
-rw-r--r--libc/test/shared/CMakeLists.txt4
-rw-r--r--libc/test/shared/shared_math_test.cpp4
-rw-r--r--libc/test/src/__support/FPUtil/comparison_operations_test.cpp27
-rw-r--r--libc/test/src/math/generic/CMakeLists.txt1
-rw-r--r--libc/test/src/math/smoke/CMakeLists.txt13
-rw-r--r--libc/test/src/math/smoke/fabsbf16_test.cpp14
-rw-r--r--libc/test/src/wchar/CMakeLists.txt47
-rw-r--r--libc/test/src/wchar/mbsnrtowcs_test.cpp212
-rw-r--r--libc/test/src/wchar/mbsrtowcs_test.cpp185
-rw-r--r--libc/test/src/wchar/mbstowcs_test.cpp171
13 files changed, 818 insertions, 22 deletions
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 0bdd99c..251b009 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -19,6 +19,23 @@ add_integration_test(
)
add_integration_test(
+ pthread_barrier_test
+ SUITE
+ libc-pthread-integration-tests
+ SRCS
+ pthread_barrier_test.cpp
+ DEPENDS
+ libc.include.pthread
+ libc.src.errno.errno
+ libc.src.pthread.pthread_barrier_destroy
+ libc.src.pthread.pthread_barrier_wait
+ libc.src.pthread.pthread_barrier_init
+ libc.src.pthread.pthread_create
+ libc.src.pthread.pthread_join
+ libc.src.stdio.printf
+)
+
+add_integration_test(
pthread_rwlock_test
SUITE
libc-pthread-integration-tests
diff --git a/libc/test/integration/src/pthread/pthread_barrier_test.cpp b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
new file mode 100644
index 0000000..c8e1104
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
@@ -0,0 +1,117 @@
+//===-- Tests for pthread_barrier_t ---------------------------------------===//
+//
+// 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/pthread/pthread_barrier_destroy.h"
+#include "src/pthread/pthread_barrier_init.h"
+#include "src/pthread/pthread_barrier_wait.h"
+
+#include "src/__support/CPP/atomic.h"
+#include "src/pthread/pthread_create.h"
+#include "src/pthread/pthread_join.h"
+#include "src/pthread/pthread_mutex_destroy.h"
+#include "src/pthread/pthread_mutex_init.h"
+#include "src/pthread/pthread_mutex_lock.h"
+#include "src/pthread/pthread_mutex_unlock.h"
+#include "src/string/memset.h"
+
+#include "test/IntegrationTest/test.h"
+
+#include <pthread.h>
+
+pthread_barrier_t barrier;
+LIBC_NAMESPACE::cpp::Atomic<int> counter;
+
+void *increment_counter_and_wait(void *args) {
+ counter.fetch_add(1);
+ return reinterpret_cast<void *>(
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier));
+}
+
+void single_use_barrier_test(int num_threads) {
+ counter.set(0);
+ // create n - 1 ADDITIONAL threads since the current thread will also wait at
+ // the barrier
+ pthread_t threads[num_threads - 1];
+ LIBC_NAMESPACE::memset(&barrier, 0, sizeof(pthread_barrier_t));
+ ASSERT_EQ(
+ LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, num_threads), 0);
+
+ for (int i = 0; i < num_threads - 1; ++i)
+ LIBC_NAMESPACE::pthread_create(&threads[i], nullptr,
+ increment_counter_and_wait, nullptr);
+
+ uintptr_t return_val_sum =
+ reinterpret_cast<uintptr_t>(increment_counter_and_wait(nullptr));
+ ASSERT_EQ(counter.load(), num_threads);
+
+ // verify only one thread got the PTHREAD_BARRIER_SERIAL_THREAD return value
+ for (int i = 0; i < num_threads - 1; ++i) {
+ void *ret;
+ LIBC_NAMESPACE::pthread_join(threads[i], &ret);
+ if (reinterpret_cast<uintptr_t>(ret) ==
+ static_cast<uintptr_t>(PTHREAD_BARRIER_SERIAL_THREAD)) {
+ return_val_sum += reinterpret_cast<uintptr_t>(ret);
+ } else {
+ ASSERT_EQ(ret, 0);
+ }
+ }
+ ASSERT_EQ(return_val_sum,
+ static_cast<uintptr_t>(PTHREAD_BARRIER_SERIAL_THREAD));
+
+ LIBC_NAMESPACE::pthread_barrier_destroy(&barrier);
+}
+
+void reused_barrier_test() {
+ counter.set(0);
+ const int NUM_THREADS = 30;
+ const int REPEAT = 20;
+ pthread_t threads[NUM_THREADS - 1]; // subtract 1 for main thread
+ LIBC_NAMESPACE::memset(&barrier, 0, sizeof(pthread_barrier_t));
+ ASSERT_EQ(
+ LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS), 0);
+
+ for (int i = 0; i < REPEAT; ++i) {
+ for (int j = 0; j < NUM_THREADS - 1; ++j)
+ LIBC_NAMESPACE::pthread_create(&threads[j], nullptr,
+ increment_counter_and_wait, nullptr);
+
+ uintptr_t return_val_sum =
+ reinterpret_cast<uintptr_t>(increment_counter_and_wait(nullptr));
+ ASSERT_EQ(counter.load(), NUM_THREADS * (i + 1));
+
+ // verify only one thread got the PTHREAD_BARRIER_SERIAL_THREAD return value
+ for (int i = 0; i < NUM_THREADS - 1; ++i) {
+ void *ret;
+ LIBC_NAMESPACE::pthread_join(threads[i], &ret);
+ if (reinterpret_cast<uintptr_t>(ret) ==
+ static_cast<uintptr_t>(PTHREAD_BARRIER_SERIAL_THREAD)) {
+ return_val_sum += reinterpret_cast<uintptr_t>(ret);
+ } else {
+ ASSERT_EQ(ret, 0);
+ }
+ }
+ ASSERT_EQ(return_val_sum,
+ static_cast<uintptr_t>(PTHREAD_BARRIER_SERIAL_THREAD));
+ }
+
+ LIBC_NAMESPACE::pthread_barrier_destroy(&barrier);
+}
+
+void *barrier_wait(void *in) {
+ return reinterpret_cast<void *>(
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier));
+}
+
+TEST_MAIN() {
+ // don't create any additional threads; only use main thread
+ single_use_barrier_test(1);
+
+ single_use_barrier_test(30);
+ reused_barrier_test();
+ return 0;
+}
diff --git a/libc/test/integration/src/stdlib/gpu/malloc_stress.cpp b/libc/test/integration/src/stdlib/gpu/malloc_stress.cpp
index 77479f8..4c540a8 100644
--- a/libc/test/integration/src/stdlib/gpu/malloc_stress.cpp
+++ b/libc/test/integration/src/stdlib/gpu/malloc_stress.cpp
@@ -14,6 +14,20 @@
using namespace LIBC_NAMESPACE;
+static inline uint32_t entropy() {
+ return (static_cast<uint32_t>(gpu::processor_clock()) ^
+ (gpu::get_thread_id_x() * 0x632be59b) ^
+ (gpu::get_block_id_x() * 0x85157af5)) *
+ 0x9e3779bb;
+}
+
+static inline uint32_t xorshift32(uint32_t &state) {
+ state ^= state << 13;
+ state ^= state >> 17;
+ state ^= state << 5;
+ return state * 0x9e3779bb;
+}
+
static inline void use(uint8_t *ptr, uint32_t size) {
EXPECT_NE(ptr, nullptr);
for (int i = 0; i < size; ++i)
@@ -34,5 +48,19 @@ TEST_MAIN(int, char **, char **) {
for (int i = 0; i < 256; ++i)
free(ptrs[i]);
+
+ uint32_t state = entropy();
+ for (int i = 0; i < 1024; ++i) {
+ if (xorshift32(state) % 2) {
+ uint64_t size = xorshift32(state) % 256 + 16;
+ uint64_t *ptr = reinterpret_cast<uint64_t *>(malloc(size));
+ *ptr = gpu::get_thread_id();
+
+ EXPECT_EQ(*ptr, gpu::get_thread_id());
+ ASSERT_TRUE(ptr);
+ ASSERT_TRUE(__builtin_is_aligned(ptr, 16));
+ free(ptr);
+ }
+ }
return 0;
}
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index e93fbb9..6d0601f 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -16,6 +16,10 @@ add_fp_unittest(
libc.src.__support.math.asin
libc.src.__support.math.asinf
libc.src.__support.math.asinf16
+ libc.src.__support.math.asinhf
+ libc.src.__support.math.asinhf16
+ libc.src.__support.math.atan
+ libc.src.__support.math.atanf
libc.src.__support.math.erff
libc.src.__support.math.exp
libc.src.__support.math.exp10
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 51d38ec..228fa42 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -18,6 +18,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat16) {
EXPECT_FP_EQ(0x0p+0f16, LIBC_NAMESPACE::shared::acoshf16(1.0f16));
EXPECT_FP_EQ(0x0p+0f16, LIBC_NAMESPACE::shared::acospif16(1.0f16));
EXPECT_FP_EQ(0x0p+0f16, LIBC_NAMESPACE::shared::asinf16(0.0f16));
+ EXPECT_FP_EQ(0x0p+0f16, LIBC_NAMESPACE::shared::asinhf16(0.0f16));
EXPECT_FP_EQ(0x1p+0f16, LIBC_NAMESPACE::shared::exp10f16(0.0f16));
@@ -42,6 +43,8 @@ TEST(LlvmLibcSharedMathTest, AllFloat) {
EXPECT_FP_EQ(0x1.921fb6p+0, LIBC_NAMESPACE::shared::acosf(0.0f));
EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::acoshf(1.0f));
EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::asinf(0.0f));
+ EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::asinhf(0.0f));
+ EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::atanf(0.0f));
EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::erff(0.0f));
EXPECT_FP_EQ(0x1p+0f, LIBC_NAMESPACE::shared::exp10f(0.0f));
EXPECT_FP_EQ(0x1p+0f, LIBC_NAMESPACE::shared::expf(0.0f));
@@ -57,6 +60,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat) {
TEST(LlvmLibcSharedMathTest, AllDouble) {
EXPECT_FP_EQ(0x1.921fb54442d18p+0, LIBC_NAMESPACE::shared::acos(0.0));
EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::asin(0.0));
+ EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::atan(0.0));
EXPECT_FP_EQ(0x1p+0, LIBC_NAMESPACE::shared::exp(0.0));
EXPECT_FP_EQ(0x1p+0, LIBC_NAMESPACE::shared::exp10(0.0));
}
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/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