218 lines · cpp
1//===-- Unittests for mbrtowc ---------------------------------------------===//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/mbstate_t.h"11#include "hdr/types/wchar_t.h"12#include "src/__support/wchar/mbstate.h"13#include "src/string/memset.h"14#include "src/wchar/mbrtowc.h"15#include "test/UnitTest/ErrnoCheckingTest.h"16#include "test/UnitTest/Test.h"17 18using LlvmLibcMBRToWCTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;19 20TEST_F(LlvmLibcMBRToWCTest, OneByte) {21 const char *ch = "A";22 wchar_t dest[2];23 // Testing if it works with nullptr mbstate_t24 mbstate_t *mb = nullptr;25 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, mb);26 ASSERT_EQ(static_cast<char>(*dest), 'A');27 ASSERT_EQ(static_cast<int>(n), 1);28 ASSERT_ERRNO_SUCCESS();29 30 // Should fail since we have not read enough31 n = LIBC_NAMESPACE::mbrtowc(dest, ch, 0, mb);32 ASSERT_EQ(static_cast<int>(n), -2);33 ASSERT_ERRNO_SUCCESS();34}35 36TEST_F(LlvmLibcMBRToWCTest, TwoByte) {37 const char ch[2] = {static_cast<char>(0xC2),38 static_cast<char>(0x8E)}; // car symbol39 wchar_t dest[2];40 mbstate_t mb;41 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));42 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 2, &mb);43 ASSERT_EQ(static_cast<int>(*dest), 142);44 ASSERT_EQ(static_cast<int>(n), 2);45 ASSERT_ERRNO_SUCCESS();46 47 // Should fail since we have not read enough48 n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, &mb);49 ASSERT_EQ(static_cast<int>(n), -2);50 // Should pass after reading one more byte51 n = LIBC_NAMESPACE::mbrtowc(dest, ch + 1, 1, &mb);52 ASSERT_EQ(static_cast<int>(n), 1);53 ASSERT_EQ(static_cast<int>(*dest), 142);54 ASSERT_ERRNO_SUCCESS();55}56 57TEST_F(LlvmLibcMBRToWCTest, ThreeByte) {58 const char ch[3] = {static_cast<char>(0xE2), static_cast<char>(0x88),59 static_cast<char>(0x91)}; // ∑ sigma symbol60 wchar_t dest[2];61 mbstate_t mb;62 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));63 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 3, &mb);64 ASSERT_EQ(static_cast<int>(*dest), 8721);65 ASSERT_EQ(static_cast<int>(n), 3);66 ASSERT_ERRNO_SUCCESS();67 68 // Should fail since we have not read enough69 n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, &mb);70 ASSERT_EQ(static_cast<int>(n), -2);71 ASSERT_ERRNO_SUCCESS();72 // Should pass after reading two more bytes73 n = LIBC_NAMESPACE::mbrtowc(dest, ch + 1, 2, &mb);74 ASSERT_EQ(static_cast<int>(n), 2);75 ASSERT_EQ(static_cast<int>(*dest), 8721);76 ASSERT_ERRNO_SUCCESS();77}78 79TEST_F(LlvmLibcMBRToWCTest, FourByte) {80 const char ch[4] = {static_cast<char>(0xF0), static_cast<char>(0x9F),81 static_cast<char>(0xA4),82 static_cast<char>(0xA1)}; // 🤡 clown emoji83 wchar_t dest[2];84 mbstate_t mb;85 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));86 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 4, &mb);87 ASSERT_EQ(static_cast<int>(*dest), 129313);88 ASSERT_EQ(static_cast<int>(n), 4);89 ASSERT_ERRNO_SUCCESS();90 // Should fail since we have not read enough91 n = LIBC_NAMESPACE::mbrtowc(dest, ch, 2, &mb);92 ASSERT_EQ(static_cast<int>(n), -2);93 ASSERT_ERRNO_SUCCESS();94 // Should pass after reading two more bytes95 n = LIBC_NAMESPACE::mbrtowc(dest, ch + 2, 2, &mb);96 ASSERT_EQ(static_cast<int>(n), 2);97 ASSERT_EQ(static_cast<int>(*dest), 129313);98 ASSERT_ERRNO_SUCCESS();99}100 101TEST_F(LlvmLibcMBRToWCTest, InvalidByte) {102 const char ch[1] = {static_cast<char>(0x80)};103 wchar_t dest[2];104 mbstate_t mb;105 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));106 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, &mb);107 ASSERT_EQ(static_cast<int>(n), -1);108 ASSERT_ERRNO_EQ(EILSEQ);109}110 111TEST_F(LlvmLibcMBRToWCTest, InvalidMultiByte) {112 const char ch[4] = {static_cast<char>(0x80), static_cast<char>(0x00),113 static_cast<char>(0x80),114 static_cast<char>(0x00)}; // invalid sequence of bytes115 wchar_t dest[2];116 mbstate_t mb;117 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));118 // Trying to push all 4 should error119 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 4, &mb);120 ASSERT_EQ(static_cast<int>(n), -1);121 ASSERT_ERRNO_EQ(EILSEQ);122 // Trying to push just the first one should error123 n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, &mb);124 ASSERT_EQ(static_cast<int>(n), -1);125 ASSERT_ERRNO_EQ(EILSEQ);126 // Trying to push the second and third should correspond to null wc127 n = LIBC_NAMESPACE::mbrtowc(dest, ch + 1, 2, &mb);128 ASSERT_EQ(static_cast<int>(n), 0);129 ASSERT_TRUE(*dest == L'\0');130 ASSERT_ERRNO_SUCCESS();131}132 133TEST_F(LlvmLibcMBRToWCTest, InvalidLastByte) {134 // Last byte is invalid since it does not have correct starting sequence.135 // 0xC0 --> 11000000 starting sequence should be 10xxxxxx136 const char ch[4] = {static_cast<char>(0xF1), static_cast<char>(0x80),137 static_cast<char>(0x80), static_cast<char>(0xC0)};138 wchar_t dest[2];139 mbstate_t mb;140 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));141 // Trying to push all 4 should error142 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 4, &mb);143 ASSERT_EQ(static_cast<int>(n), -1);144 ASSERT_ERRNO_EQ(EILSEQ);145}146 147TEST_F(LlvmLibcMBRToWCTest, ValidTwoByteWithExtraRead) {148 const char ch[3] = {static_cast<char>(0xC2), static_cast<char>(0x8E),149 static_cast<char>(0x80)};150 wchar_t dest[2];151 mbstate_t mb;152 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));153 // Trying to push all 3 should return valid 2 byte154 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 3, &mb);155 ASSERT_EQ(static_cast<int>(n), 2);156 ASSERT_EQ(static_cast<int>(*dest), 142);157 ASSERT_ERRNO_SUCCESS();158}159 160TEST_F(LlvmLibcMBRToWCTest, TwoValidTwoBytes) {161 const char ch[4] = {static_cast<char>(0xC2), static_cast<char>(0x8E),162 static_cast<char>(0xC7), static_cast<char>(0x8C)};163 wchar_t dest[2];164 mbstate_t mb;165 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));166 // mbstate should reset after reading first one167 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 2, &mb);168 ASSERT_EQ(static_cast<int>(n), 2);169 ASSERT_EQ(static_cast<int>(*dest), 142);170 ASSERT_ERRNO_SUCCESS();171 n = LIBC_NAMESPACE::mbrtowc(dest + 1, ch + 2, 2, &mb);172 ASSERT_EQ(static_cast<int>(n), 2);173 ASSERT_EQ(static_cast<int>(*(dest + 1)), 460);174 ASSERT_ERRNO_SUCCESS();175}176 177TEST_F(LlvmLibcMBRToWCTest, NullString) {178 wchar_t dest[2] = {L'O', L'K'};179 mbstate_t mb;180 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));181 // reading on nullptr should return 0182 size_t n = LIBC_NAMESPACE::mbrtowc(dest, nullptr, 2, &mb);183 ASSERT_EQ(static_cast<int>(n), 0);184 ASSERT_TRUE(dest[0] == L'O');185 ASSERT_ERRNO_SUCCESS();186 // reading a null terminator should return 0187 const char *ch = "\0";188 n = LIBC_NAMESPACE::mbrtowc(dest, ch, 1, &mb);189 ASSERT_EQ(static_cast<int>(n), 0);190 ASSERT_ERRNO_SUCCESS();191}192 193TEST_F(LlvmLibcMBRToWCTest, NullDest) {194 const char ch[4] = {static_cast<char>(0xF0), static_cast<char>(0x9F),195 static_cast<char>(0xA4),196 static_cast<char>(0xA1)}; // 🤡 clown emoji197 mbstate_t mb;198 LIBC_NAMESPACE::memset(&mb, 0, sizeof(mbstate_t));199 // reading nullptr should return correct size200 size_t n = LIBC_NAMESPACE::mbrtowc(nullptr, ch, 10, &mb);201 ASSERT_EQ(static_cast<int>(n), 4);202 ASSERT_ERRNO_SUCCESS();203}204 205TEST_F(LlvmLibcMBRToWCTest, InvalidMBState) {206 const char ch[4] = {static_cast<char>(0xC2), static_cast<char>(0x8E),207 static_cast<char>(0xC7), static_cast<char>(0x8C)};208 wchar_t dest[2] = {L'O', L'K'};209 mbstate_t *mb;210 LIBC_NAMESPACE::internal::mbstate inv;211 inv.total_bytes = 6;212 mb = reinterpret_cast<mbstate_t *>(&inv);213 // invalid mbstate should error214 size_t n = LIBC_NAMESPACE::mbrtowc(dest, ch, 2, mb);215 ASSERT_EQ(static_cast<int>(n), -1);216 ASSERT_ERRNO_EQ(EINVAL);217}218