Make roundf-tests module depend on floorf, ceilf.
[gnulib.git] / tests / test-striconveha.c
1 /* Test of character set conversion with error handling and autodetection.
2    Copyright (C) 2007 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>, 2007.  */
18
19 #include <config.h>
20
21 #include "striconveha.h"
22
23 #if HAVE_ICONV
24 # include <iconv.h>
25 #endif
26
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.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           abort ();                                                          \
40         }                                                                    \
41     }                                                                        \
42   while (0)
43
44 /* Magic number for detecting bounds violations.  */
45 #define MAGIC 0x1983EFF1
46
47 static size_t *
48 new_offsets (size_t n)
49 {
50   size_t *offsets = (size_t *) malloc ((n + 1) * sizeof (size_t));
51   offsets[n] = MAGIC;
52   return offsets;
53 }
54
55 int
56 main ()
57 {
58   static enum iconv_ilseq_handler handlers[] =
59     { iconveh_error, iconveh_question_mark, iconveh_escape_sequence };
60   size_t h;
61   size_t o;
62   size_t i;
63
64 #if HAVE_ICONV
65   /* Assume that iconv() supports at least the encodings ASCII, ISO-8859-1,
66      ISO-8859-2, and UTF-8.  */
67
68   /* ------------------------- Test mem_iconveha() ------------------------- */
69
70   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
71   for (h = 0; h < SIZEOF (handlers); h++)
72     {
73       enum iconv_ilseq_handler handler = handlers[h];
74       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
75       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
76       for (o = 0; o < 2; o++)
77         {
78           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
79           char *result = NULL;
80           size_t length = 0;
81           int retval = mem_iconveha (input, strlen (input),
82                                      "ISO-8859-2", "ISO-8859-1",
83                                      false, handler,
84                                      offsets,
85                                      &result, &length);
86           ASSERT (retval == 0);
87           ASSERT (length == strlen (expected));
88           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
89           if (o)
90             {
91               for (i = 0; i < 37; i++)
92                 ASSERT (offsets[i] == i);
93               ASSERT (offsets[37] == MAGIC);
94               free (offsets);
95             }
96           free (result);
97         }
98     }
99
100   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
101   for (h = 0; h < SIZEOF (handlers); h++)
102     {
103       enum iconv_ilseq_handler handler = handlers[h];
104       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
105       for (o = 0; o < 2; o++)
106         {
107           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
108           char *result = NULL;
109           size_t length = 0;
110           int retval = mem_iconveha (input, strlen (input),
111                                      "ISO-8859-2", "ISO-8859-1",
112                                      false, handler,
113                                      offsets,
114                                      &result, &length);
115           switch (handler)
116             {
117             case iconveh_error:
118               ASSERT (retval == -1 && errno == EILSEQ);
119               ASSERT (result == NULL);
120               if (o)
121                 free (offsets);
122               break;
123             case iconveh_question_mark:
124               {
125                 static const char expected[] = "Rafa? Maszkowski";
126                 ASSERT (retval == 0);
127                 ASSERT (length == strlen (expected));
128                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
129                 if (o)
130                   {
131                     for (i = 0; i < 16; i++)
132                       ASSERT (offsets[i] == i);
133                     ASSERT (offsets[16] == MAGIC);
134                     free (offsets);
135                   }
136                 free (result);
137               }
138               break;
139             case iconveh_escape_sequence:
140               {
141                 static const char expected[] = "Rafa\\u0142 Maszkowski";
142                 ASSERT (retval == 0);
143                 ASSERT (length == strlen (expected));
144                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
145                 if (o)
146                   {
147                     for (i = 0; i < 16; i++)
148                       ASSERT (offsets[i] == (i < 5 ? i :
149                                              i + 5));
150                     ASSERT (offsets[16] == MAGIC);
151                     free (offsets);
152                   }
153                 free (result);
154               }
155               break;
156             }
157         }
158     }
159
160   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
161   for (h = 0; h < SIZEOF (handlers); h++)
162     {
163       enum iconv_ilseq_handler handler = handlers[h];
164       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
165       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
166       for (o = 0; o < 2; o++)
167         {
168           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
169           char *result = NULL;
170           size_t length = 0;
171           int retval = mem_iconveha (input, strlen (input),
172                                      "ISO-8859-1", "UTF-8",
173                                      false, handler,
174                                      offsets,
175                                      &result, &length);
176           ASSERT (retval == 0);
177           ASSERT (length == strlen (expected));
178           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
179           if (o)
180             {
181               for (i = 0; i < 37; i++)
182                 ASSERT (offsets[i] == (i < 1 ? i :
183                                        i < 12 ? i + 1 :
184                                        i < 18 ? i + 2 :
185                                        i + 3));
186               ASSERT (offsets[37] == MAGIC);
187               free (offsets);
188             }
189           free (result);
190         }
191     }
192
193   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
194   for (h = 0; h < SIZEOF (handlers); h++)
195     {
196       enum iconv_ilseq_handler handler = handlers[h];
197       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
198       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
199       for (o = 0; o < 2; o++)
200         {
201           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
202           char *result = NULL;
203           size_t length = 0;
204           int retval = mem_iconveha (input, strlen (input),
205                                      "UTF-8", "ISO-8859-1",
206                                      false, handler,
207                                      offsets,
208                                      &result, &length);
209           ASSERT (retval == 0);
210           ASSERT (length == strlen (expected));
211           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
212           if (o)
213             {
214               for (i = 0; i < 41; i++)
215                 ASSERT (offsets[i] == (i < 1 ? i :
216                                        i == 1 ? (size_t)(-1) :
217                                        i < 13 ? i - 1 :
218                                        i == 13 ? (size_t)(-1) :
219                                        i < 20 ? i - 2 :
220                                        i == 20 ? (size_t)(-1) :
221                                        i < 40 ? i - 3 :
222                                        (size_t)(-1)));
223               ASSERT (offsets[41] == MAGIC);
224               free (offsets);
225             }
226           free (result);
227         }
228     }
229
230   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
231   for (h = 0; h < SIZEOF (handlers); h++)
232     {
233       enum iconv_ilseq_handler handler = handlers[h];
234       static const char input[] = "Rafa\305\202 Maszkowski"; /* Rafał Maszkowski */
235       for (o = 0; o < 2; o++)
236         {
237           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
238           char *result = NULL;
239           size_t length = 0;
240           int retval = mem_iconveha (input, strlen (input),
241                                      "UTF-8", "ISO-8859-1",
242                                      false, handler,
243                                      offsets,
244                                      &result, &length);
245           switch (handler)
246             {
247             case iconveh_error:
248               ASSERT (retval == -1 && errno == EILSEQ);
249               ASSERT (result == NULL);
250               if (o)
251                 free (offsets);
252               break;
253             case iconveh_question_mark:
254               {
255                 static const char expected[] = "Rafa? Maszkowski";
256                 ASSERT (retval == 0);
257                 ASSERT (length == strlen (expected));
258                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
259                 if (o)
260                   {
261                     for (i = 0; i < 17; i++)
262                       ASSERT (offsets[i] == (i < 5 ? i :
263                                              i == 5 ? (size_t)(-1) :
264                                              i - 1));
265                     ASSERT (offsets[17] == MAGIC);
266                     free (offsets);
267                   }
268                 free (result);
269               }
270               break;
271             case iconveh_escape_sequence:
272               {
273                 static const char expected[] = "Rafa\\u0142 Maszkowski";
274                 ASSERT (retval == 0);
275                 ASSERT (length == strlen (expected));
276                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
277                 if (o)
278                   {
279                     for (i = 0; i < 17; i++)
280                       ASSERT (offsets[i] == (i < 5 ? i :
281                                              i == 5 ? (size_t)(-1) :
282                                              i + 4));
283                     ASSERT (offsets[17] == MAGIC);
284                     free (offsets);
285                   }
286                 free (result);
287               }
288               break;
289             }
290         }
291     }
292
293   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
294   for (h = 0; h < SIZEOF (handlers); h++)
295     {
296       enum iconv_ilseq_handler handler = handlers[h];
297       static const char input[] = "\342";
298       for (o = 0; o < 2; o++)
299         {
300           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
301           char *result = NULL;
302           size_t length = 0;
303           int retval = mem_iconveha (input, strlen (input),
304                                      "UTF-8", "ISO-8859-1",
305                                      false, handler,
306                                      offsets,
307                                      &result, &length);
308           ASSERT (retval == 0);
309           ASSERT (length == 0);
310           if (o)
311             {
312               ASSERT (offsets[0] == 0);
313               ASSERT (offsets[1] == MAGIC);
314               free (offsets);
315             }
316           if (result != NULL)
317             free (result);
318         }
319     }
320
321   /* autodetect_jp is only supported when iconv() support ISO-2022-JP-2.  */
322 # if defined _LIBICONV_VERSION || !(defined _AIX || defined __sgi || defined __hpux || defined __osf__ || defined __sun)
323   /* Test conversions from autodetect_jp to UTF-8.  */
324   for (h = 0; h < SIZEOF (handlers); h++)
325     {
326       enum iconv_ilseq_handler handler = handlers[h];
327       static const char input[] = "\244\263\244\363\244\313\244\301\244\317"; /* こんにちは in EUC-JP */
328       static const char expected[] = "\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257"; /* こんにちは */
329       for (o = 0; o < 2; o++)
330         {
331           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
332           char *result = NULL;
333           size_t length = 0;
334           int retval = mem_iconveha (input, strlen (input),
335                                      "autodetect_jp", "UTF-8",
336                                      false, handler,
337                                      offsets,
338                                      &result, &length);
339           ASSERT (retval == 0);
340           ASSERT (length == strlen (expected));
341           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
342           if (o)
343             {
344               for (i = 0; i < 10; i++)
345                 ASSERT (offsets[i] == ((i % 2) == 0 ? (i / 2) * 3 : (size_t)(-1)));
346               ASSERT (offsets[10] == MAGIC);
347               free (offsets);
348             }
349           free (result);
350         }
351     }
352   for (h = 0; h < SIZEOF (handlers); h++)
353     {
354       enum iconv_ilseq_handler handler = handlers[h];
355       static const char input[] = "\202\261\202\361\202\311\202\277\202\315"; /* こんにちは in Shift_JIS */
356       static const char expected[] = "\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257"; /* こんにちは */
357       for (o = 0; o < 2; o++)
358         {
359           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
360           char *result = NULL;
361           size_t length = 0;
362           int retval = mem_iconveha (input, strlen (input),
363                                      "autodetect_jp", "UTF-8",
364                                      false, handler,
365                                      offsets,
366                                      &result, &length);
367           ASSERT (retval == 0);
368           ASSERT (length == strlen (expected));
369           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
370           if (o)
371             {
372               for (i = 0; i < 10; i++)
373                 ASSERT (offsets[i] == ((i % 2) == 0 ? (i / 2) * 3 : (size_t)(-1)));
374               ASSERT (offsets[10] == MAGIC);
375               free (offsets);
376             }
377           free (result);
378         }
379     }
380   for (h = 0; h < SIZEOF (handlers); h++)
381     {
382       enum iconv_ilseq_handler handler = handlers[h];
383       static const char input[] = "\033$B$3$s$K$A$O\033(B"; /* こんにちは in ISO-2022-JP-2 */
384       static const char expected[] = "\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257"; /* こんにちは */
385       for (o = 0; o < 2; o++)
386         {
387           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
388           char *result = NULL;
389           size_t length = 0;
390           int retval = mem_iconveha (input, strlen (input),
391                                      "autodetect_jp", "UTF-8",
392                                      false, handler,
393                                      offsets,
394                                      &result, &length);
395           ASSERT (retval == 0);
396           ASSERT (length == strlen (expected));
397           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
398           if (o)
399             {
400               for (i = 0; i < 16; i++)
401                 ASSERT (offsets[i] == (i == 0 ? 0 :
402                                        i == 5 ? 3 :
403                                        i == 7 ? 6 :
404                                        i == 9 ? 9 :
405                                        i == 11 ? 12 :
406                                        i == 13 ? 15 :
407                                        (size_t)(-1)));
408               ASSERT (offsets[16] == MAGIC);
409               free (offsets);
410             }
411           free (result);
412         }
413     }
414 # endif
415
416 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || _LIBICONV_VERSION >= 0x0105
417   /* Test conversion from UTF-8 to ISO-8859-1 with transliteration.  */
418   for (h = 0; h < SIZEOF (handlers); h++)
419     {
420       enum iconv_ilseq_handler handler = handlers[h];
421       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
422       static const char expected[] = "Costs: 27 EUR";
423       for (o = 0; o < 2; o++)
424         {
425           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
426           char *result = NULL;
427           size_t length = 0;
428           int retval = mem_iconveha (input, strlen (input),
429                                      "UTF-8", "ISO-8859-1",
430                                      true, handler,
431                                      offsets,
432                                      &result, &length);
433           ASSERT (retval == 0);
434           ASSERT (length == strlen (expected));
435           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
436           if (o)
437             {
438               for (i = 0; i < 13; i++)
439                 ASSERT (offsets[i] == (i < 11 ? i : (size_t)(-1)));
440               ASSERT (offsets[13] == MAGIC);
441               free (offsets);
442             }
443           free (result);
444         }
445     }
446 # endif
447
448   /* ------------------------- Test str_iconveha() ------------------------- */
449
450   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
451   for (h = 0; h < SIZEOF (handlers); h++)
452     {
453       enum iconv_ilseq_handler handler = handlers[h];
454       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
455       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
456       char *result = str_iconveha (input, "ISO-8859-2", "ISO-8859-1", false, handler);
457       ASSERT (result != NULL);
458       ASSERT (strcmp (result, expected) == 0);
459       free (result);
460     }
461
462   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
463   for (h = 0; h < SIZEOF (handlers); h++)
464     {
465       enum iconv_ilseq_handler handler = handlers[h];
466       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
467       char *result = str_iconveha (input, "ISO-8859-2", "ISO-8859-1", false, handler);
468       switch (handler)
469         {
470         case iconveh_error:
471           ASSERT (result == NULL && errno == EILSEQ);
472           break;
473         case iconveh_question_mark:
474           {
475             static const char expected[] = "Rafa? Maszkowski";
476             ASSERT (result != NULL);
477             ASSERT (strcmp (result, expected) == 0);
478             free (result);
479           }
480           break;
481         case iconveh_escape_sequence:
482           {
483             static const char expected[] = "Rafa\\u0142 Maszkowski";
484             ASSERT (result != NULL);
485             ASSERT (strcmp (result, expected) == 0);
486             free (result);
487           }
488           break;
489         }
490     }
491
492   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
493   for (h = 0; h < SIZEOF (handlers); h++)
494     {
495       enum iconv_ilseq_handler handler = handlers[h];
496       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
497       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
498       char *result = str_iconveha (input, "ISO-8859-1", "UTF-8", false, handler);
499       ASSERT (result != NULL);
500       ASSERT (strcmp (result, expected) == 0);
501       free (result);
502     }
503
504   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
505   for (h = 0; h < SIZEOF (handlers); h++)
506     {
507       enum iconv_ilseq_handler handler = handlers[h];
508       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
509       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
510       char *result = str_iconveha (input, "UTF-8", "ISO-8859-1", false, handler);
511       ASSERT (result != NULL);
512       ASSERT (strcmp (result, expected) == 0);
513       free (result);
514     }
515
516   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
517   for (h = 0; h < SIZEOF (handlers); h++)
518     {
519       enum iconv_ilseq_handler handler = handlers[h];
520       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
521       char *result = str_iconveha (input, "UTF-8", "ISO-8859-1", false, handler);
522       switch (handler)
523         {
524         case iconveh_error:
525           ASSERT (result == NULL && errno == EILSEQ);
526           break;
527         case iconveh_question_mark:
528           {
529             static const char expected[] = "Costs: 27 ?";
530             ASSERT (result != NULL);
531             ASSERT (strcmp (result, expected) == 0);
532             free (result);
533           }
534           break;
535         case iconveh_escape_sequence:
536           {
537             static const char expected[] = "Costs: 27 \\u20AC";
538             ASSERT (result != NULL);
539             ASSERT (strcmp (result, expected) == 0);
540             free (result);
541           }
542           break;
543         }
544     }
545
546   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
547   for (h = 0; h < SIZEOF (handlers); h++)
548     {
549       enum iconv_ilseq_handler handler = handlers[h];
550       static const char input[] = "\342";
551       char *result = str_iconveha (input, "UTF-8", "ISO-8859-1", false, handler);
552       ASSERT (result != NULL);
553       ASSERT (strcmp (result, "") == 0);
554       free (result);
555     }
556
557   /* autodetect_jp is only supported when iconv() support ISO-2022-JP-2.  */
558 # if defined _LIBICONV_VERSION || !(defined _AIX || defined __sgi || defined __hpux || defined __osf__ || defined __sun)
559   /* Test conversions from autodetect_jp to UTF-8.  */
560   for (h = 0; h < SIZEOF (handlers); h++)
561     {
562       enum iconv_ilseq_handler handler = handlers[h];
563       static const char input[] = "\244\263\244\363\244\313\244\301\244\317"; /* こんにちは in EUC-JP */
564       static const char expected[] = "\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257"; /* こんにちは */
565       char *result = str_iconveha (input, "autodetect_jp", "UTF-8", false, handler);
566       ASSERT (result != NULL);
567       ASSERT (strcmp (result, expected) == 0);
568       free (result);
569     }
570   for (h = 0; h < SIZEOF (handlers); h++)
571     {
572       enum iconv_ilseq_handler handler = handlers[h];
573       static const char input[] = "\202\261\202\361\202\311\202\277\202\315"; /* こんにちは in Shift_JIS */
574       static const char expected[] = "\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257"; /* こんにちは */
575       char *result = str_iconveha (input, "autodetect_jp", "UTF-8", false, handler);
576       ASSERT (result != NULL);
577       ASSERT (strcmp (result, expected) == 0);
578       free (result);
579     }
580   for (h = 0; h < SIZEOF (handlers); h++)
581     {
582       enum iconv_ilseq_handler handler = handlers[h];
583       static const char input[] = "\033$B$3$s$K$A$O\033(B"; /* こんにちは in ISO-2022-JP-2 */
584       static const char expected[] = "\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257"; /* こんにちは */
585       char *result = str_iconveha (input, "autodetect_jp", "UTF-8", false, handler);
586       ASSERT (result != NULL);
587       ASSERT (strcmp (result, expected) == 0);
588       free (result);
589     }
590 # endif
591
592 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || _LIBICONV_VERSION >= 0x0105
593   /* Test conversion from UTF-8 to ISO-8859-1 with transliteration.  */
594   for (h = 0; h < SIZEOF (handlers); h++)
595     {
596       enum iconv_ilseq_handler handler = handlers[h];
597       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
598       static const char expected[] = "Costs: 27 EUR";
599       char *result = str_iconveha (input, "UTF-8", "ISO-8859-1", true, handler);
600       ASSERT (result != NULL);
601       ASSERT (strcmp (result, expected) == 0);
602       free (result);
603     }
604 # endif
605
606 #endif
607
608   return 0;
609 }