1 /* Test c16rtomb handling of surrogate pairs (DR#488, bug 23794).
2    Copyright (C) 2018-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <locale.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <uchar.h>
24 #include <wchar.h>
25 #include <array_length.h>
26 #include <support/check.h>
27 
28 static int
do_test(void)29 do_test (void)
30 {
31   TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL);
32   /* Test conversions of surrogate pairs.  */
33   for (char32_t c = 0x10000; c <= 0x10ffff; c += 0x123)
34     {
35       char32_t c_pos = c - 0x10000;
36       char16_t c_hi = (c_pos >> 10) + 0xd800;
37       char16_t c_lo = (c_pos & 0x3ff) + 0xdc00;
38       printf ("testing U+0x%08x (0x%x 0x%x)\n",
39 	      (unsigned int) c, (unsigned int) c_hi, (unsigned int) c_lo);
40       char buf[16] = { 0 };
41       size_t ret_hi = c16rtomb (buf, c_hi, NULL);
42       TEST_COMPARE (ret_hi, 0);
43       size_t ret_lo = c16rtomb (buf, c_lo, NULL);
44       TEST_COMPARE (ret_lo, 4);
45       wchar_t wc = 0;
46       size_t ret_wc = mbrtowc (&wc, buf, 4, NULL);
47       TEST_COMPARE (ret_wc, 4);
48       TEST_COMPARE (wc, (wchar_t) c);
49     }
50   /* Test errors for invalid conversions.  */
51   static const char16_t err_cases[][2] =
52     {
53       /* High surrogate followed by non-surrogate.  */
54       { 0xd800, 0x1 },
55       /* High surrogate followed by another high surrogate.  */
56       { 0xd800, 0xd800 },
57       /* Low surrogate not following high surrogate.  */
58       { 0xdc00, 0 }
59     };
60   for (size_t i = 0; i < array_length (err_cases); i++)
61     {
62       char16_t c_hi = err_cases[i][0];
63       char16_t c_lo = err_cases[i][1];
64       printf ("testing error case: 0x%x 0x%x\n", (unsigned int) c_hi,
65 	      (unsigned int) c_lo);
66       c16rtomb (NULL, 0, NULL);
67       char buf[16] = { 0 };
68       errno = 0;
69       size_t ret_hi = c16rtomb (buf, c_hi, NULL);
70       if (c_lo == 0)
71 	{
72 	  /* Unmatched low surrogate in first place.  */
73 	  TEST_COMPARE (ret_hi, (size_t) -1);
74 	  TEST_COMPARE (errno, EILSEQ);
75 	}
76       else
77 	{
78 	  /* High surrogate; error in second place.  */
79 	  TEST_COMPARE (ret_hi, 0);
80 	  errno = 0;
81 	  size_t ret_lo = c16rtomb (buf, c_lo, NULL);
82 	  TEST_COMPARE (ret_lo, (size_t) -1);
83 	  TEST_COMPARE (errno, EILSEQ);
84 	}
85     }
86   return 0;
87 }
88 
89 #include <support/test-driver.c>
90