Merge branch 'master' of git://git.denx.de/u-boot-sh
[oweals/u-boot.git] / test / unicode_ut.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Unit tests for Unicode functions
4  *
5  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  */
7
8 #include <common.h>
9 #include <charset.h>
10 #include <command.h>
11 #include <errno.h>
12 #include <test/test.h>
13 #include <test/suites.h>
14 #include <test/ut.h>
15
16 /* Linker list entry for a Unicode test */
17 #define UNICODE_TEST(_name) UNIT_TEST(_name, 0, unicode_test)
18
19 /* Constants c1-c4 and d1-d4 encode the same letters */
20
21 /* Six characters translating to one utf-8 byte each. */
22 static const u16 c1[] = {0x55, 0x2d, 0x42, 0x6f, 0x6f, 0x74, 0x00};
23 /* One character translating to two utf-8 bytes */
24 static const u16 c2[] = {0x6b, 0x61, 0x66, 0x62, 0xe1, 0x74, 0x75, 0x72, 0x00};
25 /* Three characters translating to three utf-8 bytes each */
26 static const u16 c3[] = {0x6f5c, 0x6c34, 0x8266, 0x00};
27 /* Three letters translating to four utf-8 bytes each */
28 static const u16 c4[] = {0xd801, 0xdc8d, 0xd801, 0xdc96, 0xd801, 0xdc87,
29                          0x0000};
30
31 /* Illegal utf-16 strings */
32 static const u16 i1[] = {0x69, 0x31, 0xdc87, 0x6c, 0x00};
33 static const u16 i2[] = {0x69, 0x32, 0xd801, 0xd801, 0x6c, 0x00};
34 static const u16 i3[] = {0x69, 0x33, 0xd801, 0x00};
35
36 /* Six characters translating to one utf-16 word each. */
37 static const char d1[] = {0x55, 0x2d, 0x42, 0x6f, 0x6f, 0x74, 0x00};
38 /* Eight characters translating to one utf-16 word each */
39 static const char d2[] = {0x6b, 0x61, 0x66, 0x62, 0xc3, 0xa1, 0x74, 0x75,
40                           0x72, 0x00};
41 /* Three characters translating to one utf-16 word each */
42 static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89,
43                           0xa6, 0x00};
44 /* Three letters translating to two utf-16 word each */
45 static const char d4[] = {0xf0, 0x90, 0x92, 0x8d, 0xf0, 0x90, 0x92, 0x96,
46                           0xf0, 0x90, 0x92, 0x87, 0x00};
47
48 /* Illegal utf-8 strings */
49 static const char j1[] = {0x6a, 0x31, 0xa1, 0x6c, 0x00};
50 static const char j2[] = {0x6a, 0x32, 0xc3, 0xc3, 0x6c, 0x00};
51 static const char j3[] = {0x6a, 0x33, 0xf0, 0x90, 0xf0, 0x00};
52
53 static int unicode_test_u16_strlen(struct unit_test_state *uts)
54 {
55         ut_asserteq(6, u16_strlen(c1));
56         ut_asserteq(8, u16_strlen(c2));
57         ut_asserteq(3, u16_strlen(c3));
58         ut_asserteq(6, u16_strlen(c4));
59         return 0;
60 }
61 UNICODE_TEST(unicode_test_u16_strlen);
62
63 static int unicode_test_u16_strdup(struct unit_test_state *uts)
64 {
65         u16 *copy = u16_strdup(c4);
66
67         ut_assert(copy != c4);
68         ut_assert(!memcmp(copy, c4, sizeof(c4)));
69         free(copy);
70         return 0;
71 }
72 UNICODE_TEST(unicode_test_u16_strdup);
73
74 static int unicode_test_u16_strcpy(struct unit_test_state *uts)
75 {
76         u16 *r;
77         u16 copy[10];
78
79         r = u16_strcpy(copy, c1);
80         ut_assert(r == copy);
81         ut_assert(!memcmp(copy, c1, sizeof(c1)));
82         return 0;
83 }
84 UNICODE_TEST(unicode_test_u16_strcpy);
85
86 /* U-Boot uses UTF-16 strings in the EFI context only. */
87 #if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
88 static int unicode_test_string16(struct unit_test_state *uts)
89 {
90         char buf[20];
91
92         /* Test length and precision */
93         memset(buf, 0xff, sizeof(buf));
94         sprintf(buf, "%8.6ls", c2);
95         ut_asserteq(' ', buf[1]);
96         ut_assert(!strncmp(&buf[2], d2, 7));
97         ut_assert(!buf[9]);
98
99         memset(buf, 0xff, sizeof(buf));
100         sprintf(buf, "%8.6ls", c4);
101         ut_asserteq(' ', buf[4]);
102         ut_assert(!strncmp(&buf[5], d4, 12));
103         ut_assert(!buf[17]);
104
105         memset(buf, 0xff, sizeof(buf));
106         sprintf(buf, "%-8.2ls", c4);
107         ut_asserteq(' ', buf[8]);
108         ut_assert(!strncmp(buf, d4, 8));
109         ut_assert(!buf[14]);
110
111         /* Test handling of illegal utf-16 sequences */
112         memset(buf, 0xff, sizeof(buf));
113         sprintf(buf, "%ls", i1);
114         ut_asserteq_str("i1?l", buf);
115
116         memset(buf, 0xff, sizeof(buf));
117         sprintf(buf, "%ls", i2);
118         ut_asserteq_str("i2?l", buf);
119
120         memset(buf, 0xff, sizeof(buf));
121         sprintf(buf, "%ls", i3);
122         ut_asserteq_str("i3?", buf);
123
124         return 0;
125 }
126 UNICODE_TEST(unicode_test_string16);
127 #endif
128
129 static int unicode_test_utf8_get(struct unit_test_state *uts)
130 {
131         const char *s;
132         s32 code;
133         int i;
134
135         /* Check characters less than 0x800 */
136         s = d2;
137         for (i = 0; i < 8; ++i) {
138                 code = utf8_get((const char **)&s);
139                 /* c2 is the utf-8 encoding of d2 */
140                 ut_asserteq(c2[i], code);
141                 if (!code)
142                         break;
143         }
144         ut_asserteq_ptr(s, d2 + 9)
145
146         /* Check characters less than 0x10000 */
147         s = d3;
148         for (i = 0; i < 4; ++i) {
149                 code = utf8_get((const char **)&s);
150                 /* c3 is the utf-8 encoding of d3 */
151                 ut_asserteq(c3[i], code);
152                 if (!code)
153                         break;
154         }
155         ut_asserteq_ptr(s, d3 + 9)
156
157         /* Check character greater 0xffff */
158         s = d4;
159         code = utf8_get((const char **)&s);
160         ut_asserteq(0x0001048d, code);
161         ut_asserteq_ptr(s, d4 + 4);
162
163         return 0;
164 }
165 UNICODE_TEST(unicode_test_utf8_get);
166
167 static int unicode_test_utf8_put(struct unit_test_state *uts)
168 {
169         char buffer[8] = { 0, };
170         char *pos;
171
172         /* Commercial at, translates to one character */
173         pos = buffer;
174         ut_assert(!utf8_put('@', &pos))
175         ut_asserteq(1, pos - buffer);
176         ut_asserteq('@', buffer[0]);
177         ut_assert(!buffer[1]);
178
179         /* Latin letter G with acute, translates to two charactes */
180         pos = buffer;
181         ut_assert(!utf8_put(0x1f4, &pos));
182         ut_asserteq(2, pos - buffer);
183         ut_asserteq_str("\xc7\xb4", buffer);
184
185         /* Tagalog letter i, translates to three characters */
186         pos = buffer;
187         ut_assert(!utf8_put(0x1701, &pos));
188         ut_asserteq(3, pos - buffer);
189         ut_asserteq_str("\xe1\x9c\x81", buffer);
190
191         /* Hamster face, translates to four characters */
192         pos = buffer;
193         ut_assert(!utf8_put(0x1f439, &pos));
194         ut_asserteq(4, pos - buffer);
195         ut_asserteq_str("\xf0\x9f\x90\xb9", buffer);
196
197         /* Illegal code */
198         pos = buffer;
199         ut_asserteq(-1, utf8_put(0xd888, &pos));
200
201         return 0;
202 }
203 UNICODE_TEST(unicode_test_utf8_put);
204
205 static int unicode_test_utf8_utf16_strlen(struct unit_test_state *uts)
206 {
207         ut_asserteq(6, utf8_utf16_strlen(d1));
208         ut_asserteq(8, utf8_utf16_strlen(d2));
209         ut_asserteq(3, utf8_utf16_strlen(d3));
210         ut_asserteq(6, utf8_utf16_strlen(d4));
211
212         /* illegal utf-8 sequences */
213         ut_asserteq(4, utf8_utf16_strlen(j1));
214         ut_asserteq(4, utf8_utf16_strlen(j2));
215         ut_asserteq(3, utf8_utf16_strlen(j3));
216
217         return 0;
218 }
219 UNICODE_TEST(unicode_test_utf8_utf16_strlen);
220
221 static int unicode_test_utf8_utf16_strnlen(struct unit_test_state *uts)
222 {
223         ut_asserteq(3, utf8_utf16_strnlen(d1, 3));
224         ut_asserteq(6, utf8_utf16_strnlen(d1, 13));
225         ut_asserteq(6, utf8_utf16_strnlen(d2, 6));
226         ut_asserteq(2, utf8_utf16_strnlen(d3, 2));
227         ut_asserteq(4, utf8_utf16_strnlen(d4, 2));
228         ut_asserteq(6, utf8_utf16_strnlen(d4, 3));
229
230         /* illegal utf-8 sequences */
231         ut_asserteq(4, utf8_utf16_strnlen(j1, 16));
232         ut_asserteq(4, utf8_utf16_strnlen(j2, 16));
233         ut_asserteq(3, utf8_utf16_strnlen(j3, 16));
234
235         return 0;
236 }
237 UNICODE_TEST(unicode_test_utf8_utf16_strnlen);
238
239 /**
240  * ut_u16_strcmp() - Compare to u16 strings.
241  *
242  * @a1:         first string
243  * @a2:         second string
244  * @count:      number of u16 to compare
245  * Return:      -1 if a1 < a2, 0 if a1 == a2, 1 if a1 > a2
246  */
247 static int unicode_test_u16_strcmp(const u16 *a1, const u16 *a2, size_t count)
248 {
249         for (; (*a1 || *a2) && count; ++a1, ++a2, --count) {
250                 if (*a1 < *a2)
251                         return -1;
252                 if (*a1 > *a2)
253                         return 1;
254         }
255         return 0;
256 }
257
258 static int unicode_test_utf8_utf16_strcpy(struct unit_test_state *uts)
259 {
260         u16 buf[16];
261         u16 *pos;
262
263         pos = buf;
264         utf8_utf16_strcpy(&pos, d1);
265         ut_asserteq(6, pos - buf);
266         ut_assert(!unicode_test_u16_strcmp(buf, c1, SIZE_MAX));
267
268         pos = buf;
269         utf8_utf16_strcpy(&pos, d2);
270         ut_asserteq(8, pos - buf);
271         ut_assert(!unicode_test_u16_strcmp(buf, c2, SIZE_MAX));
272
273         pos = buf;
274         utf8_utf16_strcpy(&pos, d3);
275         ut_asserteq(3, pos - buf);
276         ut_assert(!unicode_test_u16_strcmp(buf, c3, SIZE_MAX));
277
278         pos = buf;
279         utf8_utf16_strcpy(&pos, d4);
280         ut_asserteq(6, pos - buf);
281         ut_assert(!unicode_test_u16_strcmp(buf, c4, SIZE_MAX));
282
283         /* Illegal utf-8 strings */
284         pos = buf;
285         utf8_utf16_strcpy(&pos, j1);
286         ut_asserteq(4, pos - buf);
287         ut_assert(!unicode_test_u16_strcmp(buf, L"j1?l", SIZE_MAX));
288
289         pos = buf;
290         utf8_utf16_strcpy(&pos, j2);
291         ut_asserteq(4, pos - buf);
292         ut_assert(!unicode_test_u16_strcmp(buf, L"j2?l", SIZE_MAX));
293
294         pos = buf;
295         utf8_utf16_strcpy(&pos, j3);
296         ut_asserteq(3, pos - buf);
297         ut_assert(!unicode_test_u16_strcmp(buf, L"j3?", SIZE_MAX));
298
299         return 0;
300 }
301 UNICODE_TEST(unicode_test_utf8_utf16_strcpy);
302
303 static int unicode_test_utf8_utf16_strncpy(struct unit_test_state *uts)
304 {
305         u16 buf[16];
306         u16 *pos;
307
308         pos = buf;
309         memset(buf, 0, sizeof(buf));
310         utf8_utf16_strncpy(&pos, d1, 4);
311         ut_asserteq(4, pos - buf);
312         ut_assert(!buf[4]);
313         ut_assert(!unicode_test_u16_strcmp(buf, c1, 4));
314
315         pos = buf;
316         memset(buf, 0, sizeof(buf));
317         utf8_utf16_strncpy(&pos, d2, 10);
318         ut_asserteq(8, pos - buf);
319         ut_assert(buf[4]);
320         ut_assert(!unicode_test_u16_strcmp(buf, c2, SIZE_MAX));
321
322         pos = buf;
323         memset(buf, 0, sizeof(buf));
324         utf8_utf16_strncpy(&pos, d3, 2);
325         ut_asserteq(2, pos - buf);
326         ut_assert(!buf[2]);
327         ut_assert(!unicode_test_u16_strcmp(buf, c3, 2));
328
329         pos = buf;
330         memset(buf, 0, sizeof(buf));
331         utf8_utf16_strncpy(&pos, d4, 2);
332         ut_asserteq(4, pos - buf);
333         ut_assert(!buf[4]);
334         ut_assert(!unicode_test_u16_strcmp(buf, c4, 4));
335
336         pos = buf;
337         memset(buf, 0, sizeof(buf));
338         utf8_utf16_strncpy(&pos, d4, 10);
339         ut_asserteq(6, pos - buf);
340         ut_assert(buf[5]);
341         ut_assert(!unicode_test_u16_strcmp(buf, c4, SIZE_MAX));
342
343         return 0;
344 }
345 UNICODE_TEST(unicode_test_utf8_utf16_strncpy);
346
347 static int unicode_test_utf16_get(struct unit_test_state *uts)
348 {
349         const u16 *s;
350         s32 code;
351         int i;
352
353         /* Check characters less than 0x10000 */
354         s = c2;
355         for (i = 0; i < 9; ++i) {
356                 code = utf16_get((const u16 **)&s);
357                 ut_asserteq(c2[i], code);
358                 if (!code)
359                         break;
360         }
361         ut_asserteq_ptr(c2 + 8, s);
362
363         /* Check character greater 0xffff */
364         s = c4;
365         code = utf16_get((const u16 **)&s);
366         ut_asserteq(0x0001048d, code);
367         ut_asserteq_ptr(c4 + 2, s);
368
369         return 0;
370 }
371 UNICODE_TEST(unicode_test_utf16_get);
372
373 static int unicode_test_utf16_put(struct unit_test_state *uts)
374 {
375         u16 buffer[4] = { 0, };
376         u16 *pos;
377
378         /* Commercial at, translates to one word */
379         pos = buffer;
380         ut_assert(!utf16_put('@', &pos));
381         ut_asserteq(1, pos - buffer);
382         ut_asserteq((u16)'@', buffer[0]);
383         ut_assert(!buffer[1]);
384
385         /* Hamster face, translates to two words */
386         pos = buffer;
387         ut_assert(!utf16_put(0x1f439, &pos));
388         ut_asserteq(2, pos - buffer);
389         ut_asserteq((u16)0xd83d, buffer[0]);
390         ut_asserteq((u16)0xdc39, buffer[1]);
391         ut_assert(!buffer[2]);
392
393         /* Illegal code */
394         pos = buffer;
395         ut_asserteq(-1, utf16_put(0xd888, &pos));
396
397         return 0;
398 }
399 UNICODE_TEST(unicode_test_utf16_put);
400
401 static int unicode_test_utf16_strnlen(struct unit_test_state *uts)
402 {
403         ut_asserteq(3, utf16_strnlen(c1, 3));
404         ut_asserteq(6, utf16_strnlen(c1, 13));
405         ut_asserteq(6, utf16_strnlen(c2, 6));
406         ut_asserteq(2, utf16_strnlen(c3, 2));
407         ut_asserteq(2, utf16_strnlen(c4, 2));
408         ut_asserteq(3, utf16_strnlen(c4, 3));
409
410         /* illegal utf-16 word sequences */
411         ut_asserteq(4, utf16_strnlen(i1, 16));
412         ut_asserteq(4, utf16_strnlen(i2, 16));
413         ut_asserteq(3, utf16_strnlen(i3, 16));
414
415         return 0;
416 }
417 UNICODE_TEST(unicode_test_utf16_strnlen);
418
419 static int unicode_test_utf16_utf8_strlen(struct unit_test_state *uts)
420 {
421         ut_asserteq(6, utf16_utf8_strlen(c1));
422         ut_asserteq(9, utf16_utf8_strlen(c2));
423         ut_asserteq(9, utf16_utf8_strlen(c3));
424         ut_asserteq(12, utf16_utf8_strlen(c4));
425
426         /* illegal utf-16 word sequences */
427         ut_asserteq(4, utf16_utf8_strlen(i1));
428         ut_asserteq(4, utf16_utf8_strlen(i2));
429         ut_asserteq(3, utf16_utf8_strlen(i3));
430
431         return 0;
432 }
433 UNICODE_TEST(unicode_test_utf16_utf8_strlen);
434
435 static int unicode_test_utf16_utf8_strnlen(struct unit_test_state *uts)
436 {
437         ut_asserteq(3, utf16_utf8_strnlen(c1, 3));
438         ut_asserteq(6, utf16_utf8_strnlen(c1, 13));
439         ut_asserteq(7, utf16_utf8_strnlen(c2, 6));
440         ut_asserteq(6, utf16_utf8_strnlen(c3, 2));
441         ut_asserteq(8, utf16_utf8_strnlen(c4, 2));
442         ut_asserteq(12, utf16_utf8_strnlen(c4, 3));
443         return 0;
444 }
445 UNICODE_TEST(unicode_test_utf16_utf8_strnlen);
446
447 static int unicode_test_utf16_utf8_strcpy(struct unit_test_state *uts)
448 {
449         char buf[16];
450         char *pos;
451
452         pos = buf;
453         utf16_utf8_strcpy(&pos, c1);
454         ut_asserteq(6, pos - buf);
455         ut_asserteq_str(d1, buf);
456
457         pos = buf;
458         utf16_utf8_strcpy(&pos, c2);
459         ut_asserteq(9, pos - buf);
460         ut_asserteq_str(d2, buf);
461
462         pos = buf;
463         utf16_utf8_strcpy(&pos, c3);
464         ut_asserteq(9, pos - buf);
465         ut_asserteq_str(d3, buf);
466
467         pos = buf;
468         utf16_utf8_strcpy(&pos, c4);
469         ut_asserteq(12, pos - buf);
470         ut_asserteq_str(d4, buf);
471
472         /* Illegal utf-16 strings */
473         pos = buf;
474         utf16_utf8_strcpy(&pos, i1);
475         ut_asserteq(4, pos - buf);
476         ut_asserteq_str("i1?l", buf);
477
478         pos = buf;
479         utf16_utf8_strcpy(&pos, i2);
480         ut_asserteq(4, pos - buf);
481         ut_asserteq_str("i2?l", buf);
482
483         pos = buf;
484         utf16_utf8_strcpy(&pos, i3);
485         ut_asserteq(3, pos - buf);
486         ut_asserteq_str("i3?", buf);
487
488         return 0;
489 }
490 UNICODE_TEST(unicode_test_utf16_utf8_strcpy);
491
492 static int unicode_test_utf16_utf8_strncpy(struct unit_test_state *uts)
493 {
494         char buf[16];
495         char *pos;
496
497         pos = buf;
498         memset(buf, 0, sizeof(buf));
499         utf16_utf8_strncpy(&pos, c1, 4);
500         ut_asserteq(4, pos - buf);
501         ut_assert(!buf[4]);
502         ut_assert(!strncmp(buf, d1, 4));
503
504         pos = buf;
505         memset(buf, 0, sizeof(buf));
506         utf16_utf8_strncpy(&pos, c2, 10);
507         ut_asserteq(9, pos - buf);
508         ut_assert(buf[4]);
509         ut_assert(!strncmp(buf, d2, SIZE_MAX));
510
511         pos = buf;
512         memset(buf, 0, sizeof(buf));
513         utf16_utf8_strncpy(&pos, c3, 2);
514         ut_asserteq(6, pos - buf);
515         ut_assert(!buf[6]);
516         ut_assert(!strncmp(buf, d3, 6));
517
518         pos = buf;
519         memset(buf, 0, sizeof(buf));
520         utf16_utf8_strncpy(&pos, c4, 2);
521         ut_asserteq(8, pos - buf);
522         ut_assert(!buf[8]);
523         ut_assert(!strncmp(buf, d4, 8));
524
525         pos = buf;
526         memset(buf, 0, sizeof(buf));
527         utf16_utf8_strncpy(&pos, c4, 10);
528         ut_asserteq(12, pos - buf);
529         ut_assert(buf[5]);
530         ut_assert(!strncmp(buf, d4, SIZE_MAX));
531
532         return 0;
533 }
534 UNICODE_TEST(unicode_test_utf16_utf8_strncpy);
535
536 static int unicode_test_utf_to_lower(struct unit_test_state *uts)
537 {
538         ut_asserteq('@', utf_to_lower('@'));
539         ut_asserteq('a', utf_to_lower('A'));
540         ut_asserteq('z', utf_to_lower('Z'));
541         ut_asserteq('[', utf_to_lower('['));
542         ut_asserteq('m', utf_to_lower('m'));
543         /* Latin letter O with diaresis (umlaut) */
544         ut_asserteq(0x00f6, utf_to_lower(0x00d6));
545 #ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
546         /* Cyrillic letter I*/
547         ut_asserteq(0x0438, utf_to_lower(0x0418));
548 #endif
549         return 0;
550 }
551 UNICODE_TEST(unicode_test_utf_to_lower);
552
553 static int unicode_test_utf_to_upper(struct unit_test_state *uts)
554 {
555         ut_asserteq('`', utf_to_upper('`'));
556         ut_asserteq('A', utf_to_upper('a'));
557         ut_asserteq('Z', utf_to_upper('z'));
558         ut_asserteq('{', utf_to_upper('{'));
559         ut_asserteq('M', utf_to_upper('M'));
560         /* Latin letter O with diaresis (umlaut) */
561         ut_asserteq(0x00d6, utf_to_upper(0x00f6));
562 #ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
563         /* Cyrillic letter I */
564         ut_asserteq(0x0418, utf_to_upper(0x0438));
565 #endif
566         return 0;
567 }
568 UNICODE_TEST(unicode_test_utf_to_upper);
569
570 int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
571 {
572         struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test);
573         const int n_ents = ll_entry_count(struct unit_test, unicode_test);
574
575         return cmd_ut_category("Unicode", tests, n_ents, argc, argv);
576 }