140 lines · cpp
1//===-- Unittests for mbrlen ----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "hdr/errno_macros.h"10#include "hdr/types/wchar_t.h"11#include "src/__support/wchar/mbstate.h"12#include "src/string/memset.h"13#include "src/wchar/mbrlen.h"14#include "test/UnitTest/ErrnoCheckingTest.h"15#include "test/UnitTest/Test.h"16 17using LlvmLibcMBRLenTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;18 19TEST_F(LlvmLibcMBRLenTest, OneByte) {20 const char *ch = "A";21 mbstate_t mb;22 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));23 size_t n = LIBC_NAMESPACE::mbrlen(ch, 1, &mb);24 ASSERT_ERRNO_SUCCESS();25 ASSERT_EQ(n, static_cast<size_t>(1));26 27 // Should fail since we have not read enough28 n = LIBC_NAMESPACE::mbrlen(ch, 0, &mb);29 ASSERT_ERRNO_SUCCESS();30 ASSERT_EQ(n, static_cast<size_t>(-2));31}32 33TEST_F(LlvmLibcMBRLenTest, TwoByte) {34 const char ch[2] = {static_cast<char>(0xC2),35 static_cast<char>(0x8E)}; // car symbol36 mbstate_t mb;37 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));38 size_t n = LIBC_NAMESPACE::mbrlen(ch, 4, nullptr);39 ASSERT_ERRNO_SUCCESS();40 ASSERT_EQ(static_cast<int>(n), 2);41 42 // Should fail since we have not read enough43 n = LIBC_NAMESPACE::mbrlen(ch, 1, &mb);44 ASSERT_EQ(static_cast<int>(n), -2);45 ASSERT_ERRNO_SUCCESS();46 // Should pass after trying to read next byte47 n = LIBC_NAMESPACE::mbrlen(ch + 1, 1, &mb);48 ASSERT_EQ(static_cast<int>(n), 1);49 ASSERT_ERRNO_SUCCESS();50}51 52TEST_F(LlvmLibcMBRLenTest, ThreeByte) {53 const char ch[3] = {static_cast<char>(0xE2), static_cast<char>(0x88),54 static_cast<char>(0x91)}; // ∑ sigma symbol55 mbstate_t mb;56 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));57 size_t n = LIBC_NAMESPACE::mbrlen(ch, 3, &mb);58 ASSERT_EQ(static_cast<int>(n), 3);59 ASSERT_ERRNO_SUCCESS();60 61 // Should fail since we have not read enough62 n = LIBC_NAMESPACE::mbrlen(ch, 2, &mb);63 ASSERT_EQ(static_cast<int>(n), -2);64 ASSERT_ERRNO_SUCCESS();65}66 67TEST_F(LlvmLibcMBRLenTest, FourByte) {68 const char ch[4] = {static_cast<char>(0xF0), static_cast<char>(0x9F),69 static_cast<char>(0xA4),70 static_cast<char>(0xA1)}; // 🤡 clown emoji71 mbstate_t mb;72 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));73 size_t n = LIBC_NAMESPACE::mbrlen(ch, 4, &mb);74 ASSERT_EQ(static_cast<int>(n), 4);75 ASSERT_ERRNO_SUCCESS();76 77 // Should fail since we have not read enough78 n = LIBC_NAMESPACE::mbrlen(ch, 2, &mb);79 ASSERT_EQ(static_cast<int>(n), -2);80 ASSERT_ERRNO_SUCCESS();81 82 // Should fail since we have not read enough83 n = LIBC_NAMESPACE::mbrlen(ch + 2, 1, &mb);84 ASSERT_EQ(static_cast<int>(n), -2);85 ASSERT_ERRNO_SUCCESS();86 87 // Should pass after reading final byte88 n = LIBC_NAMESPACE::mbrlen(ch + 3, 5, &mb);89 ASSERT_EQ(static_cast<int>(n), 1);90 ASSERT_ERRNO_SUCCESS();91}92 93TEST_F(LlvmLibcMBRLenTest, InvalidByte) {94 const char ch[1] = {static_cast<char>(0x80)};95 size_t n = LIBC_NAMESPACE::mbrlen(ch, 1, nullptr);96 ASSERT_EQ(static_cast<int>(n), -1);97 ASSERT_ERRNO_EQ(EILSEQ);98}99 100TEST_F(LlvmLibcMBRLenTest, InvalidMultiByte) {101 const char ch[4] = {static_cast<char>(0x80), static_cast<char>(0x00),102 static_cast<char>(0x80),103 static_cast<char>(0x00)}; // invalid sequence of bytes104 mbstate_t mb;105 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));106 // Trying to push all 4 should error107 size_t n = LIBC_NAMESPACE::mbrlen(ch, 4, &mb);108 ASSERT_EQ(static_cast<int>(n), -1);109 ASSERT_ERRNO_EQ(EILSEQ);110 111 // Trying to push the second and third should correspond to null wc112 n = LIBC_NAMESPACE::mbrlen(ch + 1, 2, &mb);113 ASSERT_EQ(static_cast<int>(n), 0);114 ASSERT_ERRNO_SUCCESS();115}116 117TEST_F(LlvmLibcMBRLenTest, NullString) {118 // reading on nullptr should return 0119 size_t n = LIBC_NAMESPACE::mbrlen(nullptr, 2, nullptr);120 ASSERT_EQ(static_cast<int>(n), 0);121 ASSERT_ERRNO_SUCCESS();122 // reading a null terminator should return 0123 const char *ch = "\0";124 n = LIBC_NAMESPACE::mbrlen(ch, 1, nullptr);125 ASSERT_EQ(static_cast<int>(n), 0);126}127 128TEST_F(LlvmLibcMBRLenTest, InvalidMBState) {129 const char ch[4] = {static_cast<char>(0xC2), static_cast<char>(0x8E),130 static_cast<char>(0xC7), static_cast<char>(0x8C)};131 mbstate_t *mb;132 LIBC_NAMESPACE::internal::mbstate inv;133 inv.total_bytes = 6;134 mb = reinterpret_cast<mbstate_t *>(&inv);135 // invalid mbstate should error136 size_t n = LIBC_NAMESPACE::mbrlen(ch, 2, mb);137 ASSERT_EQ(static_cast<int>(n), -1);138 ASSERT_ERRNO_EQ(EINVAL);139}140