Blame


1 3448adb0 2022-11-02 op /* See LICENSE file for copyright and license details. */
2 3448adb0 2022-11-02 op #include <stdbool.h>
3 3448adb0 2022-11-02 op #include <stdint.h>
4 3448adb0 2022-11-02 op #include <stdio.h>
5 3448adb0 2022-11-02 op #include <string.h>
6 3448adb0 2022-11-02 op
7 3448adb0 2022-11-02 op #include "../grapheme.h"
8 3448adb0 2022-11-02 op #include "util.h"
9 3448adb0 2022-11-02 op
10 3448adb0 2022-11-02 op struct unit_test_is_case_utf8 {
11 3448adb0 2022-11-02 op const char *description;
12 3448adb0 2022-11-02 op struct {
13 3448adb0 2022-11-02 op const char *src;
14 3448adb0 2022-11-02 op size_t srclen;
15 3448adb0 2022-11-02 op } input;
16 3448adb0 2022-11-02 op struct {
17 3448adb0 2022-11-02 op bool ret;
18 3448adb0 2022-11-02 op size_t caselen;
19 3448adb0 2022-11-02 op } output;
20 3448adb0 2022-11-02 op };
21 3448adb0 2022-11-02 op
22 3448adb0 2022-11-02 op struct unit_test_to_case_utf8 {
23 3448adb0 2022-11-02 op const char *description;
24 3448adb0 2022-11-02 op struct {
25 3448adb0 2022-11-02 op const char *src;
26 3448adb0 2022-11-02 op size_t srclen;
27 3448adb0 2022-11-02 op size_t destlen;
28 3448adb0 2022-11-02 op } input;
29 3448adb0 2022-11-02 op struct {
30 3448adb0 2022-11-02 op const char *dest;
31 3448adb0 2022-11-02 op size_t ret;
32 3448adb0 2022-11-02 op } output;
33 3448adb0 2022-11-02 op };
34 3448adb0 2022-11-02 op
35 3448adb0 2022-11-02 op static const struct unit_test_is_case_utf8 is_lowercase_utf8[] = {
36 3448adb0 2022-11-02 op {
37 3448adb0 2022-11-02 op .description = "empty input",
38 3448adb0 2022-11-02 op .input = { "", 0 },
39 3448adb0 2022-11-02 op .output = { true, 0 },
40 3448adb0 2022-11-02 op },
41 3448adb0 2022-11-02 op {
42 3448adb0 2022-11-02 op .description = "one character, violation",
43 3448adb0 2022-11-02 op .input = { "A", 1 },
44 3448adb0 2022-11-02 op .output = { false, 0 },
45 3448adb0 2022-11-02 op },
46 3448adb0 2022-11-02 op {
47 3448adb0 2022-11-02 op .description = "one character, confirmation",
48 3448adb0 2022-11-02 op .input = { "\xC3\x9F", 2 },
49 3448adb0 2022-11-02 op .output = { true, 2 },
50 3448adb0 2022-11-02 op },
51 3448adb0 2022-11-02 op {
52 3448adb0 2022-11-02 op .description = "one character, violation, NUL-terminated",
53 3448adb0 2022-11-02 op .input = { "A", SIZE_MAX },
54 3448adb0 2022-11-02 op .output = { false, 0 },
55 3448adb0 2022-11-02 op },
56 3448adb0 2022-11-02 op {
57 3448adb0 2022-11-02 op .description = "one character, confirmation, NUL-terminated",
58 3448adb0 2022-11-02 op .input = { "\xC3\x9F", SIZE_MAX },
59 3448adb0 2022-11-02 op .output = { true, 2 },
60 3448adb0 2022-11-02 op },
61 3448adb0 2022-11-02 op {
62 3448adb0 2022-11-02 op .description = "one word, violation",
63 3448adb0 2022-11-02 op .input = { "Hello", 5 },
64 3448adb0 2022-11-02 op .output = { false, 0 },
65 3448adb0 2022-11-02 op },
66 3448adb0 2022-11-02 op {
67 3448adb0 2022-11-02 op .description = "one word, partial confirmation",
68 3448adb0 2022-11-02 op .input = { "gru" "\xC3\x9F" "fOrmel", 11 },
69 3448adb0 2022-11-02 op .output = { false, 6 },
70 3448adb0 2022-11-02 op },
71 3448adb0 2022-11-02 op {
72 3448adb0 2022-11-02 op .description = "one word, full confirmation",
73 3448adb0 2022-11-02 op .input = { "gru" "\xC3\x9F" "formel", 11 },
74 3448adb0 2022-11-02 op .output = { true, 11 },
75 3448adb0 2022-11-02 op },
76 3448adb0 2022-11-02 op {
77 3448adb0 2022-11-02 op .description = "one word, violation, NUL-terminated",
78 3448adb0 2022-11-02 op .input = { "Hello", SIZE_MAX },
79 3448adb0 2022-11-02 op .output = { false, 0 },
80 3448adb0 2022-11-02 op },
81 3448adb0 2022-11-02 op {
82 3448adb0 2022-11-02 op .description = "one word, partial confirmation, NUL-terminated",
83 3448adb0 2022-11-02 op .input = { "gru" "\xC3\x9F" "fOrmel", SIZE_MAX },
84 3448adb0 2022-11-02 op .output = { false, 6 },
85 3448adb0 2022-11-02 op },
86 3448adb0 2022-11-02 op {
87 3448adb0 2022-11-02 op .description = "one word, full confirmation, NUL-terminated",
88 3448adb0 2022-11-02 op .input = { "gru" "\xC3\x9F" "formel", SIZE_MAX },
89 3448adb0 2022-11-02 op .output = { true, 11 },
90 3448adb0 2022-11-02 op },
91 3448adb0 2022-11-02 op };
92 3448adb0 2022-11-02 op
93 3448adb0 2022-11-02 op static const struct unit_test_is_case_utf8 is_uppercase_utf8[] = {
94 3448adb0 2022-11-02 op {
95 3448adb0 2022-11-02 op .description = "empty input",
96 3448adb0 2022-11-02 op .input = { "", 0 },
97 3448adb0 2022-11-02 op .output = { true, 0 },
98 3448adb0 2022-11-02 op },
99 3448adb0 2022-11-02 op {
100 3448adb0 2022-11-02 op .description = "one character, violation",
101 3448adb0 2022-11-02 op .input = { "\xC3\x9F", 2 },
102 3448adb0 2022-11-02 op .output = { false, 0 },
103 3448adb0 2022-11-02 op },
104 3448adb0 2022-11-02 op {
105 3448adb0 2022-11-02 op .description = "one character, confirmation",
106 3448adb0 2022-11-02 op .input = { "A", 1 },
107 3448adb0 2022-11-02 op .output = { true, 1 },
108 3448adb0 2022-11-02 op },
109 3448adb0 2022-11-02 op {
110 3448adb0 2022-11-02 op .description = "one character, violation, NUL-terminated",
111 3448adb0 2022-11-02 op .input = { "\xC3\x9F", SIZE_MAX },
112 3448adb0 2022-11-02 op .output = { false, 0 },
113 3448adb0 2022-11-02 op },
114 3448adb0 2022-11-02 op {
115 3448adb0 2022-11-02 op .description = "one character, confirmation, NUL-terminated",
116 3448adb0 2022-11-02 op .input = { "A", SIZE_MAX },
117 3448adb0 2022-11-02 op .output = { true, 1 },
118 3448adb0 2022-11-02 op },
119 3448adb0 2022-11-02 op {
120 3448adb0 2022-11-02 op .description = "one word, violation",
121 3448adb0 2022-11-02 op .input = { "hello", 5 },
122 3448adb0 2022-11-02 op .output = { false, 0 },
123 3448adb0 2022-11-02 op },
124 3448adb0 2022-11-02 op {
125 3448adb0 2022-11-02 op .description = "one word, partial confirmation",
126 3448adb0 2022-11-02 op .input = { "GRU" "\xC3\x9F" "formel", 11 },
127 3448adb0 2022-11-02 op .output = { false, 3 },
128 3448adb0 2022-11-02 op },
129 3448adb0 2022-11-02 op {
130 3448adb0 2022-11-02 op .description = "one word, full confirmation",
131 3448adb0 2022-11-02 op .input = { "HELLO", 5 },
132 3448adb0 2022-11-02 op .output = { true, 5 },
133 3448adb0 2022-11-02 op },
134 3448adb0 2022-11-02 op {
135 3448adb0 2022-11-02 op .description = "one word, violation, NUL-terminated",
136 3448adb0 2022-11-02 op .input = { "hello", SIZE_MAX },
137 3448adb0 2022-11-02 op .output = { false, 0 },
138 3448adb0 2022-11-02 op },
139 3448adb0 2022-11-02 op {
140 3448adb0 2022-11-02 op .description = "one word, partial confirmation, NUL-terminated",
141 3448adb0 2022-11-02 op .input = { "GRU" "\xC3\x9F" "formel", SIZE_MAX },
142 3448adb0 2022-11-02 op .output = { false, 3 },
143 3448adb0 2022-11-02 op },
144 3448adb0 2022-11-02 op {
145 3448adb0 2022-11-02 op .description = "one word, full confirmation, NUL-terminated",
146 3448adb0 2022-11-02 op .input = { "HELLO", SIZE_MAX },
147 3448adb0 2022-11-02 op .output = { true, 5 },
148 3448adb0 2022-11-02 op },
149 3448adb0 2022-11-02 op };
150 3448adb0 2022-11-02 op
151 3448adb0 2022-11-02 op static const struct unit_test_is_case_utf8 is_titlecase_utf8[] = {
152 3448adb0 2022-11-02 op {
153 3448adb0 2022-11-02 op .description = "empty input",
154 3448adb0 2022-11-02 op .input = { "", 0 },
155 3448adb0 2022-11-02 op .output = { true, 0 },
156 3448adb0 2022-11-02 op },
157 3448adb0 2022-11-02 op {
158 3448adb0 2022-11-02 op .description = "one character, violation",
159 3448adb0 2022-11-02 op .input = { "\xC3\x9F", 2 },
160 3448adb0 2022-11-02 op .output = { false, 0 },
161 3448adb0 2022-11-02 op },
162 3448adb0 2022-11-02 op {
163 3448adb0 2022-11-02 op .description = "one character, confirmation",
164 3448adb0 2022-11-02 op .input = { "A", 1 },
165 3448adb0 2022-11-02 op .output = { true, 1 },
166 3448adb0 2022-11-02 op },
167 3448adb0 2022-11-02 op {
168 3448adb0 2022-11-02 op .description = "one character, violation, NUL-terminated",
169 3448adb0 2022-11-02 op .input = { "\xC3\x9F", SIZE_MAX },
170 3448adb0 2022-11-02 op .output = { false, 0 },
171 3448adb0 2022-11-02 op },
172 3448adb0 2022-11-02 op {
173 3448adb0 2022-11-02 op .description = "one character, confirmation, NUL-terminated",
174 3448adb0 2022-11-02 op .input = { "A", SIZE_MAX },
175 3448adb0 2022-11-02 op .output = { true, 1 },
176 3448adb0 2022-11-02 op },
177 3448adb0 2022-11-02 op {
178 3448adb0 2022-11-02 op .description = "one word, violation",
179 3448adb0 2022-11-02 op .input = { "hello", 5 },
180 3448adb0 2022-11-02 op .output = { false, 0 },
181 3448adb0 2022-11-02 op },
182 3448adb0 2022-11-02 op {
183 3448adb0 2022-11-02 op .description = "one word, partial confirmation",
184 3448adb0 2022-11-02 op .input = { "Gru" "\xC3\x9F" "fOrmel", 11 },
185 3448adb0 2022-11-02 op .output = { false, 6 },
186 3448adb0 2022-11-02 op },
187 3448adb0 2022-11-02 op {
188 3448adb0 2022-11-02 op .description = "one word, full confirmation",
189 3448adb0 2022-11-02 op .input = { "Gru" "\xC3\x9F" "formel", 11 },
190 3448adb0 2022-11-02 op .output = { true, 11 },
191 3448adb0 2022-11-02 op },
192 3448adb0 2022-11-02 op {
193 3448adb0 2022-11-02 op .description = "one word, violation, NUL-terminated",
194 3448adb0 2022-11-02 op .input = { "hello", SIZE_MAX },
195 3448adb0 2022-11-02 op .output = { false, 0 },
196 3448adb0 2022-11-02 op },
197 3448adb0 2022-11-02 op {
198 3448adb0 2022-11-02 op .description = "one word, partial confirmation, NUL-terminated",
199 3448adb0 2022-11-02 op .input = { "Gru" "\xC3\x9F" "fOrmel", SIZE_MAX },
200 3448adb0 2022-11-02 op .output = { false, 6 },
201 3448adb0 2022-11-02 op },
202 3448adb0 2022-11-02 op {
203 3448adb0 2022-11-02 op .description = "one word, full confirmation, NUL-terminated",
204 3448adb0 2022-11-02 op .input = { "Gru" "\xC3\x9F" "formel", SIZE_MAX },
205 3448adb0 2022-11-02 op .output = { true, 11 },
206 3448adb0 2022-11-02 op },
207 3448adb0 2022-11-02 op {
208 3448adb0 2022-11-02 op .description = "multiple words, partial confirmation",
209 3448adb0 2022-11-02 op .input = { "Hello Gru" "\xC3\x9F" "fOrmel!", 18 },
210 3448adb0 2022-11-02 op .output = { false, 12 },
211 3448adb0 2022-11-02 op },
212 3448adb0 2022-11-02 op {
213 3448adb0 2022-11-02 op .description = "multiple words, full confirmation",
214 3448adb0 2022-11-02 op .input = { "Hello Gru" "\xC3\x9F" "formel!", 18 },
215 3448adb0 2022-11-02 op .output = { true, 18 },
216 3448adb0 2022-11-02 op },
217 3448adb0 2022-11-02 op {
218 3448adb0 2022-11-02 op .description = "multiple words, partial confirmation, NUL-terminated",
219 3448adb0 2022-11-02 op .input = { "Hello Gru" "\xC3\x9F" "fOrmel!", SIZE_MAX },
220 3448adb0 2022-11-02 op .output = { false, 12 },
221 3448adb0 2022-11-02 op },
222 3448adb0 2022-11-02 op {
223 3448adb0 2022-11-02 op .description = "multiple words, full confirmation, NUL-terminated",
224 3448adb0 2022-11-02 op .input = { "Hello Gru" "\xC3\x9F" "formel!", SIZE_MAX },
225 3448adb0 2022-11-02 op .output = { true, 18 },
226 3448adb0 2022-11-02 op },
227 3448adb0 2022-11-02 op };
228 3448adb0 2022-11-02 op
229 3448adb0 2022-11-02 op static const struct unit_test_to_case_utf8 to_lowercase_utf8[] = {
230 3448adb0 2022-11-02 op {
231 3448adb0 2022-11-02 op .description = "empty input",
232 3448adb0 2022-11-02 op .input = { "", 0, 10 },
233 3448adb0 2022-11-02 op .output = { "", 0 },
234 3448adb0 2022-11-02 op },
235 3448adb0 2022-11-02 op {
236 3448adb0 2022-11-02 op .description = "empty output",
237 3448adb0 2022-11-02 op .input = { "hello", 5, 0 },
238 3448adb0 2022-11-02 op .output = { "", 5 },
239 3448adb0 2022-11-02 op },
240 3448adb0 2022-11-02 op {
241 3448adb0 2022-11-02 op .description = "one character, conversion",
242 3448adb0 2022-11-02 op .input = { "A", 1, 10 },
243 3448adb0 2022-11-02 op .output = { "a", 1 },
244 3448adb0 2022-11-02 op },
245 3448adb0 2022-11-02 op {
246 3448adb0 2022-11-02 op .description = "one character, no conversion",
247 3448adb0 2022-11-02 op .input = { "\xC3\x9F", 2, 10 },
248 3448adb0 2022-11-02 op .output = { "\xC3\x9F", 2 },
249 3448adb0 2022-11-02 op },
250 3448adb0 2022-11-02 op {
251 3448adb0 2022-11-02 op .description = "one character, conversion, truncation",
252 3448adb0 2022-11-02 op .input = { "A", 1, 0 },
253 3448adb0 2022-11-02 op .output = { "", 1 },
254 3448adb0 2022-11-02 op },
255 3448adb0 2022-11-02 op {
256 3448adb0 2022-11-02 op .description = "one character, conversion, NUL-terminated",
257 3448adb0 2022-11-02 op .input = { "A", SIZE_MAX, 10 },
258 3448adb0 2022-11-02 op .output = { "a", 1 },
259 3448adb0 2022-11-02 op },
260 3448adb0 2022-11-02 op {
261 3448adb0 2022-11-02 op .description = "one character, no conversion, NUL-terminated",
262 3448adb0 2022-11-02 op .input = { "\xC3\x9F", SIZE_MAX, 10 },
263 3448adb0 2022-11-02 op .output = { "\xC3\x9F", 2 },
264 3448adb0 2022-11-02 op },
265 3448adb0 2022-11-02 op {
266 3448adb0 2022-11-02 op .description = "one character, conversion, NUL-terminated, truncation",
267 3448adb0 2022-11-02 op .input = { "A", SIZE_MAX, 0 },
268 3448adb0 2022-11-02 op .output = { "", 1 },
269 3448adb0 2022-11-02 op },
270 3448adb0 2022-11-02 op {
271 3448adb0 2022-11-02 op .description = "one word, conversion",
272 3448adb0 2022-11-02 op .input = { "wOrD", 4, 10 },
273 3448adb0 2022-11-02 op .output = { "word", 4 },
274 3448adb0 2022-11-02 op },
275 3448adb0 2022-11-02 op {
276 3448adb0 2022-11-02 op .description = "one word, no conversion",
277 3448adb0 2022-11-02 op .input = { "word", 4, 10 },
278 3448adb0 2022-11-02 op .output = { "word", 4 },
279 3448adb0 2022-11-02 op },
280 3448adb0 2022-11-02 op {
281 3448adb0 2022-11-02 op .description = "one word, conversion, truncation",
282 3448adb0 2022-11-02 op .input = { "wOrD", 4, 3 },
283 3448adb0 2022-11-02 op .output = { "wo", 4 },
284 3448adb0 2022-11-02 op },
285 3448adb0 2022-11-02 op {
286 3448adb0 2022-11-02 op .description = "one word, conversion, NUL-terminated",
287 3448adb0 2022-11-02 op .input = { "wOrD", SIZE_MAX, 10 },
288 3448adb0 2022-11-02 op .output = { "word", 4 },
289 3448adb0 2022-11-02 op },
290 3448adb0 2022-11-02 op {
291 3448adb0 2022-11-02 op .description = "one word, no conversion, NUL-terminated",
292 3448adb0 2022-11-02 op .input = { "word", SIZE_MAX, 10 },
293 3448adb0 2022-11-02 op .output = { "word", 4 },
294 3448adb0 2022-11-02 op },
295 3448adb0 2022-11-02 op {
296 3448adb0 2022-11-02 op .description = "one word, conversion, NUL-terminated, truncation",
297 3448adb0 2022-11-02 op .input = { "wOrD", SIZE_MAX, 3 },
298 3448adb0 2022-11-02 op .output = { "wo", 4 },
299 3448adb0 2022-11-02 op },
300 3448adb0 2022-11-02 op };
301 3448adb0 2022-11-02 op
302 3448adb0 2022-11-02 op static const struct unit_test_to_case_utf8 to_uppercase_utf8[] = {
303 3448adb0 2022-11-02 op {
304 3448adb0 2022-11-02 op .description = "empty input",
305 3448adb0 2022-11-02 op .input = { "", 0, 10 },
306 3448adb0 2022-11-02 op .output = { "", 0 },
307 3448adb0 2022-11-02 op },
308 3448adb0 2022-11-02 op {
309 3448adb0 2022-11-02 op .description = "empty output",
310 3448adb0 2022-11-02 op .input = { "hello", 5, 0 },
311 3448adb0 2022-11-02 op .output = { "", 5 },
312 3448adb0 2022-11-02 op },
313 3448adb0 2022-11-02 op {
314 3448adb0 2022-11-02 op .description = "one character, conversion",
315 3448adb0 2022-11-02 op .input = { "\xC3\x9F", 2, 10 },
316 3448adb0 2022-11-02 op .output = { "SS", 2 },
317 3448adb0 2022-11-02 op },
318 3448adb0 2022-11-02 op {
319 3448adb0 2022-11-02 op .description = "one character, no conversion",
320 3448adb0 2022-11-02 op .input = { "A", 1, 10 },
321 3448adb0 2022-11-02 op .output = { "A", 1 },
322 3448adb0 2022-11-02 op },
323 3448adb0 2022-11-02 op {
324 3448adb0 2022-11-02 op .description = "one character, conversion, truncation",
325 3448adb0 2022-11-02 op .input = { "\xC3\x9F", 2, 0 },
326 3448adb0 2022-11-02 op .output = { "", 2 },
327 3448adb0 2022-11-02 op },
328 3448adb0 2022-11-02 op {
329 3448adb0 2022-11-02 op .description = "one character, conversion, NUL-terminated",
330 3448adb0 2022-11-02 op .input = { "\xC3\x9F", SIZE_MAX, 10 },
331 3448adb0 2022-11-02 op .output = { "SS", 2 },
332 3448adb0 2022-11-02 op },
333 3448adb0 2022-11-02 op {
334 3448adb0 2022-11-02 op .description = "one character, no conversion, NUL-terminated",
335 3448adb0 2022-11-02 op .input = { "A", SIZE_MAX, 10 },
336 3448adb0 2022-11-02 op .output = { "A", 1 },
337 3448adb0 2022-11-02 op },
338 3448adb0 2022-11-02 op {
339 3448adb0 2022-11-02 op .description = "one character, conversion, NUL-terminated, truncation",
340 3448adb0 2022-11-02 op .input = { "\xC3\x9F", SIZE_MAX, 0 },
341 3448adb0 2022-11-02 op .output = { "", 2 },
342 3448adb0 2022-11-02 op },
343 3448adb0 2022-11-02 op {
344 3448adb0 2022-11-02 op .description = "one word, conversion",
345 3448adb0 2022-11-02 op .input = { "gRu" "\xC3\x9F" "fOrMel", 11, 15 },
346 3448adb0 2022-11-02 op .output = { "GRUSSFORMEL", 11 },
347 3448adb0 2022-11-02 op },
348 3448adb0 2022-11-02 op {
349 3448adb0 2022-11-02 op .description = "one word, no conversion",
350 3448adb0 2022-11-02 op .input = { "WORD", 4, 10 },
351 3448adb0 2022-11-02 op .output = { "WORD", 4 },
352 3448adb0 2022-11-02 op },
353 3448adb0 2022-11-02 op {
354 3448adb0 2022-11-02 op .description = "one word, conversion, truncation",
355 3448adb0 2022-11-02 op .input = { "gRu" "\xC3\x9F" "formel", 11, 5 },
356 3448adb0 2022-11-02 op .output = { "GRUS", 11 },
357 3448adb0 2022-11-02 op },
358 3448adb0 2022-11-02 op {
359 3448adb0 2022-11-02 op .description = "one word, conversion, NUL-terminated",
360 3448adb0 2022-11-02 op .input = { "gRu" "\xC3\x9F" "formel", SIZE_MAX, 15 },
361 3448adb0 2022-11-02 op .output = { "GRUSSFORMEL", 11 },
362 3448adb0 2022-11-02 op },
363 3448adb0 2022-11-02 op {
364 3448adb0 2022-11-02 op .description = "one word, no conversion, NUL-terminated",
365 3448adb0 2022-11-02 op .input = { "WORD", SIZE_MAX, 10 },
366 3448adb0 2022-11-02 op .output = { "WORD", 4 },
367 3448adb0 2022-11-02 op },
368 3448adb0 2022-11-02 op {
369 3448adb0 2022-11-02 op .description = "one word, conversion, NUL-terminated, truncation",
370 3448adb0 2022-11-02 op .input = { "gRu" "\xC3\x9F" "formel", SIZE_MAX, 5 },
371 3448adb0 2022-11-02 op .output = { "GRUS", 11 },
372 3448adb0 2022-11-02 op },
373 3448adb0 2022-11-02 op };
374 3448adb0 2022-11-02 op
375 3448adb0 2022-11-02 op static const struct unit_test_to_case_utf8 to_titlecase_utf8[] = {
376 3448adb0 2022-11-02 op {
377 3448adb0 2022-11-02 op .description = "empty input",
378 3448adb0 2022-11-02 op .input = { "", 0, 10 },
379 3448adb0 2022-11-02 op .output = { "", 0 },
380 3448adb0 2022-11-02 op },
381 3448adb0 2022-11-02 op {
382 3448adb0 2022-11-02 op .description = "empty output",
383 3448adb0 2022-11-02 op .input = { "hello", 5, 0 },
384 3448adb0 2022-11-02 op .output = { "", 5 },
385 3448adb0 2022-11-02 op },
386 3448adb0 2022-11-02 op {
387 3448adb0 2022-11-02 op .description = "one character, conversion",
388 3448adb0 2022-11-02 op .input = { "a", 1, 10 },
389 3448adb0 2022-11-02 op .output = { "A", 1 },
390 3448adb0 2022-11-02 op },
391 3448adb0 2022-11-02 op {
392 3448adb0 2022-11-02 op .description = "one character, no conversion",
393 3448adb0 2022-11-02 op .input = { "A", 1, 10 },
394 3448adb0 2022-11-02 op .output = { "A", 1 },
395 3448adb0 2022-11-02 op },
396 3448adb0 2022-11-02 op {
397 3448adb0 2022-11-02 op .description = "one character, conversion, truncation",
398 3448adb0 2022-11-02 op .input = { "a", 1, 0 },
399 3448adb0 2022-11-02 op .output = { "", 1 },
400 3448adb0 2022-11-02 op },
401 3448adb0 2022-11-02 op {
402 3448adb0 2022-11-02 op .description = "one character, conversion, NUL-terminated",
403 3448adb0 2022-11-02 op .input = { "a", SIZE_MAX, 10 },
404 3448adb0 2022-11-02 op .output = { "A", 1 },
405 3448adb0 2022-11-02 op },
406 3448adb0 2022-11-02 op {
407 3448adb0 2022-11-02 op .description = "one character, no conversion, NUL-terminated",
408 3448adb0 2022-11-02 op .input = { "A", SIZE_MAX, 10 },
409 3448adb0 2022-11-02 op .output = { "A", 1 },
410 3448adb0 2022-11-02 op },
411 3448adb0 2022-11-02 op {
412 3448adb0 2022-11-02 op .description = "one character, conversion, NUL-terminated, truncation",
413 3448adb0 2022-11-02 op .input = { "a", SIZE_MAX, 0 },
414 3448adb0 2022-11-02 op .output = { "", 1 },
415 3448adb0 2022-11-02 op },
416 3448adb0 2022-11-02 op {
417 3448adb0 2022-11-02 op .description = "one word, conversion",
418 3448adb0 2022-11-02 op .input = { "heLlo", 5, 10 },
419 3448adb0 2022-11-02 op .output = { "Hello", 5 },
420 3448adb0 2022-11-02 op },
421 3448adb0 2022-11-02 op {
422 3448adb0 2022-11-02 op .description = "one word, no conversion",
423 3448adb0 2022-11-02 op .input = { "Hello", 5, 10 },
424 3448adb0 2022-11-02 op .output = { "Hello", 5 },
425 3448adb0 2022-11-02 op },
426 3448adb0 2022-11-02 op {
427 3448adb0 2022-11-02 op .description = "one word, conversion, truncation",
428 3448adb0 2022-11-02 op .input = { "heLlo", 5, 2 },
429 3448adb0 2022-11-02 op .output = { "H", 5 },
430 3448adb0 2022-11-02 op },
431 3448adb0 2022-11-02 op {
432 3448adb0 2022-11-02 op .description = "one word, conversion, NUL-terminated",
433 3448adb0 2022-11-02 op .input = { "heLlo", SIZE_MAX, 10 },
434 3448adb0 2022-11-02 op .output = { "Hello", 5 },
435 3448adb0 2022-11-02 op },
436 3448adb0 2022-11-02 op {
437 3448adb0 2022-11-02 op .description = "one word, no conversion, NUL-terminated",
438 3448adb0 2022-11-02 op .input = { "Hello", SIZE_MAX, 10 },
439 3448adb0 2022-11-02 op .output = { "Hello", 5 },
440 3448adb0 2022-11-02 op },
441 3448adb0 2022-11-02 op {
442 3448adb0 2022-11-02 op .description = "one word, conversion, NUL-terminated, truncation",
443 3448adb0 2022-11-02 op .input = { "heLlo", SIZE_MAX, 3 },
444 3448adb0 2022-11-02 op .output = { "He", 5 },
445 3448adb0 2022-11-02 op },
446 3448adb0 2022-11-02 op {
447 3448adb0 2022-11-02 op .description = "two words, conversion",
448 3448adb0 2022-11-02 op .input = { "heLlo wORLd!", 12, 20 },
449 3448adb0 2022-11-02 op .output = { "Hello World!", 12 },
450 3448adb0 2022-11-02 op },
451 3448adb0 2022-11-02 op {
452 3448adb0 2022-11-02 op .description = "two words, no conversion",
453 3448adb0 2022-11-02 op .input = { "Hello World!", 12, 20 },
454 3448adb0 2022-11-02 op .output = { "Hello World!", 12 },
455 3448adb0 2022-11-02 op },
456 3448adb0 2022-11-02 op {
457 3448adb0 2022-11-02 op .description = "two words, conversion, truncation",
458 3448adb0 2022-11-02 op .input = { "heLlo wORLd!", 12, 8 },
459 3448adb0 2022-11-02 op .output = { "Hello W", 12 },
460 3448adb0 2022-11-02 op },
461 3448adb0 2022-11-02 op {
462 3448adb0 2022-11-02 op .description = "two words, conversion, NUL-terminated",
463 3448adb0 2022-11-02 op .input = { "heLlo wORLd!", SIZE_MAX, 20 },
464 3448adb0 2022-11-02 op .output = { "Hello World!", 12 },
465 3448adb0 2022-11-02 op },
466 3448adb0 2022-11-02 op {
467 3448adb0 2022-11-02 op .description = "two words, no conversion, NUL-terminated",
468 3448adb0 2022-11-02 op .input = { "Hello World!", SIZE_MAX, 20 },
469 3448adb0 2022-11-02 op .output = { "Hello World!", 12 },
470 3448adb0 2022-11-02 op },
471 3448adb0 2022-11-02 op {
472 3448adb0 2022-11-02 op .description = "two words, conversion, NUL-terminated, truncation",
473 3448adb0 2022-11-02 op .input = { "heLlo wORLd!", SIZE_MAX, 4 },
474 3448adb0 2022-11-02 op .output = { "Hel", 12 },
475 3448adb0 2022-11-02 op },
476 3448adb0 2022-11-02 op };
477 3448adb0 2022-11-02 op
478 3448adb0 2022-11-02 op static int
479 3448adb0 2022-11-02 op unit_test_callback_is_case_utf8(const void *t, size_t off, const char *name,
480 3448adb0 2022-11-02 op const char *argv0)
481 3448adb0 2022-11-02 op {
482 3448adb0 2022-11-02 op const struct unit_test_is_case_utf8 *test =
483 3448adb0 2022-11-02 op (const struct unit_test_is_case_utf8 *)t + off;
484 3448adb0 2022-11-02 op bool ret = false;
485 3448adb0 2022-11-02 op size_t caselen = 0x7f;
486 3448adb0 2022-11-02 op
487 3448adb0 2022-11-02 op if (t == is_lowercase_utf8) {
488 3448adb0 2022-11-02 op ret = grapheme_is_lowercase_utf8(test->input.src, test->input.srclen,
489 3448adb0 2022-11-02 op &caselen);
490 3448adb0 2022-11-02 op } else if (t == is_uppercase_utf8) {
491 3448adb0 2022-11-02 op ret = grapheme_is_uppercase_utf8(test->input.src, test->input.srclen,
492 3448adb0 2022-11-02 op &caselen);
493 3448adb0 2022-11-02 op } else if (t == is_titlecase_utf8) {
494 3448adb0 2022-11-02 op ret = grapheme_is_titlecase_utf8(test->input.src, test->input.srclen,
495 3448adb0 2022-11-02 op &caselen);
496 3448adb0 2022-11-02 op
497 3448adb0 2022-11-02 op } else {
498 3448adb0 2022-11-02 op goto err;
499 3448adb0 2022-11-02 op }
500 3448adb0 2022-11-02 op
501 3448adb0 2022-11-02 op /* check results */
502 3448adb0 2022-11-02 op if (ret != test->output.ret || caselen != test->output.caselen) {
503 3448adb0 2022-11-02 op goto err;
504 3448adb0 2022-11-02 op }
505 3448adb0 2022-11-02 op
506 3448adb0 2022-11-02 op return 0;
507 3448adb0 2022-11-02 op err:
508 3448adb0 2022-11-02 op fprintf(stderr, "%s: %s: Failed unit test %zu \"%s\" "
509 3448adb0 2022-11-02 op "(returned (%s, %zu) instead of (%s, %zu)).\n", argv0,
510 3448adb0 2022-11-02 op name, off, test->description, ret ? "true" : "false",
511 3448adb0 2022-11-02 op caselen, test->output.ret ? "true" : "false",
512 3448adb0 2022-11-02 op test->output.caselen);
513 3448adb0 2022-11-02 op return 1;
514 3448adb0 2022-11-02 op }
515 3448adb0 2022-11-02 op
516 3448adb0 2022-11-02 op static int
517 3448adb0 2022-11-02 op unit_test_callback_to_case_utf8(const void *t, size_t off, const char *name,
518 3448adb0 2022-11-02 op const char *argv0)
519 3448adb0 2022-11-02 op {
520 3448adb0 2022-11-02 op const struct unit_test_to_case_utf8 *test =
521 3448adb0 2022-11-02 op (const struct unit_test_to_case_utf8 *)t + off;
522 3448adb0 2022-11-02 op size_t ret = 0, i;
523 3448adb0 2022-11-02 op char buf[512];
524 3448adb0 2022-11-02 op
525 3448adb0 2022-11-02 op /* fill the array with canary values */
526 3448adb0 2022-11-02 op memset(buf, 0x7f, LEN(buf));
527 3448adb0 2022-11-02 op
528 3448adb0 2022-11-02 op if (t == to_lowercase_utf8) {
529 3448adb0 2022-11-02 op ret = grapheme_to_lowercase_utf8(test->input.src, test->input.srclen,
530 3448adb0 2022-11-02 op buf, test->input.destlen);
531 3448adb0 2022-11-02 op } else if (t == to_uppercase_utf8) {
532 3448adb0 2022-11-02 op ret = grapheme_to_uppercase_utf8(test->input.src, test->input.srclen,
533 3448adb0 2022-11-02 op buf, test->input.destlen);
534 3448adb0 2022-11-02 op } else if (t == to_titlecase_utf8) {
535 3448adb0 2022-11-02 op ret = grapheme_to_titlecase_utf8(test->input.src, test->input.srclen,
536 3448adb0 2022-11-02 op buf, test->input.destlen);
537 3448adb0 2022-11-02 op } else {
538 3448adb0 2022-11-02 op goto err;
539 3448adb0 2022-11-02 op }
540 3448adb0 2022-11-02 op
541 3448adb0 2022-11-02 op /* check results */
542 3448adb0 2022-11-02 op if (ret != test->output.ret ||
543 3448adb0 2022-11-02 op memcmp(buf, test->output.dest, MIN(test->input.destlen, test->output.ret))) {
544 3448adb0 2022-11-02 op goto err;
545 3448adb0 2022-11-02 op }
546 3448adb0 2022-11-02 op
547 3448adb0 2022-11-02 op /* check that none of the canary values have been overwritten */
548 3448adb0 2022-11-02 op for (i = test->input.destlen; i < LEN(buf); i++) {
549 3448adb0 2022-11-02 op if (buf[i] != 0x7f) {
550 3448adb0 2022-11-02 op goto err;
551 3448adb0 2022-11-02 op }
552 3448adb0 2022-11-02 op }
553 3448adb0 2022-11-02 op
554 3448adb0 2022-11-02 op return 0;
555 3448adb0 2022-11-02 op err:
556 3448adb0 2022-11-02 op fprintf(stderr, "%s: %s: Failed unit test %zu \"%s\" "
557 3448adb0 2022-11-02 op "(returned (\"%.*s\", %zu) instead of (\"%.*s\", %zu)).\n", argv0,
558 3448adb0 2022-11-02 op name, off, test->description, (int)ret, buf, ret,
559 3448adb0 2022-11-02 op (int)test->output.ret, test->output.dest, test->output.ret);
560 3448adb0 2022-11-02 op return 1;
561 3448adb0 2022-11-02 op }
562 3448adb0 2022-11-02 op
563 3448adb0 2022-11-02 op int
564 3448adb0 2022-11-02 op main(int argc, char *argv[])
565 3448adb0 2022-11-02 op {
566 3448adb0 2022-11-02 op (void)argc;
567 3448adb0 2022-11-02 op
568 3448adb0 2022-11-02 op return run_unit_tests(unit_test_callback_is_case_utf8, is_lowercase_utf8,
569 3448adb0 2022-11-02 op LEN(is_lowercase_utf8), "grapheme_is_lowercase_utf8", argv[0]) +
570 3448adb0 2022-11-02 op run_unit_tests(unit_test_callback_is_case_utf8, is_uppercase_utf8,
571 3448adb0 2022-11-02 op LEN(is_uppercase_utf8), "grapheme_is_uppercase_utf8", argv[0]) +
572 3448adb0 2022-11-02 op run_unit_tests(unit_test_callback_is_case_utf8, is_titlecase_utf8,
573 3448adb0 2022-11-02 op LEN(is_titlecase_utf8), "grapheme_is_titlecase_utf8", argv[0]) +
574 3448adb0 2022-11-02 op run_unit_tests(unit_test_callback_to_case_utf8, to_lowercase_utf8,
575 3448adb0 2022-11-02 op LEN(to_lowercase_utf8), "grapheme_to_lowercase_utf8", argv[0]) +
576 3448adb0 2022-11-02 op run_unit_tests(unit_test_callback_to_case_utf8, to_uppercase_utf8,
577 3448adb0 2022-11-02 op LEN(to_uppercase_utf8), "grapheme_to_uppercase_utf8", argv[0]) +
578 3448adb0 2022-11-02 op run_unit_tests(unit_test_callback_to_case_utf8, to_titlecase_utf8,
579 3448adb0 2022-11-02 op LEN(to_titlecase_utf8), "grapheme_to_titlecase_utf8", argv[0]);
580 3448adb0 2022-11-02 op }