1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
//===-- Unittests for mbtowc ---------------------------------------------===//
//
// 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/errno_macros.h"
#include "hdr/types/wchar_t.h"
#include "src/stdlib/mbtowc.h"
#include "test/UnitTest/ErrnoCheckingTest.h"
#include "test/UnitTest/Test.h"
using LlvmLibcMBToWCTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
TEST_F(LlvmLibcMBToWCTest, OneByte) {
const char *ch = "A";
wchar_t dest[2];
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 1);
ASSERT_EQ(static_cast<char>(*dest), 'A');
ASSERT_EQ(n, 1);
// Should fail since we have not read enough
n = LIBC_NAMESPACE::mbtowc(dest, ch, 0);
ASSERT_EQ(n, -1);
ASSERT_ERRNO_EQ(EILSEQ);
}
TEST_F(LlvmLibcMBToWCTest, TwoByte) {
const char ch[2] = {static_cast<char>(0xC2),
static_cast<char>(0x8E)}; // car symbol
wchar_t dest[2];
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 2);
ASSERT_EQ(static_cast<int>(*dest), 142);
ASSERT_EQ(n, 2);
// Should fail since we have not read enough
n = LIBC_NAMESPACE::mbtowc(dest, ch, 1);
ASSERT_EQ(n, -1);
// Should fail after trying to read next byte too
n = LIBC_NAMESPACE::mbtowc(dest, ch + 1, 1);
ASSERT_EQ(n, -1);
ASSERT_ERRNO_EQ(EILSEQ);
}
TEST_F(LlvmLibcMBToWCTest, ThreeByte) {
const char ch[3] = {static_cast<char>(0xE2), static_cast<char>(0x88),
static_cast<char>(0x91)}; // ∑ sigma symbol
wchar_t dest[2];
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 3);
ASSERT_EQ(static_cast<int>(*dest), 8721);
ASSERT_EQ(n, 3);
// Should fail since we have not read enough
n = LIBC_NAMESPACE::mbtowc(dest, ch, 2);
ASSERT_EQ(n, -1);
ASSERT_ERRNO_EQ(EILSEQ);
}
TEST_F(LlvmLibcMBToWCTest, FourByte) {
const char ch[4] = {static_cast<char>(0xF0), static_cast<char>(0x9F),
static_cast<char>(0xA4),
static_cast<char>(0xA1)}; // 🤡 clown emoji
wchar_t dest[2];
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 4);
ASSERT_EQ(static_cast<int>(*dest), 129313);
ASSERT_EQ(n, 4);
// Should fail since we have not read enough
n = LIBC_NAMESPACE::mbtowc(dest, ch, 2);
ASSERT_EQ(n, -1);
ASSERT_ERRNO_EQ(EILSEQ);
}
TEST_F(LlvmLibcMBToWCTest, InvalidByte) {
const char ch[1] = {static_cast<char>(0x80)};
wchar_t dest[2];
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 1);
ASSERT_EQ(n, -1);
ASSERT_ERRNO_EQ(EILSEQ);
}
TEST_F(LlvmLibcMBToWCTest, InvalidMultiByte) {
const char ch[4] = {static_cast<char>(0x80), static_cast<char>(0x00),
static_cast<char>(0x80),
static_cast<char>(0x00)}; // invalid sequence of bytes
wchar_t dest[2];
// Trying to push all 4 should error
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 4);
ASSERT_EQ(n, -1);
ASSERT_ERRNO_EQ(EILSEQ);
// Trying to push the second and third should correspond to null wc
n = LIBC_NAMESPACE::mbtowc(dest, ch + 1, 2);
ASSERT_EQ(n, 0);
ASSERT_TRUE(*dest == L'\0');
}
TEST_F(LlvmLibcMBToWCTest, InvalidLastByte) {
// Last byte is invalid since it does not have correct starting sequence.
// 0xC0 --> 11000000 starting sequence should be 10xxxxxx
const char ch[4] = {static_cast<char>(0xF1), static_cast<char>(0x80),
static_cast<char>(0x80), static_cast<char>(0xC0)};
wchar_t dest[2];
// Trying to push all 4 should error
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 4);
ASSERT_EQ(n, -1);
ASSERT_ERRNO_EQ(EILSEQ);
}
TEST_F(LlvmLibcMBToWCTest, ValidTwoByteWithExtraRead) {
const char ch[3] = {static_cast<char>(0xC2), static_cast<char>(0x8E),
static_cast<char>(0x80)};
wchar_t dest[2];
// Trying to push all 3 should return valid 2 byte
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 3);
ASSERT_EQ(n, 2);
ASSERT_EQ(static_cast<int>(*dest), 142);
}
TEST_F(LlvmLibcMBToWCTest, TwoValidTwoBytes) {
const char ch[4] = {static_cast<char>(0xC2), static_cast<char>(0x8E),
static_cast<char>(0xC7), static_cast<char>(0x8C)};
wchar_t dest[2];
int n = LIBC_NAMESPACE::mbtowc(dest, ch, 2);
ASSERT_EQ(n, 2);
ASSERT_EQ(static_cast<int>(*dest), 142);
n = LIBC_NAMESPACE::mbtowc(dest + 1, ch + 2, 2);
ASSERT_EQ(n, 2);
ASSERT_EQ(static_cast<int>(*(dest + 1)), 460);
}
TEST_F(LlvmLibcMBToWCTest, NullString) {
wchar_t dest[2] = {L'O', L'K'};
// reading on nullptr should return 0
int n = LIBC_NAMESPACE::mbtowc(dest, nullptr, 2);
ASSERT_EQ(n, 0);
ASSERT_TRUE(dest[0] == L'O');
// reading a null terminator should return 0
const char *ch = "\0";
n = LIBC_NAMESPACE::mbtowc(dest, ch, 1);
ASSERT_EQ(n, 0);
}
TEST_F(LlvmLibcMBToWCTest, NullWCPtr) {
const char ch[2] = {
static_cast<char>(0xC2),
static_cast<char>(0x8E),
};
// a null destination should still return the number of read bytes
int n = LIBC_NAMESPACE::mbtowc(nullptr, ch, 2);
ASSERT_EQ(n, 2);
}
|