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