Skip to content

Commit d4a86b2

Browse files
committed
wcstombs test
1 parent 953eca5 commit d4a86b2

File tree

4 files changed

+66
-17
lines changed

4 files changed

+66
-17
lines changed

libc/src/wchar/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ add_entrypoint_object(
187187
)
188188

189189
add_entrypoint_object(
190-
wcstombs
190+
wcsnrtombs
191191
SRCS
192192
wcsnrtombs.cpp
193193
HDRS

libc/src/wchar/wcstombs.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,22 @@ LLVM_LIBC_FUNCTION(size_t, wcstombs,
2323
(char *__restrict s, const wchar_t *__restrict pwcs,
2424
size_t n)) {
2525
static internal::mbstate internal_mbstate;
26+
27+
if (s == nullptr)
28+
n = SIZE_MAX;
29+
2630
internal::StringConverter<char32_t> str_conv(
2731
reinterpret_cast<const char32_t *>(pwcs), &internal_mbstate, n);
2832

2933
int dst_idx = 0;
3034
ErrorOr<char8_t> converted = str_conv.popUTF8();
3135
while (converted.has_value()) {
32-
if (s != nullptr)
36+
if (s != nullptr)
3337
s[dst_idx] = converted.value();
34-
dst_idx++;
38+
39+
if (converted.value() != '\0')
40+
dst_idx++;
41+
3542
converted = str_conv.popUTF8();
3643
}
3744

libc/test/src/wchar/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,18 @@ add_libc_test(
101101
libc.hdr.types.wchar_t
102102
)
103103

104+
add_libc_test(
105+
wcstombs_test
106+
SUITE
107+
libc_wchar_unittests
108+
SRCS
109+
wcstombs_test.cpp
110+
DEPENDS
111+
libc.src.wchar.wcstombs
112+
libc.test.UnitTest.ErrnoCheckingTest
113+
libc.hdr.types.wchar_t
114+
)
115+
104116
add_libc_test(
105117
wmemset_test
106118
SUITE

libc/test/src/wchar/wcstombs_test.cpp

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ TEST_F(LlvmLibcWcstombs, AllMultibyteLengths) {
2020
static_cast<wchar_t>(0x0)};
2121
char mbs[11];
2222

23-
ASSERT_EQ(wcstombs(mbs, src, 11), static_cast<size_t>(11));
23+
ASSERT_EQ(LIBC_NAMESPACE::wcstombs(mbs, src, 11), static_cast<size_t>(10));
2424
ASSERT_ERRNO_SUCCESS();
2525
ASSERT_EQ(mbs[0], '\xF0'); // clown begin
2626
ASSERT_EQ(mbs[1], '\x9F');
@@ -35,29 +35,59 @@ TEST_F(LlvmLibcWcstombs, AllMultibyteLengths) {
3535
ASSERT_EQ(mbs[10], '\0'); // null terminator
3636
}
3737

38-
TEST_F(LlvmLibcWcstombs, PartialConversion) {
38+
TEST_F(LlvmLibcWcstombs, DestLimit) {
3939
/// clown emoji, sigma symbol, y with diaeresis, letter A
4040
const wchar_t src[] = {static_cast<wchar_t>(0x1f921),
4141
static_cast<wchar_t>(0x2211),
4242
static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),
4343
static_cast<wchar_t>(0x0)};
44-
char mbs[11] = {0};
44+
char mbs[11];
45+
for (int i = 0; i < 11; ++i)
46+
mbs[i] = '\x01'; // dummy initial values
4547

46-
ASSERT_EQ(wcstombs(mbs, src, 6), static_cast<size_t>(4));
48+
ASSERT_EQ(LIBC_NAMESPACE::wcstombs(mbs, src, 4), static_cast<size_t>(4));
4749
ASSERT_ERRNO_SUCCESS();
48-
ASSERT_EQ(mbs[0], '\xF0'); // clown begin
50+
ASSERT_EQ(mbs[0], '\xF0');
4951
ASSERT_EQ(mbs[1], '\x9F');
5052
ASSERT_EQ(mbs[2], '\xA4');
5153
ASSERT_EQ(mbs[3], '\xA1');
52-
ASSERT_EQ(mbs[4], '\0');
54+
ASSERT_EQ(mbs[4], '\x01'); // didn't write more than 4 bytes
5355

54-
ASSERT_EQ(wcstombs(mbs, src, 6), static_cast<size_t>(4));
56+
for (int i = 0; i < 11; ++i)
57+
mbs[i] = '\x01'; // dummy initial values
5558

56-
ASSERT_EQ(mbs[4], '\xE2'); // sigma begin
57-
ASSERT_EQ(mbs[5], '\x88');
58-
ASSERT_EQ(mbs[6], '\x91');
59-
ASSERT_EQ(mbs[7], '\xC3'); // y diaeresis begin
60-
ASSERT_EQ(mbs[8], '\xBF');
61-
ASSERT_EQ(mbs[9], '\x41'); // A begin
62-
ASSERT_EQ(mbs[10], '\0'); // null terminator
59+
// not enough bytes to convert the second character, so only converts one
60+
ASSERT_EQ(LIBC_NAMESPACE::wcstombs(mbs, src, 6), static_cast<size_t>(4));
61+
ASSERT_ERRNO_SUCCESS();
62+
ASSERT_EQ(mbs[0], '\xF0');
63+
ASSERT_EQ(mbs[1], '\x9F');
64+
ASSERT_EQ(mbs[2], '\xA4');
65+
ASSERT_EQ(mbs[3], '\xA1');
66+
ASSERT_EQ(mbs[4], '\x01');
67+
}
68+
69+
TEST_F(LlvmLibcWcstombs, NullDest) {
70+
const wchar_t src[] = {static_cast<wchar_t>(0x1f921),
71+
static_cast<wchar_t>(0x2211),
72+
static_cast<wchar_t>(0xff), static_cast<wchar_t>(0x41),
73+
static_cast<wchar_t>(0x0)};
74+
75+
// n parameter ignored when dest is null
76+
ASSERT_EQ(LIBC_NAMESPACE::wcstombs(nullptr, src, 1), static_cast<size_t>(10));
77+
ASSERT_ERRNO_SUCCESS();
78+
ASSERT_EQ(LIBC_NAMESPACE::wcstombs(nullptr, src, 100), static_cast<size_t>(10));
79+
ASSERT_ERRNO_SUCCESS();
6380
}
81+
82+
TEST_F(LlvmLibcWcstombs, ErrnoTest) {
83+
const wchar_t src[] = {static_cast<wchar_t>(0x1f921),
84+
static_cast<wchar_t>(0x2211),
85+
static_cast<wchar_t>(0x12ffff), // invalid widechar
86+
static_cast<wchar_t>(0x0)};
87+
88+
// n parameter ignored when dest is null
89+
ASSERT_EQ(LIBC_NAMESPACE::wcstombs(nullptr, src, 7), static_cast<size_t>(7));
90+
ASSERT_ERRNO_SUCCESS();
91+
ASSERT_EQ(LIBC_NAMESPACE::wcstombs(nullptr, src, 100), static_cast<size_t>(-1));
92+
ASSERT_ERRNO_EQ(EILSEQ);
93+
}

0 commit comments

Comments
 (0)