Use spaces for indentation, not tabs.
[gnulib.git] / tests / uninorm / test-u8-nfkd.c
1 /* Test of compatibility decomposition 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_NFKD, 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_NFKD, 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_NFKD, input, input_length, preallocated, &length);
89     if (!(result != NULL))
90       return 8;
91     if (!(preallocated == NULL || 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_nfkd (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 expected[] = { 0x41, 0xCC, 0x88 };
117     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
118   }
119
120   { /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON */
121     static const uint8_t input[]    = { 0xC7, 0x9E };
122     static const uint8_t expected[] = { 0x41, 0xCC, 0x88, 0xCC, 0x84 };
123     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
124   }
125
126   { /* GREEK DIALYTIKA AND PERISPOMENI */
127     static const uint8_t input[]    = { 0xE1, 0xBF, 0x81 };
128     static const uint8_t expected[] = { 0x20, 0xCC, 0x88, 0xCD, 0x82 };
129     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
130   }
131
132   { /* SCRIPT SMALL L */
133     static const uint8_t input[]    = { 0xE2, 0x84, 0x93 };
134     static const uint8_t expected[] = { 0x6C };
135     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
136   }
137
138   { /* NO-BREAK SPACE */
139     static const uint8_t input[]    = { 0xC2, 0xA0 };
140     static const uint8_t expected[] = { 0x20 };
141     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
142   }
143
144   { /* ARABIC LETTER VEH INITIAL FORM */
145     static const uint8_t input[]    = { 0xEF, 0xAD, 0xAC };
146     static const uint8_t expected[] = { 0xDA, 0xA4 };
147     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
148   }
149
150   { /* ARABIC LETTER VEH MEDIAL FORM */
151     static const uint8_t input[]    = { 0xEF, 0xAD, 0xAD };
152     static const uint8_t expected[] = { 0xDA, 0xA4 };
153     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
154   }
155
156   { /* ARABIC LETTER VEH FINAL FORM */
157     static const uint8_t input[]    = { 0xEF, 0xAD, 0xAB };
158     static const uint8_t expected[] = { 0xDA, 0xA4 };
159     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
160   }
161
162   { /* ARABIC LETTER VEH ISOLATED FORM */
163     static const uint8_t input[]    = { 0xEF, 0xAD, 0xAA };
164     static const uint8_t expected[] = { 0xDA, 0xA4 };
165     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
166   }
167
168   { /* CIRCLED NUMBER FIFTEEN */
169     static const uint8_t input[]    = { 0xE2, 0x91, 0xAE };
170     static const uint8_t expected[] = { 0x31, 0x35 };
171     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
172   }
173
174   { /* TRADE MARK SIGN */
175     static const uint8_t input[]    = { 0xE2, 0x84, 0xA2 };
176     static const uint8_t expected[] = { 0x54, 0x4D };
177     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
178   }
179
180   { /* LATIN SUBSCRIPT SMALL LETTER I */
181     static const uint8_t input[]    = { 0xE1, 0xB5, 0xA2 };
182     static const uint8_t expected[] = { 0x69 };
183     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
184   }
185
186   { /* PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS */
187     static const uint8_t input[]    = { 0xEF, 0xB8, 0xB5 };
188     static const uint8_t expected[] = { 0x28 };
189     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
190   }
191
192   { /* FULLWIDTH LATIN CAPITAL LETTER A */
193     static const uint8_t input[]    = { 0xEF, 0xBC, 0xA1 };
194     static const uint8_t expected[] = { 0x41 };
195     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
196   }
197
198   { /* HALFWIDTH IDEOGRAPHIC COMMA */
199     static const uint8_t input[]    = { 0xEF, 0xBD, 0xA4 };
200     static const uint8_t expected[] = { 0xE3, 0x80, 0x81 };
201     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
202   }
203
204   { /* SMALL IDEOGRAPHIC COMMA */
205     static const uint8_t input[]    = { 0xEF, 0xB9, 0x91 };
206     static const uint8_t expected[] = { 0xE3, 0x80, 0x81 };
207     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
208   }
209
210   { /* SQUARE MHZ */
211     static const uint8_t input[]    = { 0xE3, 0x8E, 0x92 };
212     static const uint8_t expected[] = { 0x4D, 0x48, 0x7A };
213     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
214   }
215
216   { /* VULGAR FRACTION THREE EIGHTHS */
217     static const uint8_t input[]    = { 0xE2, 0x85, 0x9C };
218     static const uint8_t expected[] = { 0x33, 0xE2, 0x81, 0x84, 0x38 };
219     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
220   }
221
222   { /* MICRO SIGN */
223     static const uint8_t input[]    = { 0xC2, 0xB5 };
224     static const uint8_t expected[] = { 0xCE, 0xBC };
225     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
226   }
227
228   { /* ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM */
229     static const uint8_t input[]    = { 0xEF, 0xB7, 0xBA };
230     static const uint8_t expected[] =
231       { 0xD8, 0xB5, 0xD9, 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, 0x84, 0xD9,
232         0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, 0xD9, 0x84, 0xD9, 0x8A, 0xD9, 0x87,
233         0x20, 0xD9, 0x88, 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85
234       };
235     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
236   }
237
238   { /* HANGUL SYLLABLE GEUL */
239     static const uint8_t input[]    = { 0xEA, 0xB8, 0x80 };
240     static const uint8_t expected[] =
241       { 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xB3, 0xE1, 0x86, 0xAF };
242     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
243   }
244
245   { /* HANGUL SYLLABLE GEU */
246     static const uint8_t input[]    = { 0xEA, 0xB7, 0xB8 };
247     static const uint8_t expected[] = { 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xB3 };
248     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
249   }
250
251   { /* "Grüß Gott. Здравствуйте! x=(-b±sqrt(b²-4ac))/(2a)  日本語,中文,한글" */
252     static const uint8_t input[] =
253       { 'G', 'r', 0xC3, 0xBC, 0xC3, 0x9F, ' ', 'G', 'o', 't', 't', '.',
254         ' ', 0xD0, 0x97, 0xD0, 0xB4, 0xD1, 0x80, 0xD0, 0xB0, 0xD0, 0xB2, 0xD1,
255         0x81, 0xD1, 0x82, 0xD0, 0xB2, 0xD1, 0x83, 0xD0, 0xB9,
256         0xD1, 0x82, 0xD0, 0xB5, '!', ' ', 'x', '=', '(', '-', 'b', 0xC2, 0xB1,
257         's', 'q', 'r', 't', '(', 'b', 0xC2, 0xB2, '-', '4', 'a', 'c', ')', ')',
258         '/', '(', '2', 'a', ')', ' ', ' ', 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC,
259         0xE8, 0xAA, 0x9E, ',', 0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, ',',
260         0xED, 0x95, 0x9C,
261         0xEA, 0xB8, 0x80, '\n'
262       };
263     static const uint8_t expected[] =
264       { 'G', 'r', 0x75, 0xCC, 0x88, 0xC3, 0x9F, ' ', 'G', 'o', 't', 't', '.',
265         ' ', 0xD0, 0x97, 0xD0, 0xB4, 0xD1, 0x80, 0xD0, 0xB0, 0xD0, 0xB2, 0xD1,
266         0x81, 0xD1, 0x82, 0xD0, 0xB2, 0xD1, 0x83, 0xD0, 0xB8, 0xCC, 0x86,
267         0xD1, 0x82, 0xD0, 0xB5, '!', ' ', 'x', '=', '(', '-', 'b', 0xC2, 0xB1,
268         's', 'q', 'r', 't', '(', 'b', 0x32, '-', '4', 'a', 'c', ')', ')',
269         '/', '(', '2', 'a', ')', ' ', ' ', 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC,
270         0xE8, 0xAA, 0x9E, ',', 0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, ',',
271         0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0xE1, 0x86, 0xAB,
272         0xE1, 0x84, 0x80, 0xE1, 0x85, 0xB3, 0xE1, 0x86, 0xAF, '\n'
273       };
274     ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0);
275   }
276
277 #if HAVE_DECL_ALARM
278   /* Declare failure if test takes too long, by using default abort
279      caused by SIGALRM.  */
280   signal (SIGALRM, SIG_DFL);
281   alarm (50);
282 #endif
283
284   /* Check that the sorting is not O(n²) but O(n log n).  */
285   {
286     int pass;
287     for (pass = 0; pass < 3; pass++)
288       {
289         size_t repeat = 1;
290         size_t m = 100000;
291         uint8_t *input = (uint8_t *) malloc (2 * (2 * m - 1) * sizeof (uint8_t));
292         if (input != NULL)
293           {
294             uint8_t *expected = input + (2 * m - 1);
295             size_t m1 = m / 2;
296             size_t m2 = (m - 1) / 2;
297             /* NB: m1 + m2 == m - 1.  */
298             uint8_t *p;
299             size_t i;
300
301             input[0] = 0x41;
302             p = input + 1;
303             switch (pass)
304               {
305               case 0:
306                 for (i = 0; i < m1; i++)
307                   {
308                     *p++ = 0xCC;
309                     *p++ = 0x99;
310                   }
311                 for (i = 0; i < m2; i++)
312                   {
313                     *p++ = 0xCC;
314                     *p++ = 0x80;
315                   }
316                 break;
317
318               case 1:
319                 for (i = 0; i < m2; i++)
320                   {
321                     *p++ = 0xCC;
322                     *p++ = 0x80;
323                   }
324                 for (i = 0; i < m1; i++)
325                   {
326                     *p++ = 0xCC;
327                     *p++ = 0x99;
328                   }
329                 break;
330
331               case 2:
332                 for (i = 0; i < m2; i++)
333                   {
334                     *p++ = 0xCC;
335                     *p++ = 0x99;
336                     *p++ = 0xCC;
337                     *p++ = 0x80;
338                   }
339                 for (; i < m1; i++)
340                   {
341                     *p++ = 0xCC;
342                     *p++ = 0x99;
343                   }
344                 break;
345
346               default:
347                 abort ();
348               }
349
350             expected[0] = 0x41;
351             p = expected + 1;
352             for (i = 0; i < m1; i++)
353               {
354                 *p++ = 0xCC;
355                 *p++ = 0x99;
356               }
357             for (i = 0; i < m2; i++)
358               {
359                 *p++ = 0xCC;
360                 *p++ = 0x80;
361               }
362
363             for (; repeat > 0; repeat--)
364               ASSERT (check (input, 2 * m - 1, expected, 2 * m - 1) == 0);
365
366             free (input);
367           }
368       }
369   }
370 }
371
372 #else
373
374 void
375 test_u8_nfkd (void)
376 {
377 }
378
379 #endif