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