214 lines · cpp
1//===-- Unittests for wcsnrtombs ------------------------------------------===//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/size_t.h"11#include "hdr/types/wchar_t.h"12#include "src/__support/error_or.h"13#include "src/__support/macros/null_check.h"14#include "src/__support/macros/properties/os.h"15#include "src/__support/wchar/mbstate.h"16#include "src/__support/wchar/wcsnrtombs.h"17#include "test/UnitTest/Test.h"18 19// TODO: add support for 16-bit widechars to remove this macro20#ifdef LIBC_TARGET_OS_IS_WINDOWS21TEST(LlvmLibcStringConverterTest, Windows) {22 // pass on windows for now23}24 25#else26 27TEST(LlvmLibcWcsnrtombs, AllMultibyteLengths) {28 LIBC_NAMESPACE::internal::mbstate state;29 30 /// clown emoji, sigma symbol, y with diaeresis, letter A31 const wchar_t src[] = {static_cast<wchar_t>(0x1f921),32 static_cast<wchar_t>(0x2211),33 static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),34 static_cast<wchar_t>(0x0)};35 const wchar_t *cur = src;36 char mbs[11];37 38 auto res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 5, 11, &state);39 ASSERT_TRUE(res.has_value());40 ASSERT_EQ(res.value(), static_cast<size_t>(10));41 ASSERT_EQ(cur, nullptr);42 ASSERT_EQ(mbs[0], '\xF0'); // clown begin43 ASSERT_EQ(mbs[1], '\x9F');44 ASSERT_EQ(mbs[2], '\xA4');45 ASSERT_EQ(mbs[3], '\xA1');46 ASSERT_EQ(mbs[4], '\xE2'); // sigma begin47 ASSERT_EQ(mbs[5], '\x88');48 ASSERT_EQ(mbs[6], '\x91');49 ASSERT_EQ(mbs[7], '\xC3'); // y diaeresis begin50 ASSERT_EQ(mbs[8], '\xBF');51 ASSERT_EQ(mbs[9], '\x41'); // A begin52 ASSERT_EQ(mbs[10], '\0'); // null terminator53}54 55TEST(LlvmLibcWcsnrtombs, DestLimit) {56 LIBC_NAMESPACE::internal::mbstate state1;57 58 /// clown emoji, sigma symbol, y with diaeresis, letter A59 const wchar_t src[] = {static_cast<wchar_t>(0x1f921),60 static_cast<wchar_t>(0x2211),61 static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),62 static_cast<wchar_t>(0x0)};63 const wchar_t *cur = src;64 65 char mbs[11];66 for (int i = 0; i < 11; ++i)67 mbs[i] = '\x01'; // dummy initial values68 69 auto res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 5, 4, &state1);70 ASSERT_TRUE(res.has_value());71 ASSERT_EQ(res.value(), static_cast<size_t>(4));72 ASSERT_EQ(cur, src + 1);73 ASSERT_EQ(mbs[0], '\xF0');74 ASSERT_EQ(mbs[1], '\x9F');75 ASSERT_EQ(mbs[2], '\xA4');76 ASSERT_EQ(mbs[3], '\xA1');77 ASSERT_EQ(mbs[4], '\x01'); // didn't write more than 4 bytes78 79 for (int i = 0; i < 11; ++i)80 mbs[i] = '\x01'; // dummy initial values81 LIBC_NAMESPACE::internal::mbstate state2;82 83 // not enough bytes to convert the second character, so only converts one84 cur = src;85 res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 5, 6, &state2);86 ASSERT_TRUE(res.has_value());87 ASSERT_EQ(res.value(), static_cast<size_t>(4));88 ASSERT_EQ(cur, src + 1);89 ASSERT_EQ(mbs[0], '\xF0');90 ASSERT_EQ(mbs[1], '\x9F');91 ASSERT_EQ(mbs[2], '\xA4');92 ASSERT_EQ(mbs[3], '\xA1');93 ASSERT_EQ(mbs[4], '\x01');94}95 96TEST(LlvmLibcWcsnrtombs, SrcLimit) {97 LIBC_NAMESPACE::internal::mbstate state;98 99 /// clown emoji, sigma symbol, y with diaeresis, letter A100 const wchar_t src[] = {static_cast<wchar_t>(0x1f921),101 static_cast<wchar_t>(0x2211),102 static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),103 static_cast<wchar_t>(0x0)};104 const wchar_t *cur = src;105 106 char mbs[11];107 for (int i = 0; i < 11; ++i)108 mbs[i] = '\x01'; // dummy initial values109 110 auto res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 2, 11, &state);111 ASSERT_TRUE(res.has_value());112 ASSERT_EQ(res.value(), static_cast<size_t>(7));113 ASSERT_EQ(cur, src + 2);114 ASSERT_EQ(mbs[0], '\xF0'); // clown begin115 ASSERT_EQ(mbs[1], '\x9F');116 ASSERT_EQ(mbs[2], '\xA4');117 ASSERT_EQ(mbs[3], '\xA1');118 ASSERT_EQ(mbs[4], '\xE2'); // sigma begin119 ASSERT_EQ(mbs[5], '\x88');120 ASSERT_EQ(mbs[6], '\x91');121 ASSERT_EQ(mbs[7], '\x01');122 123 res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs + res.value(), &cur, 100, 11,124 &state);125 ASSERT_TRUE(res.has_value());126 ASSERT_EQ(res.value(), static_cast<size_t>(3));127 ASSERT_EQ(cur, nullptr);128 ASSERT_EQ(mbs[0], '\xF0'); // clown begin129 ASSERT_EQ(mbs[1], '\x9F');130 ASSERT_EQ(mbs[2], '\xA4');131 ASSERT_EQ(mbs[3], '\xA1');132 ASSERT_EQ(mbs[4], '\xE2'); // sigma begin133 ASSERT_EQ(mbs[5], '\x88');134 ASSERT_EQ(mbs[6], '\x91');135 ASSERT_EQ(mbs[7], '\xC3'); // y diaeresis begin136 ASSERT_EQ(mbs[8], '\xBF');137 ASSERT_EQ(mbs[9], '\x41'); // A begin138 ASSERT_EQ(mbs[10], '\0'); // null terminator139}140 141TEST(LlvmLibcWcsnrtombs, NullDest) {142 LIBC_NAMESPACE::internal::mbstate state1;143 144 const wchar_t src[] = {static_cast<wchar_t>(0x1f921),145 static_cast<wchar_t>(0x2211),146 static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),147 static_cast<wchar_t>(0x0)};148 const wchar_t *cur = src;149 150 // n parameter ignored when dest is null151 auto res = LIBC_NAMESPACE::internal::wcsnrtombs(nullptr, &cur, 5, 1, &state1);152 ASSERT_TRUE(res.has_value());153 ASSERT_EQ(res.value(), static_cast<size_t>(10));154 ASSERT_EQ(cur, src); // pointer not updated when dest = null155 156 LIBC_NAMESPACE::internal::mbstate state2;157 res = LIBC_NAMESPACE::internal::wcsnrtombs(nullptr, &cur, 5, 100, &state2);158 ASSERT_TRUE(res.has_value());159 ASSERT_EQ(res.value(), static_cast<size_t>(10));160 ASSERT_EQ(cur, src);161}162 163TEST(LlvmLibcWcsnrtombs, InvalidState) {164 // this is more thoroughly tested by CharacterConverter165 LIBC_NAMESPACE::internal::mbstate state;166 state.total_bytes = 100;167 168 const wchar_t src[] = {static_cast<wchar_t>(0x1f921),169 static_cast<wchar_t>(0x2211),170 static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),171 static_cast<wchar_t>(0x0)};172 const wchar_t *cur = src;173 174 // n parameter ignored when dest is null175 auto res = LIBC_NAMESPACE::internal::wcsnrtombs(nullptr, &cur, 5, 1, &state);176 ASSERT_FALSE(res.has_value());177 ASSERT_EQ(res.error(), EINVAL);178}179 180TEST(LlvmLibcWcsnrtombs, InvalidCharacter) {181 LIBC_NAMESPACE::internal::mbstate state1;182 183 const wchar_t src[] = {static_cast<wchar_t>(0x1f921),184 static_cast<wchar_t>(0x2211),185 static_cast<wchar_t>(0x12ffff), // invalid widechar186 static_cast<wchar_t>(0x0)};187 const wchar_t *cur = src;188 char mbs[11];189 190 // n parameter ignored when dest is null191 auto res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 5, 7, &state1);192 ASSERT_TRUE(res.has_value());193 ASSERT_EQ(res.value(), static_cast<size_t>(7));194 195 LIBC_NAMESPACE::internal::mbstate state2;196 cur = src;197 res = LIBC_NAMESPACE::internal::wcsnrtombs(mbs, &cur, 5, 11, &state2);198 ASSERT_FALSE(res.has_value());199 ASSERT_EQ(res.error(), EILSEQ);200}201 202#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)203TEST(LlvmLibcWcsnrtombs, NullSrc) {204 EXPECT_DEATH(205 [] {206 LIBC_NAMESPACE::internal::mbstate state;207 char mbs[10];208 LIBC_NAMESPACE::internal::wcsnrtombs(mbs, nullptr, 1, 1, &state);209 },210 WITH_SIGNAL(-1));211}212#endif // LIBC_HAS_ADDRESS_SANITIZER213#endif214