1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2020 Robert Mustacchi
14 */
15
16 /*
17 * Test the implementation of various pieces of uchar.h(3HEAD) functionality.
18 */
19
20 #include <locale.h>
21 #include <err.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/sysmacros.h>
25 #include <strings.h>
26 #include <wchar.h>
27 #include <uchar.h>
28 #include <errno.h>
29
30 static const char *uchar_wide = "光";
31 static const char32_t uchar_value = 0x5149;
32 static const char *uchar_hello = "hello";
33
34 static void
update_locale(const char * loc)35 update_locale(const char *loc)
36 {
37 const char *newloc = setlocale(LC_CTYPE, loc);
38 if (newloc == NULL) {
39 err(EXIT_FAILURE, "TEST FAILED: failed to update locale to %s",
40 loc);
41 }
42
43 if (strcmp(newloc, loc) != 0) {
44 errx(EXIT_FAILURE, "TEST FAILED: locale set to %s, but got %s",
45 loc, newloc);
46 }
47 }
48
49 static boolean_t
mbrtoc32_ascii(mbstate_t * mbs)50 mbrtoc32_ascii(mbstate_t *mbs)
51 {
52 char32_t out;
53 size_t len;
54 boolean_t ret = B_TRUE;
55
56 if ((len = mbrtoc32(&out, uchar_hello, 5, mbs)) != 1) {
57 warnx("expected mbrtoc32 to return 1, returned %zu", len);
58 ret = B_FALSE;
59 }
60
61 if (out != 'h') {
62 warnx("got bad char32_t, expected 0x%x, found 0x%x\n", 'h',
63 out);
64 ret = B_FALSE;
65 }
66
67 if ((len = mbrtoc32(&out, uchar_hello + 1, 4, mbs)) != 1) {
68 warnx("expected mbrtoc32 to return 1, returned %zu", len);
69 ret = B_FALSE;
70 }
71
72 if (out != 'e') {
73 warnx("got bad char32_t, expected 0x%x, found 0x%x\n", 'h',
74 out);
75 ret = B_FALSE;
76 }
77
78 return (ret);
79 }
80
81 static boolean_t
mbrtoc32_ascii_internal(void)82 mbrtoc32_ascii_internal(void)
83 {
84 return (mbrtoc32_ascii(NULL));
85 }
86
87 static boolean_t
mbrtoc32_ascii_mbstate(void)88 mbrtoc32_ascii_mbstate(void)
89 {
90 mbstate_t mbs;
91
92 bzero(&mbs, sizeof (mbs));
93 return (mbrtoc32_ascii(&mbs));
94 }
95
96 static boolean_t
mbrtoc32_badseq_utf8(void)97 mbrtoc32_badseq_utf8(void)
98 {
99 mbstate_t mbs;
100 size_t len;
101 char32_t out;
102 boolean_t ret = B_TRUE;
103 char *badstr;
104
105 bzero(&mbs, sizeof (mbs));
106 len = mbrtoc32(&out, "\xa9", 1, &mbs);
107 if (len != (size_t)-1) {
108 warnx("mbrtoc32 returned %zu, not %zu", len, (size_t)-1);
109 ret = B_FALSE;
110 }
111
112 if (errno != EILSEQ) {
113 warnx("found bad errno, expected %d, found %d\n", errno,
114 EILSEQ);
115 ret = B_FALSE;
116 }
117
118 badstr = strdup(uchar_wide);
119 if (badstr == NULL) {
120 warn("failed to duplicate uchar_wide");
121 return (B_FALSE);
122 }
123
124 badstr[1] = '?';
125 bzero(&mbs, sizeof (mbs));
126 len = mbrtoc32(&out, badstr, strlen(badstr), &mbs);
127 free(badstr);
128 if (len != (size_t)-1) {
129 warnx("mbrtoc32 returned %zu, not %zu", len, (size_t)-1);
130 ret = B_FALSE;
131 }
132
133 if (errno != EILSEQ) {
134 warnx("found bad errno, expected %d, found %d\n", errno,
135 EILSEQ);
136 ret = B_FALSE;
137 }
138
139 return (ret);
140 }
141
142 static boolean_t
mbrtoc32_roundtrip(void)143 mbrtoc32_roundtrip(void)
144 {
145 char32_t out;
146 size_t len, clen;
147 mbstate_t mbs;
148 char buf[MB_CUR_MAX];
149 boolean_t ret = B_TRUE;
150
151 bzero(&mbs, sizeof (mbs));
152 len = mbrtoc32(&out, uchar_wide, strlen(uchar_wide), &mbs);
153 if (len != 3) {
154 warnx("mbrtoc32 returned %zu, expected %u", len, 3);
155 ret = B_FALSE;
156 }
157
158 if (out != uchar_value) {
159 warnx("mbrtoc32 converted character to 0x%x not 0x%x",
160 out, uchar_value);
161 ret = B_FALSE;
162 }
163
164 clen = c32rtomb(buf, out, &mbs);
165 if (clen != len) {
166 warnx("c32rtomb returned %d bytes, but we originally used %d",
167 clen, len);
168 ret = B_FALSE;
169 }
170
171 if (strncmp(buf, uchar_wide, len) != 0) {
172 warnx("round trip string comparison failed");
173 ret = B_FALSE;
174 }
175
176 return (ret);
177 }
178
179 static boolean_t
mbrtoc32_partial(void)180 mbrtoc32_partial(void)
181 {
182 char32_t out;
183 size_t len, i;
184 mbstate_t mbs;
185 boolean_t ret = B_TRUE;
186
187 bzero(&mbs, sizeof (mbs));
188 for (i = 0; i < strlen(uchar_wide) - 1; i++) {
189 len = mbrtoc32(&out, uchar_wide + i, 1, &mbs);
190 if (len != (size_t)-2) {
191 warnx("partial mbrtoc32 returned %zu, not -2", len);
192 ret = B_FALSE;
193 }
194 }
195
196 len = mbrtoc32(&out, uchar_wide + i, 1, &mbs);
197 if (len != 1) {
198 warnx("partial mbrtoc32 returned %zu, not 1", len);
199 ret = B_FALSE;
200 }
201
202 if (out != uchar_value) {
203 warnx("mbrtoc32 converted character to 0x%x not 0x%x",
204 out, uchar_value);
205 ret = B_FALSE;
206 }
207
208 return (ret);
209 }
210
211 static boolean_t
mbrtoc32_zero(void)212 mbrtoc32_zero(void)
213 {
214 char32_t out, exp = L'\0';
215 size_t len;
216 mbstate_t mbs;
217 boolean_t ret = B_TRUE;
218
219 bzero(&mbs, sizeof (mbs));
220 len = mbrtoc32(&out, "", 1, &mbs);
221 if (len != 0) {
222 warnx("partial mbrtoc32 returned %zu, not 0", len);
223 ret = B_FALSE;
224 }
225
226 if (out != exp) {
227 warnx("mbrtoc32 converted character to 0x%x not 0x%x",
228 out, exp);
229 ret = B_FALSE;
230 }
231
232 return (ret);
233 }
234
235 static boolean_t
mbrtoc32_zero_len(void)236 mbrtoc32_zero_len(void)
237 {
238 char32_t out = 0x12345, exp = 0x12345;
239 size_t len;
240 mbstate_t mbs;
241 boolean_t ret = B_TRUE;
242
243 bzero(&mbs, sizeof (mbs));
244 len = mbrtoc32(&out, uchar_wide, 0, &mbs);
245 if (len != (size_t)-2) {
246 warnx("partial mbrtoc32 returned %zu, not -2", len);
247 ret = B_FALSE;
248 }
249
250 if (out != exp) {
251 warnx("mbrtoc32 incorrectly wrote to char32_t value with "
252 "zero string, found 0x%x not 0x%x", out, exp);
253 ret = B_FALSE;
254 }
255
256 return (ret);
257 }
258
259 static boolean_t
mbrtoc32_null(void)260 mbrtoc32_null(void)
261 {
262 char32_t out = 0x123456, exp = 0x123456;
263 size_t len;
264 mbstate_t mbs;
265 boolean_t ret = B_TRUE;
266
267 bzero(&mbs, sizeof (mbs));
268 len = mbrtoc32(&out, NULL, 1, &mbs);
269 if (len != 0) {
270 warnx("partial mbrtoc32 returned %zu, not 0", len);
271 ret = B_FALSE;
272 }
273
274 if (out != exp) {
275 warnx("mbrtoc32 incorrectly wrote to char32_t value with "
276 "null string, found 0x%x not 0x%x", out, exp);
277 ret = B_FALSE;
278 }
279
280 return (ret);
281 }
282
283 static boolean_t
mbrtoc16_ascii(mbstate_t * mbs)284 mbrtoc16_ascii(mbstate_t *mbs)
285 {
286 char16_t out;
287 size_t len;
288 boolean_t ret = B_TRUE;
289
290 if ((len = mbrtoc16(&out, uchar_hello, 5, mbs)) != 1) {
291 warnx("expected mbrtoc16 to return 1, returned %zu", len);
292 ret = B_FALSE;
293 }
294
295 if (out != 'h') {
296 warnx("got bad char16_t, expected 0x%x, found 0x%x\n", 'h',
297 out);
298 ret = B_FALSE;
299 }
300
301 if ((len = mbrtoc16(&out, uchar_hello + 1, 4, mbs)) != 1) {
302 warnx("expected mbrtoc16 to return 1, returned %zu", len);
303 ret = B_FALSE;
304 }
305
306 if (out != 'e') {
307 warnx("got bad char16_t, expected 0x%x, found 0x%x\n", 'h',
308 out);
309 ret = B_FALSE;
310 }
311
312 return (ret);
313 }
314
315 static boolean_t
mbrtoc16_ascii_internal(void)316 mbrtoc16_ascii_internal(void)
317 {
318 return (mbrtoc16_ascii(NULL));
319 }
320
321 static boolean_t
mbrtoc16_ascii_mbstate(void)322 mbrtoc16_ascii_mbstate(void)
323 {
324 mbstate_t mbs;
325
326 bzero(&mbs, sizeof (mbs));
327 return (mbrtoc16_ascii(&mbs));
328 }
329
330 static boolean_t
mbrtoc16_null(void)331 mbrtoc16_null(void)
332 {
333 char16_t out = 0x1234, exp = 0x1234;
334 size_t len;
335 mbstate_t mbs;
336 boolean_t ret = B_TRUE;
337
338 bzero(&mbs, sizeof (mbs));
339 len = mbrtoc16(&out, NULL, 1, &mbs);
340 if (len != 0) {
341 warnx("partial mbrtoc16 returned %zu, not 0", len);
342 ret = B_FALSE;
343 }
344
345 if (out != exp) {
346 warnx("mbrtoc16 incorrectly wrote to char16_t value with "
347 "null string, found 0x%x not 0x%x", out, exp);
348 ret = B_FALSE;
349 }
350
351 return (ret);
352 }
353
354 static boolean_t
mbrtoc16_zero(void)355 mbrtoc16_zero(void)
356 {
357 char16_t out, exp = L'\0';
358 size_t len;
359 mbstate_t mbs;
360 boolean_t ret = B_TRUE;
361
362 bzero(&mbs, sizeof (mbs));
363 len = mbrtoc16(&out, "", 1, &mbs);
364 if (len != 0) {
365 warnx("partial mbrtoc16 returned %zu, not 0", len);
366 ret = B_FALSE;
367 }
368
369 if (out != exp) {
370 warnx("mbrtoc16 converted character to 0x%x not 0x%x",
371 out, exp);
372 ret = B_FALSE;
373 }
374
375 return (ret);
376 }
377
378 static boolean_t
mbrtoc16_zero_len(void)379 mbrtoc16_zero_len(void)
380 {
381 char16_t out = 0x5432, exp = 0x5432;
382 size_t len;
383 mbstate_t mbs;
384 boolean_t ret = B_TRUE;
385
386 bzero(&mbs, sizeof (mbs));
387 len = mbrtoc16(&out, uchar_wide, 0, &mbs);
388 if (len != (size_t)-2) {
389 warnx("partial mbrtoc16 returned %zu, not -2", len);
390 ret = B_FALSE;
391 }
392
393 if (out != exp) {
394 warnx("mbrtoc16 incorrectly wrote to char16_t value with "
395 "zero length string, found 0x%x not 0x%x", out, exp);
396 ret = B_FALSE;
397 }
398
399 return (ret);
400 }
401
402 static boolean_t
mbrtoc16_roundtrip(void)403 mbrtoc16_roundtrip(void)
404 {
405 char16_t out;
406 size_t len, clen;
407 mbstate_t mbs;
408 char buf[MB_CUR_MAX];
409 boolean_t ret = B_TRUE;
410
411 bzero(&mbs, sizeof (mbs));
412 len = mbrtoc16(&out, uchar_wide, strlen(uchar_wide), &mbs);
413 if (len != 3) {
414 warnx("mbrtoc16 returned %zu, expected %u", len, 3);
415 ret = B_FALSE;
416 }
417
418 if (out != uchar_value) {
419 warnx("mbrtoc16 converted character to 0x%x not 0x%x",
420 out, uchar_value);
421 ret = B_FALSE;
422 }
423
424 clen = c16rtomb(buf, out, &mbs);
425 if (clen != len) {
426 warnx("c16rtomb returned %d bytes, but we originally used %d",
427 clen, len);
428 ret = B_FALSE;
429 }
430
431 if (strncmp(buf, uchar_wide, len) != 0) {
432 warnx("round trip string comparison failed");
433 ret = B_FALSE;
434 }
435
436 return (ret);
437 }
438
439 static boolean_t
mbrtoc16_partial(void)440 mbrtoc16_partial(void)
441 {
442 char16_t out;
443 size_t len, i;
444 mbstate_t mbs;
445 boolean_t ret = B_TRUE;
446
447 bzero(&mbs, sizeof (mbs));
448 for (i = 0; i < strlen(uchar_wide) - 1; i++) {
449 len = mbrtoc16(&out, uchar_wide + i, 1, &mbs);
450 if (len != (size_t)-2) {
451 warnx("partial mbrtoc16 returned %zu, not -2", len);
452 ret = B_FALSE;
453 }
454 }
455
456 len = mbrtoc16(&out, uchar_wide + i, 1, &mbs);
457 if (len != 1) {
458 warnx("partial mbrtoc16 returned %zu, not 1", len);
459 ret = B_FALSE;
460 }
461
462 if (out != uchar_value) {
463 warnx("mbrtoc16 converted character to 0x%x not 0x%x",
464 out, uchar_value);
465 ret = B_FALSE;
466 }
467
468 return (ret);
469 }
470
471 static boolean_t
mbrtoc16_surrogate(void)472 mbrtoc16_surrogate(void)
473 {
474 char16_t out0, out1;
475 size_t len, clen;
476 mbstate_t mbs;
477 const char *surrogate = "\xF0\x9F\x92\xA9";
478 char16_t exp0 = 0xd83d, exp1 = 0xdca9;
479 size_t slen = strlen(surrogate);
480 boolean_t ret = B_TRUE;
481 char buf[MB_CUR_MAX];
482
483 bzero(&mbs, sizeof (mbs));
484 len = mbrtoc16(&out0, surrogate, slen, &mbs);
485 if (len != slen) {
486 warnx("mbrtoc16 returned %zu, expected %u", len, slen);
487 ret = B_FALSE;
488 }
489
490 if (out0 != exp0) {
491 warnx("mbrtoc16 converted character to 0x%x not 0x%x",
492 out0, exp0);
493 ret = B_FALSE;
494 }
495
496 if (mbsinit(&mbs) != 0) {
497 warnx("mb state with a surrogate character is somehow in the "
498 "initial state");
499 ret = B_FALSE;
500 }
501
502 len = mbrtoc16(&out1, uchar_wide, strlen(uchar_wide), &mbs);
503 if (len != (size_t)-3) {
504 warnx("mbrtoc16 returned %zu, expected -3", len);
505 ret = B_FALSE;
506 }
507
508 if (mbsinit(&mbs) == 0) {
509 warnx("mb state with after both surrogate characters isn't "
510 "in initial state");
511 ret = B_FALSE;
512 }
513
514 if (out1 != exp1) {
515 warnx("mbrtoc32 converted character to 0x%x not 0x%x",
516 out1, exp1);
517 ret = B_FALSE;
518 }
519
520 clen = c16rtomb(buf, out0, &mbs);
521 if (clen != 0) {
522 warnx("c16rtomb returned %d bytes, but expected zero for the "
523 "first surrogate", clen);
524 ret = B_FALSE;
525 }
526
527 if (mbsinit(&mbs) != 0) {
528 warnx("mb state with a surrogate character is somehow in the "
529 "initial state");
530 ret = B_FALSE;
531 }
532
533 clen = c16rtomb(buf, out1, &mbs);
534 if (clen != slen) {
535 warnx("c16rtomb returned %zd, expected %u", len, slen);
536 ret = B_FALSE;
537 }
538
539 if (mbsinit(&mbs) == 0) {
540 warnx("mb state with after both surrogate characters isn't "
541 "in initial state");
542 ret = B_FALSE;
543 }
544
545 if (strncmp(buf, surrogate, slen) != 0) {
546 warnx("round trip string comparison failed");
547 ret = B_FALSE;
548 }
549
550 return (ret);
551 }
552
553 static boolean_t
c32rtomb_eilseq_iso8859(void)554 c32rtomb_eilseq_iso8859(void)
555 {
556 char buf[MB_CUR_MAX];
557 mbstate_t mbs;
558 size_t len;
559 boolean_t ret = B_TRUE;
560
561 bzero(&mbs, sizeof (mbs));
562 len = c32rtomb(buf, uchar_value, &mbs);
563 if (len != (size_t)-1) {
564 warnx("c32rtomb returned %zd, expected -1\n", len);
565 ret = B_FALSE;
566 }
567
568 if (errno != EILSEQ) {
569 warnx("expected errno set to %d was %d", EILSEQ, errno);
570 ret = B_FALSE;
571 }
572
573 return (ret);
574 }
575
576 static boolean_t
c16rtomb_eilseq_iso8859(void)577 c16rtomb_eilseq_iso8859(void)
578 {
579 char buf[MB_CUR_MAX];
580 mbstate_t mbs;
581 size_t len;
582 boolean_t ret = B_TRUE;
583
584 bzero(&mbs, sizeof (mbs));
585 len = c32rtomb(buf, (char16_t)uchar_value, &mbs);
586 if (len != (size_t)-1) {
587 warnx("c32rtomb returned %zd, expected -1\n", len);
588 ret = B_FALSE;
589 }
590
591 if (errno != EILSEQ) {
592 warnx("expected errno set to %d was %d", EILSEQ, errno);
593 ret = B_FALSE;
594 }
595
596 return (ret);
597 }
598
599 static boolean_t
c32rtomb_eilseq_utf8(void)600 c32rtomb_eilseq_utf8(void)
601 {
602 char buf[MB_CUR_MAX];
603 mbstate_t mbs;
604 size_t len;
605 boolean_t ret = B_TRUE;
606
607 bzero(&mbs, sizeof (mbs));
608 len = c32rtomb(buf, UINT32_MAX, &mbs);
609 if (len != (size_t)-1) {
610 warnx("c32rtomb returned %zd, expected -1\n", len);
611 ret = B_FALSE;
612 }
613
614 if (errno != EILSEQ) {
615 warnx("expected errno set to %d was %d", EILSEQ, errno);
616 ret = B_FALSE;
617 }
618
619 return (ret);
620 }
621
622 static boolean_t
c16rtomb_bad_first(void)623 c16rtomb_bad_first(void)
624 {
625 char buf[MB_CUR_MAX];
626 mbstate_t mbs;
627 size_t len, i;
628 char16_t first = 0xd83d;
629 char16_t bad[] = { 0x0, 0xd7ff, 0xd83d, 0xd900, 0xffff };
630 boolean_t ret = B_TRUE;
631
632 for (i = 0; i < ARRAY_SIZE(bad); i++) {
633 bzero(&mbs, sizeof (mbs));
634 len = c16rtomb(buf, first, &mbs);
635 if (len != 0) {
636 warnx("c16rtomb returned %zd, expected 0\n", len);
637 ret = B_FALSE;
638 }
639
640 len = c16rtomb(buf, bad[i], &mbs);
641 if (len != (size_t)-1) {
642 warnx("c16rtomb surrogate %x returned %zd, expected "
643 "-1\n", bad[i], len);
644 ret = B_FALSE;
645 }
646
647 if (errno != EILSEQ) {
648 warnx("expected errno set to %d was %d", EILSEQ, errno);
649 ret = B_FALSE;
650 }
651 }
652
653 return (ret);
654 }
655
656 static boolean_t
c16rtomb_bad_second(void)657 c16rtomb_bad_second(void)
658 {
659 char buf[MB_CUR_MAX];
660 mbstate_t mbs;
661 size_t len, i;
662 char16_t bad[] = { 0xdc00, 0xdd34, 0xdfff };
663 boolean_t ret = B_TRUE;
664
665 for (i = 0; i < ARRAY_SIZE(bad); i++) {
666 bzero(&mbs, sizeof (mbs));
667 len = c16rtomb(buf, bad[i], &mbs);
668 if (len != (size_t)-1) {
669 warnx("c16rtomb surrogate %x returned %zd, expected "
670 "-1\n", bad[i], len);
671 ret = B_FALSE;
672 }
673
674 if (errno != EILSEQ) {
675 warnx("expected errno set to %d was %d", EILSEQ, errno);
676 ret = B_FALSE;
677 }
678 }
679
680 return (ret);
681 }
682
683 static boolean_t
c32rtomb_null(void)684 c32rtomb_null(void)
685 {
686 size_t len;
687 mbstate_t mbs;
688 boolean_t ret = B_TRUE;
689
690 bzero(&mbs, sizeof (mbs));
691 len = c32rtomb(NULL, uchar_value, &mbs);
692 if (len != 1) {
693 warnx("c32rtomb returned %zd, expected %zd", len, 1);
694 ret = B_FALSE;
695 }
696
697 return (ret);
698 }
699
700 static boolean_t
c16rtomb_null(void)701 c16rtomb_null(void)
702 {
703 size_t len;
704 mbstate_t mbs;
705 boolean_t ret = B_TRUE;
706
707 bzero(&mbs, sizeof (mbs));
708 len = c16rtomb(NULL, uchar_value, &mbs);
709 if (len != 1) {
710 warnx("c16rtomb returned %zd, expected %zd", len, 1);
711 ret = B_FALSE;
712 }
713
714 return (ret);
715 }
716
717 typedef boolean_t (*uchar_test_f)(void);
718
719 typedef struct uchar_test {
720 uchar_test_f ut_func;
721 const char *ut_test;
722 const char *ut_locale;
723 } uchar_test_t;
724
725 static const uchar_test_t uchar_tests[] = {
726 { mbrtoc32_ascii_mbstate, "mbrtoc32: ascii conversion" },
727 { mbrtoc32_ascii_internal, "mbrtoc32: ascii conversion (internal "
728 "mbstate_t)" },
729 { mbrtoc32_badseq_utf8, "mbrtoc32: bad locale sequence (UTF-8)" },
730 { mbrtoc32_roundtrip, "mbrtoc32: round trip conversion" },
731 { mbrtoc32_partial, "mbrtoc32: correctly consume partial sequences" },
732 { mbrtoc32_zero, "mbrtoc32: correctly handle L'\\0'" },
733 { mbrtoc32_zero_len, "mbrtoc32: correctly handle length of zero" },
734 { mbrtoc32_null, "mbrtoc32: correctly handle null string" },
735 { mbrtoc16_ascii_mbstate, "mbrtoc16: ascii conversion" },
736 { mbrtoc16_ascii_internal, "mbrtoc16: ascii conversion (internal "
737 "mbstate_t)" },
738 { mbrtoc16_null, "mbrtoc16: correctly handle null string" },
739 { mbrtoc16_zero, "mbrtoc16: correctly handle L'\\0'" },
740 { mbrtoc16_zero_len, "mbrtoc16: correctly handle length of zero" },
741 { mbrtoc16_roundtrip, "mbrtoc16: round trip conversion" },
742 { mbrtoc16_partial, "mbrtoc16: correctly consume partial sequences" },
743 { mbrtoc16_surrogate, "mbrtoc16: correctly generate surrogate pairs "
744 "and round trip conversion" },
745 { c32rtomb_eilseq_iso8859, "c32rtomb: character outside of locale is "
746 "caught", "en_US.ISO8859-1" },
747 { c16rtomb_eilseq_iso8859, "c16rtomb: character outside of locale is "
748 "caught", "en_US.ISO8859-1" },
749 { c32rtomb_eilseq_utf8, "c32rtomb: character outside of locale is "
750 "caught" },
751 { c16rtomb_bad_first, "c16rtomb: bad first surrogate pair" },
752 { c16rtomb_bad_second, "c16rtomb: bad second surrogate pair" },
753 { c32rtomb_null, "c32rtomb: correctly handle null buffer" },
754 { c16rtomb_null, "c16rtomb: correctly handle null buffer" },
755 };
756
757 int
main(void)758 main(void)
759 {
760 uint_t i;
761 uint_t passes = 0;
762 uint_t ntests = ARRAY_SIZE(uchar_tests);
763
764 for (i = 0; i < ntests; i++) {
765 boolean_t r;
766
767 /*
768 * Default to a standard UTF-8 locale if none is requested by
769 * the test.
770 */
771 if (uchar_tests[i].ut_locale != NULL) {
772 update_locale(uchar_tests[i].ut_locale);
773 } else {
774 update_locale("en_US.UTF-8");
775 }
776
777 r = uchar_tests[i].ut_func();
778 (void) fprintf(stderr, "TEST %s: %s\n", r ? "PASSED" : "FAILED",
779 uchar_tests[i].ut_test);
780 if (r) {
781 passes++;
782 }
783 }
784
785 (void) printf("%d/%d test%s passed\n", passes, ntests,
786 passes > 1 ? "s" : "");
787 return (passes == ntests ? EXIT_SUCCESS : EXIT_FAILURE);
788
789 }
790