Handle empty strings correctly.
[gnulib.git] / tests / uninorm / test-u8-nfc.c
1 /* Test of canonical normalization of UTF-8 strings.
2    Copyright (C) 2009 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Bruno Haible <bruno@clisp.org>, 2009.  */
18
19 #include <config.h>
20
21 #if GNULIB_UNINORM_U8_NORMALIZE
22
23 #include "uninorm.h"
24
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29
30 #include "unistr.h"
31
32 #define SIZEOF(array) (sizeof (array) / sizeof (array[0]))
33 #define ASSERT(expr) \
34   do                                                                         \
35     {                                                                        \
36       if (!(expr))                                                           \
37         {                                                                    \
38           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
39           fflush (stderr);                                                   \
40           abort ();                                                          \
41         }                                                                    \
42     }                                                                        \
43   while (0)
44
45 static int
46 check (const uint8_t *input, size_t input_length,
47        const uint8_t *expected, size_t expected_length)
48 {
49   size_t length;
50   uint8_t *result;
51
52   /* Test return conventions with resultbuf == NULL.  */
53   result = u8_normalize (UNINORM_NFC, input, input_length, NULL, &length);
54   if (!(result != NULL))
55     return 1;
56   if (!(length == expected_length))
57     return 2;
58   if (!(u8_cmp (result, expected, expected_length) == 0))
59     return 3;
60   free (result);
61
62   /* Test return conventions with resultbuf too small.  */
63   if (expected_length > 0)
64     {
65       uint8_t *preallocated;
66
67       length = expected_length - 1;
68       preallocated = (uint8_t *) malloc (length * sizeof (uint8_t));
69       result = u8_normalize (UNINORM_NFC, input, input_length, preallocated, &length);
70       if (!(result != NULL))
71         return 4;
72       if (!(result != preallocated))
73         return 5;
74       if (!(length == expected_length))
75         return 6;
76       if (!(u8_cmp (result, expected, expected_length) == 0))
77         return 7;
78       free (result);
79       free (preallocated);
80     }
81
82   /* Test return conventions with resultbuf large enough.  */
83   {
84     uint8_t *preallocated;
85
86     length = expected_length;
87     preallocated = (uint8_t *) malloc (length * sizeof (uint8_t));
88     result = u8_normalize (UNINORM_NFC, input, input_length, preallocated, &length);
89     if (!(result != NULL))
90       return 8;
91     if (!(result == preallocated))
92       return 9;
93     if (!(length == expected_length))
94       return 10;
95     if (!(u8_cmp (result, expected, expected_length) == 0))
96       return 11;
97     free (preallocated);
98   }
99
100   return 0;
101 }
102
103 void
104 test_u8_nfc (void)
105 {
106   { /* Empty string.  */
107     ASSERT (check (NULL, 0, NULL, 0) == 0);
108   }
109   { /* SPACE */
110     static const uint8_t input[]    = { 0x20 };
111     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
112   }
113
114   { /* LATIN CAPITAL LETTER A WITH DIAERESIS */
115     static const uint8_t input[]      = { 0xC3, 0x84 };
116     static const uint8_t decomposed[] = { 0x41, 0xCC, 0x88 };
117     ASSERT (check (input, SIZEOF (input),           input, SIZEOF (input)) == 0);
118     ASSERT (check (decomposed, SIZEOF (decomposed), input, SIZEOF (input)) == 0);
119   }
120
121   { /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON */
122     static const uint8_t input[]      = { 0xC7, 0x9E };
123     static const uint8_t decomposed[] = { 0x41, 0xCC, 0x88, 0xCC, 0x84 };
124     ASSERT (check (input, SIZEOF (input),           input, SIZEOF (input)) == 0);
125     ASSERT (check (decomposed, SIZEOF (decomposed), input, SIZEOF (input)) == 0);
126   }
127
128   { /* ANGSTROM SIGN */
129     static const uint8_t input[]      = { 0xE2, 0x84, 0xAB };
130     static const uint8_t decomposed[] = { 0x41, 0xCC, 0x8A };
131     static const uint8_t expected[]   = { 0xC3, 0x85 };
132     ASSERT (check (input, SIZEOF (input),           expected, SIZEOF (expected)) == 0);
133     ASSERT (check (decomposed, SIZEOF (decomposed), expected, SIZEOF (expected)) == 0);
134     ASSERT (check (expected, SIZEOF (expected),     expected, SIZEOF (expected)) == 0);
135   }
136
137   { /* GREEK DIALYTIKA AND PERISPOMENI */
138     static const uint8_t input[]      = { 0xE1, 0xBF, 0x81 };
139     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
140   }
141
142   { /* SCRIPT SMALL L */
143     static const uint8_t input[]      = { 0xE2, 0x84, 0x93 };
144     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
145   }
146
147   { /* NO-BREAK SPACE */
148     static const uint8_t input[]      = { 0xC2, 0xA0 };
149     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
150   }
151
152   { /* ARABIC LETTER VEH INITIAL FORM */
153     static const uint8_t input[]      = { 0xEF, 0xAD, 0xAC };
154     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
155   }
156
157   { /* ARABIC LETTER VEH MEDIAL FORM */
158     static const uint8_t input[]      = { 0xEF, 0xAD, 0xAD };
159     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
160   }
161
162   { /* ARABIC LETTER VEH FINAL FORM */
163     static const uint8_t input[]      = { 0xEF, 0xAD, 0xAB };
164     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
165   }
166
167   { /* ARABIC LETTER VEH ISOLATED FORM */
168     static const uint8_t input[]      = { 0xEF, 0xAD, 0xAA };
169     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
170   }
171
172   { /* CIRCLED NUMBER FIFTEEN */
173     static const uint8_t input[]      = { 0xE2, 0x91, 0xAE };
174     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
175   }
176
177   { /* TRADE MARK SIGN */
178     static const uint8_t input[]      = { 0xE2, 0x84, 0xA2 };
179     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
180   }
181
182   { /* LATIN SUBSCRIPT SMALL LETTER I */
183     static const uint8_t input[]      = { 0xE1, 0xB5, 0xA2 };
184     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
185   }
186
187   { /* PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS */
188     static const uint8_t input[]      = { 0xEF, 0xB8, 0xB5 };
189     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
190   }
191
192   { /* FULLWIDTH LATIN CAPITAL LETTER A */
193     static const uint8_t input[]      = { 0xEF, 0xBC, 0xA1 };
194     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
195   }
196
197   { /* HALFWIDTH IDEOGRAPHIC COMMA */
198     static const uint8_t input[]      = { 0xEF, 0xBD, 0xA4 };
199     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
200   }
201
202   { /* SMALL IDEOGRAPHIC COMMA */
203     static const uint8_t input[]      = { 0xEF, 0xB9, 0x91 };
204     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
205   }
206
207   { /* SQUARE MHZ */
208     static const uint8_t input[]      = { 0xE3, 0x8E, 0x92 };
209     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
210   }
211
212   { /* VULGAR FRACTION THREE EIGHTHS */
213     static const uint8_t input[]      = { 0xE2, 0x85, 0x9C };
214     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
215   }
216
217   { /* MICRO SIGN */
218     static const uint8_t input[]      = { 0xC2, 0xB5 };
219     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
220   }
221
222   { /* ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM */
223     static const uint8_t input[]      = { 0xEF, 0xB7, 0xBA };
224     ASSERT (check (input, SIZEOF (input), input, SIZEOF (input)) == 0);
225   }
226
227   { /* HANGUL SYLLABLE GEUL */
228     static const uint8_t input[]      = { 0xEA, 0xB8, 0x80 };
229     static const uint8_t decomposed[] =
230       { 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xB3, 0xE1, 0x86, 0xAF };
231     ASSERT (check (input, SIZEOF (input),           input, SIZEOF (input)) == 0);
232     ASSERT (check (decomposed, SIZEOF (decomposed), input, SIZEOF (input)) == 0);
233   }
234
235   { /* HANGUL SYLLABLE GEU */
236     static const uint8_t input[]      = { 0xEA, 0xB7, 0xB8 };
237     static const uint8_t decomposed[] = { 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xB3 };
238     ASSERT (check (input, SIZEOF (input),           input, SIZEOF (input)) == 0);
239     ASSERT (check (decomposed, SIZEOF (decomposed), input, SIZEOF (input)) == 0);
240   }
241
242   { /* "Grüß Gott. Здравствуйте! x=(-b±sqrt(b²-4ac))/(2a)  日本語,中文,한글" */
243     static const uint8_t input[] =
244       { 'G', 'r', 0xC3, 0xBC, 0xC3, 0x9F, ' ', 'G', 'o', 't', 't', '.',
245         ' ', 0xD0, 0x97, 0xD0, 0xB4, 0xD1, 0x80, 0xD0, 0xB0, 0xD0, 0xB2, 0xD1,
246         0x81, 0xD1, 0x82, 0xD0, 0xB2, 0xD1, 0x83, 0xD0, 0xB9,
247         0xD1, 0x82, 0xD0, 0xB5, '!', ' ', 'x', '=', '(', '-', 'b', 0xC2, 0xB1,
248         's', 'q', 'r', 't', '(', 'b', 0xC2, 0xB2, '-', '4', 'a', 'c', ')', ')',
249         '/', '(', '2', 'a', ')', ' ', ' ', 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC,
250         0xE8, 0xAA, 0x9E, ',', 0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, ',',
251         0xED, 0x95, 0x9C,
252         0xEA, 0xB8, 0x80, '\n'
253       };
254     static const uint8_t decomposed[] =
255       { 'G', 'r', 0x75, 0xCC, 0x88, 0xC3, 0x9F, ' ', 'G', 'o', 't', 't', '.',
256         ' ', 0xD0, 0x97, 0xD0, 0xB4, 0xD1, 0x80, 0xD0, 0xB0, 0xD0, 0xB2, 0xD1,
257         0x81, 0xD1, 0x82, 0xD0, 0xB2, 0xD1, 0x83, 0xD0, 0xB8, 0xCC, 0x86,
258         0xD1, 0x82, 0xD0, 0xB5, '!', ' ', 'x', '=', '(', '-', 'b', 0xC2, 0xB1,
259         's', 'q', 'r', 't', '(', 'b', 0xC2, 0xB2, '-', '4', 'a', 'c', ')', ')',
260         '/', '(', '2', 'a', ')', ' ', ' ', 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC,
261         0xE8, 0xAA, 0x9E, ',', 0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, ',',
262         0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0xE1, 0x86, 0xAB,
263         0xE1, 0x84, 0x80, 0xE1, 0x85, 0xB3, 0xE1, 0x86, 0xAF, '\n'
264       };
265     ASSERT (check (input, SIZEOF (input),           input, SIZEOF (input)) == 0);
266     ASSERT (check (decomposed, SIZEOF (decomposed), input, SIZEOF (input)) == 0);
267   }
268
269 #if HAVE_DECL_ALARM
270   /* Declare failure if test takes too long, by using default abort
271      caused by SIGALRM.  */
272   signal (SIGALRM, SIG_DFL);
273   alarm (50);
274 #endif
275
276   /* Check that the sorting is not O(n²) but O(n log n).  */
277   {
278     int pass;
279     for (pass = 0; pass < 3; pass++)
280       {
281         size_t repeat = 1;
282         size_t m = 100000;
283         uint8_t *input = (uint8_t *) malloc (2 * (2 * m - 1) * sizeof (uint8_t));
284         if (input != NULL)
285           {
286             uint8_t *expected = input + (2 * m - 1);
287             size_t m1 = m / 2;
288             size_t m2 = (m - 1) / 2;
289             /* NB: m1 + m2 == m - 1.  */
290             uint8_t *p;
291             size_t i;
292
293             input[0] = 0x41;
294             p = input + 1;
295             switch (pass)
296               {
297               case 0:
298                 for (i = 0; i < m1; i++)
299                   {
300                     *p++ = 0xCC;
301                     *p++ = 0x99;
302                   }
303                 for (i = 0; i < m2; i++)
304                   {
305                     *p++ = 0xCC;
306                     *p++ = 0x80;
307                   }
308                 break;
309
310               case 1:
311                 for (i = 0; i < m2; i++)
312                   {
313                     *p++ = 0xCC;
314                     *p++ = 0x80;
315                   }
316                 for (i = 0; i < m1; i++)
317                   {
318                     *p++ = 0xCC;
319                     *p++ = 0x99;
320                   }
321                 break;
322
323               case 2:
324                 for (i = 0; i < m2; i++)
325                   {
326                     *p++ = 0xCC;
327                     *p++ = 0x99;
328                     *p++ = 0xCC;
329                     *p++ = 0x80;
330                   }
331                 for (; i < m1; i++)
332                   {
333                     *p++ = 0xCC;
334                     *p++ = 0x99;
335                   }
336                 break;
337
338               default:
339                 abort ();
340               }
341
342             expected[0] = 0xC3;
343             expected[1] = 0x80;
344             p = expected + 2;
345             for (i = 0; i < m1; i++)
346               {
347                 *p++ = 0xCC;
348                 *p++ = 0x99;
349               }
350             for (i = 0; i < m2 - 1; i++)
351               {
352                 *p++ = 0xCC;
353                 *p++ = 0x80;
354               }
355
356             for (; repeat > 0; repeat--)
357               {
358                 ASSERT (check (input, 2 * m - 1,    expected, 2 * m - 2) == 0);
359                 ASSERT (check (expected, 2 * m - 2, expected, 2 * m - 2) == 0);
360               }
361
362             free (input);
363           }
364       }
365   }
366 }
367
368 #else
369
370 void
371 test_u8_nfc (void)
372 {
373 }
374
375 #endif