Unconditionally include <config.h> in unit tests.
[gnulib.git] / tests / test-striconveh.c
1 /* Test of character set conversion with error handling.
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 2, or (at your option)
7    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, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
19
20 #include <config.h>
21
22 #include "striconveh.h"
23
24 #if HAVE_ICONV
25 # include <iconv.h>
26 #endif
27
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #define SIZEOF(array) (sizeof (array) / sizeof (array[0]))
34 #define ASSERT(expr) \
35   do                                                                         \
36     {                                                                        \
37       if (!(expr))                                                           \
38         {                                                                    \
39           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
40           abort ();                                                          \
41         }                                                                    \
42     }                                                                        \
43   while (0)
44
45 /* Magic number for detecting bounds violations.  */
46 #define MAGIC 0x1983EFF1
47
48 static size_t *
49 new_offsets (size_t n)
50 {
51   size_t *offsets = (size_t *) malloc ((n + 1) * sizeof (size_t));
52   offsets[n] = MAGIC;
53   return offsets;
54 }
55
56 int
57 main ()
58 {
59   static enum iconv_ilseq_handler handlers[] =
60     { iconveh_error, iconveh_question_mark, iconveh_escape_sequence };
61   size_t h;
62   size_t o;
63   size_t i;
64
65 #if HAVE_ICONV
66   /* Assume that iconv() supports at least the encodings ASCII, ISO-8859-1,
67      ISO-8859-2, and UTF-8.  */
68   iconv_t cd_88591_to_88592 = iconv_open ("ISO-8859-2", "ISO-8859-1");
69   iconv_t cd_88592_to_88591 = iconv_open ("ISO-8859-1", "ISO-8859-2");
70   iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1");
71   iconv_t cd_utf8_to_88591 = iconv_open ("ISO-8859-1", "UTF-8");
72   iconv_t cd_88592_to_utf8 = iconv_open ("UTF-8", "ISO-8859-2");
73   iconv_t cd_utf8_to_88592 = iconv_open ("ISO-8859-2", "UTF-8");
74
75   ASSERT (cd_88591_to_utf8 != (iconv_t)(-1));
76   ASSERT (cd_utf8_to_88591 != (iconv_t)(-1));
77   ASSERT (cd_88592_to_utf8 != (iconv_t)(-1));
78   ASSERT (cd_utf8_to_88592 != (iconv_t)(-1));
79
80   /* ------------------------ Test mem_cd_iconveh() ------------------------ */
81
82   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
83   for (h = 0; h < SIZEOF (handlers); h++)
84     {
85       enum iconv_ilseq_handler handler = handlers[h];
86       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
87       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
88       for (o = 0; o < 2; o++)
89         {
90           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
91           char *result = NULL;
92           size_t length = 0;
93           int retval = mem_cd_iconveh (input, strlen (input),
94                                        cd_88592_to_88591,
95                                        cd_88592_to_utf8, cd_utf8_to_88591,
96                                        handler,
97                                        offsets,
98                                        &result, &length);
99           ASSERT (retval == 0);
100           ASSERT (length == strlen (expected));
101           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
102           if (o)
103             {
104               for (i = 0; i < 37; i++)
105                 ASSERT (offsets[i] == i);
106               ASSERT (offsets[37] == MAGIC);
107               free (offsets);
108             }
109           free (result);
110         }
111     }
112
113   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
114   for (h = 0; h < SIZEOF (handlers); h++)
115     {
116       enum iconv_ilseq_handler handler = handlers[h];
117       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
118       for (o = 0; o < 2; o++)
119         {
120           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
121           char *result = NULL;
122           size_t length = 0;
123           int retval = mem_cd_iconveh (input, strlen (input),
124                                        cd_88592_to_88591,
125                                        cd_88592_to_utf8, cd_utf8_to_88591,
126                                        handler,
127                                        offsets,
128                                        &result, &length);
129           switch (handler)
130             {
131             case iconveh_error:
132               ASSERT (retval == -1 && errno == EILSEQ);
133               ASSERT (result == NULL);
134               if (o)
135                 free (offsets);
136               break;
137             case iconveh_question_mark:
138               {
139                 static const char expected[] = "Rafa? Maszkowski";
140                 ASSERT (retval == 0);
141                 ASSERT (length == strlen (expected));
142                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
143                 if (o)
144                   {
145                     for (i = 0; i < 16; i++)
146                       ASSERT (offsets[i] == i);
147                     ASSERT (offsets[16] == MAGIC);
148                     free (offsets);
149                   }
150                 free (result);
151               }
152               break;
153             case iconveh_escape_sequence:
154               {
155                 static const char expected[] = "Rafa\\u0142 Maszkowski";
156                 ASSERT (retval == 0);
157                 ASSERT (length == strlen (expected));
158                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
159                 if (o)
160                   {
161                     for (i = 0; i < 16; i++)
162                       ASSERT (offsets[i] == (i < 5 ? i :
163                                              i + 5));
164                     ASSERT (offsets[16] == MAGIC);
165                     free (offsets);
166                   }
167                 free (result);
168               }
169               break;
170             }
171         }
172     }
173
174   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
175   for (h = 0; h < SIZEOF (handlers); h++)
176     {
177       enum iconv_ilseq_handler handler = handlers[h];
178       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
179       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
180       for (o = 0; o < 2; o++)
181         {
182           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
183           char *result = NULL;
184           size_t length = 0;
185           int retval = mem_cd_iconveh (input, strlen (input),
186                                        cd_88591_to_utf8,
187                                        cd_88591_to_utf8, (iconv_t)(-1),
188                                        handler,
189                                        offsets,
190                                        &result, &length);
191           ASSERT (retval == 0);
192           ASSERT (length == strlen (expected));
193           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
194           if (o)
195             {
196               for (i = 0; i < 37; i++)
197                 ASSERT (offsets[i] == (i < 1 ? i :
198                                        i < 12 ? i + 1 :
199                                        i < 18 ? i + 2 :
200                                        i + 3));
201               ASSERT (offsets[37] == MAGIC);
202               free (offsets);
203             }
204           free (result);
205         }
206     }
207
208   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
209   for (h = 0; h < SIZEOF (handlers); h++)
210     {
211       enum iconv_ilseq_handler handler = handlers[h];
212       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
213       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
214       for (o = 0; o < 2; o++)
215         {
216           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
217           char *result = NULL;
218           size_t length = 0;
219           int retval = mem_cd_iconveh (input, strlen (input),
220                                        cd_utf8_to_88591,
221                                        (iconv_t)(-1), cd_utf8_to_88591,
222                                        handler,
223                                        offsets,
224                                        &result, &length);
225           ASSERT (retval == 0);
226           ASSERT (length == strlen (expected));
227           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
228           if (o)
229             {
230               for (i = 0; i < 41; i++)
231                 ASSERT (offsets[i] == (i < 1 ? i :
232                                        i == 1 ? (size_t)(-1) :
233                                        i < 13 ? i - 1 :
234                                        i == 13 ? (size_t)(-1) :
235                                        i < 20 ? i - 2 :
236                                        i == 20 ? (size_t)(-1) :
237                                        i < 40 ? i - 3 :
238                                        (size_t)(-1)));
239               ASSERT (offsets[41] == MAGIC);
240               free (offsets);
241             }
242           free (result);
243         }
244     }
245
246   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
247   for (h = 0; h < SIZEOF (handlers); h++)
248     {
249       enum iconv_ilseq_handler handler = handlers[h];
250       static const char input[] = "Rafa\305\202 Maszkowski"; /* Rafał Maszkowski */
251       for (o = 0; o < 2; o++)
252         {
253           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
254           char *result = NULL;
255           size_t length = 0;
256           int retval = mem_cd_iconveh (input, strlen (input),
257                                        cd_utf8_to_88591,
258                                        (iconv_t)(-1), cd_utf8_to_88591,
259                                        handler,
260                                        offsets,
261                                        &result, &length);
262           switch (handler)
263             {
264             case iconveh_error:
265               ASSERT (retval == -1 && errno == EILSEQ);
266               ASSERT (result == NULL);
267               if (o)
268                 free (offsets);
269               break;
270             case iconveh_question_mark:
271               {
272                 static const char expected[] = "Rafa? Maszkowski";
273                 ASSERT (retval == 0);
274                 ASSERT (length == strlen (expected));
275                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
276                 if (o)
277                   {
278                     for (i = 0; i < 17; i++)
279                       ASSERT (offsets[i] == (i < 5 ? i :
280                                              i == 5 ? (size_t)(-1) :
281                                              i - 1));
282                     ASSERT (offsets[17] == MAGIC);
283                     free (offsets);
284                   }
285                 free (result);
286               }
287               break;
288             case iconveh_escape_sequence:
289               {
290                 static const char expected[] = "Rafa\\u0142 Maszkowski";
291                 ASSERT (retval == 0);
292                 ASSERT (length == strlen (expected));
293                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
294                 if (o)
295                   {
296                     for (i = 0; i < 17; i++)
297                       ASSERT (offsets[i] == (i < 5 ? i :
298                                              i == 5 ? (size_t)(-1) :
299                                              i + 4));
300                     ASSERT (offsets[17] == MAGIC);
301                     free (offsets);
302                   }
303                 free (result);
304               }
305               break;
306             }
307         }
308     }
309
310   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
311   for (h = 0; h < SIZEOF (handlers); h++)
312     {
313       enum iconv_ilseq_handler handler = handlers[h];
314       static const char input[] = "\342";
315       for (o = 0; o < 2; o++)
316         {
317           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
318           char *result = NULL;
319           size_t length = 0;
320           int retval = mem_cd_iconveh (input, strlen (input),
321                                        cd_utf8_to_88591,
322                                        (iconv_t)(-1), cd_utf8_to_88591,
323                                        handler,
324                                        offsets,
325                                        &result, &length);
326           ASSERT (retval == 0);
327           ASSERT (length == 0);
328           if (o)
329             {
330               ASSERT (offsets[0] == 0);
331               ASSERT (offsets[1] == MAGIC);
332               free (offsets);
333             }
334           if (result != NULL)
335             free (result);
336         }
337     }
338
339   /* ------------------------ Test str_cd_iconveh() ------------------------ */
340
341   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
342   for (h = 0; h < SIZEOF (handlers); h++)
343     {
344       enum iconv_ilseq_handler handler = handlers[h];
345       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
346       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
347       char *result = str_cd_iconveh (input,
348                                      cd_88592_to_88591,
349                                      cd_88592_to_utf8, cd_utf8_to_88591,
350                                      handler);
351       ASSERT (result != NULL);
352       ASSERT (strcmp (result, expected) == 0);
353       free (result);
354     }
355
356   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
357   for (h = 0; h < SIZEOF (handlers); h++)
358     {
359       enum iconv_ilseq_handler handler = handlers[h];
360       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
361       char *result = str_cd_iconveh (input,
362                                      cd_88592_to_88591,
363                                      cd_88592_to_utf8, cd_utf8_to_88591,
364                                      handler);
365       switch (handler)
366         {
367         case iconveh_error:
368           ASSERT (result == NULL && errno == EILSEQ);
369           break;
370         case iconveh_question_mark:
371           {
372             static const char expected[] = "Rafa? Maszkowski";
373             ASSERT (result != NULL);
374             ASSERT (strcmp (result, expected) == 0);
375             free (result);
376           }
377           break;
378         case iconveh_escape_sequence:
379           {
380             static const char expected[] = "Rafa\\u0142 Maszkowski";
381             ASSERT (result != NULL);
382             ASSERT (strcmp (result, expected) == 0);
383             free (result);
384           }
385           break;
386         }
387     }
388
389   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
390   for (h = 0; h < SIZEOF (handlers); h++)
391     {
392       enum iconv_ilseq_handler handler = handlers[h];
393       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
394       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
395       char *result = str_cd_iconveh (input,
396                                      cd_88591_to_utf8,
397                                      cd_88591_to_utf8, (iconv_t)(-1),
398                                      handler);
399       ASSERT (result != NULL);
400       ASSERT (strcmp (result, expected) == 0);
401       free (result);
402     }
403
404   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
405   for (h = 0; h < SIZEOF (handlers); h++)
406     {
407       enum iconv_ilseq_handler handler = handlers[h];
408       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
409       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
410       char *result = str_cd_iconveh (input,
411                                      cd_utf8_to_88591,
412                                      (iconv_t)(-1), cd_utf8_to_88591,
413                                      handler);
414       ASSERT (result != NULL);
415       ASSERT (strcmp (result, expected) == 0);
416       free (result);
417     }
418
419   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
420   for (h = 0; h < SIZEOF (handlers); h++)
421     {
422       enum iconv_ilseq_handler handler = handlers[h];
423       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
424       char *result = str_cd_iconveh (input,
425                                      cd_utf8_to_88591,
426                                      (iconv_t)(-1), cd_utf8_to_88591,
427                                      handler);
428       switch (handler)
429         {
430         case iconveh_error:
431           ASSERT (result == NULL && errno == EILSEQ);
432           break;
433         case iconveh_question_mark:
434           {
435             static const char expected[] = "Costs: 27 ?";
436             ASSERT (result != NULL);
437             ASSERT (strcmp (result, expected) == 0);
438             free (result);
439           }
440           break;
441         case iconveh_escape_sequence:
442           {
443             static const char expected[] = "Costs: 27 \\u20AC";
444             ASSERT (result != NULL);
445             ASSERT (strcmp (result, expected) == 0);
446             free (result);
447           }
448           break;
449         }
450     }
451
452   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
453   for (h = 0; h < SIZEOF (handlers); h++)
454     {
455       enum iconv_ilseq_handler handler = handlers[h];
456       static const char input[] = "\342";
457       char *result = str_cd_iconveh (input,
458                                      cd_utf8_to_88591,
459                                      (iconv_t)(-1), cd_utf8_to_88591,
460                                      handler);
461       ASSERT (result != NULL);
462       ASSERT (strcmp (result, "") == 0);
463       free (result);
464     }
465
466   if (cd_88591_to_88592 != (iconv_t)(-1))
467     iconv_close (cd_88591_to_88592);
468   if (cd_88592_to_88591 != (iconv_t)(-1))
469     iconv_close (cd_88592_to_88591);
470   iconv_close (cd_88591_to_utf8);
471   iconv_close (cd_utf8_to_88591);
472   iconv_close (cd_88592_to_utf8);
473   iconv_close (cd_utf8_to_88592);
474
475   /* ------------------------- Test mem_iconveh() ------------------------- */
476
477   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
478   for (h = 0; h < SIZEOF (handlers); h++)
479     {
480       enum iconv_ilseq_handler handler = handlers[h];
481       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
482       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
483       for (o = 0; o < 2; o++)
484         {
485           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
486           char *result = NULL;
487           size_t length = 0;
488           int retval = mem_iconveh (input, strlen (input),
489                                     "ISO-8859-2", "ISO-8859-1",
490                                     handler,
491                                     offsets,
492                                     &result, &length);
493           ASSERT (retval == 0);
494           ASSERT (length == strlen (expected));
495           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
496           if (o)
497             {
498               for (i = 0; i < 37; i++)
499                 ASSERT (offsets[i] == i);
500               ASSERT (offsets[37] == MAGIC);
501               free (offsets);
502             }
503           free (result);
504         }
505     }
506
507   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
508   for (h = 0; h < SIZEOF (handlers); h++)
509     {
510       enum iconv_ilseq_handler handler = handlers[h];
511       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
512       for (o = 0; o < 2; o++)
513         {
514           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
515           char *result = NULL;
516           size_t length = 0;
517           int retval = mem_iconveh (input, strlen (input),
518                                     "ISO-8859-2", "ISO-8859-1",
519                                     handler,
520                                     offsets,
521                                     &result, &length);
522           switch (handler)
523             {
524             case iconveh_error:
525               ASSERT (retval == -1 && errno == EILSEQ);
526               ASSERT (result == NULL);
527               if (o)
528                 free (offsets);
529               break;
530             case iconveh_question_mark:
531               {
532                 static const char expected[] = "Rafa? Maszkowski";
533                 ASSERT (retval == 0);
534                 ASSERT (length == strlen (expected));
535                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
536                 if (o)
537                   {
538                     for (i = 0; i < 16; i++)
539                       ASSERT (offsets[i] == i);
540                     ASSERT (offsets[16] == MAGIC);
541                     free (offsets);
542                   }
543                 free (result);
544               }
545               break;
546             case iconveh_escape_sequence:
547               {
548                 static const char expected[] = "Rafa\\u0142 Maszkowski";
549                 ASSERT (retval == 0);
550                 ASSERT (length == strlen (expected));
551                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
552                 if (o)
553                   {
554                     for (i = 0; i < 16; i++)
555                       ASSERT (offsets[i] == (i < 5 ? i :
556                                              i + 5));
557                     ASSERT (offsets[16] == MAGIC);
558                     free (offsets);
559                   }
560                 free (result);
561               }
562               break;
563             }
564         }
565     }
566
567   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
568   for (h = 0; h < SIZEOF (handlers); h++)
569     {
570       enum iconv_ilseq_handler handler = handlers[h];
571       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
572       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
573       for (o = 0; o < 2; o++)
574         {
575           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
576           char *result = NULL;
577           size_t length = 0;
578           int retval = mem_iconveh (input, strlen (input),
579                                     "ISO-8859-1", "UTF-8",
580                                     handler,
581                                     offsets,
582                                     &result, &length);
583           ASSERT (retval == 0);
584           ASSERT (length == strlen (expected));
585           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
586           if (o)
587             {
588               for (i = 0; i < 37; i++)
589                 ASSERT (offsets[i] == (i < 1 ? i :
590                                        i < 12 ? i + 1 :
591                                        i < 18 ? i + 2 :
592                                        i + 3));
593               ASSERT (offsets[37] == MAGIC);
594               free (offsets);
595             }
596           free (result);
597         }
598     }
599
600   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
601   for (h = 0; h < SIZEOF (handlers); h++)
602     {
603       enum iconv_ilseq_handler handler = handlers[h];
604       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
605       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
606       for (o = 0; o < 2; o++)
607         {
608           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
609           char *result = NULL;
610           size_t length = 0;
611           int retval = mem_iconveh (input, strlen (input),
612                                     "UTF-8", "ISO-8859-1",
613                                     handler,
614                                     offsets,
615                                     &result, &length);
616           ASSERT (retval == 0);
617           ASSERT (length == strlen (expected));
618           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
619           if (o)
620             {
621               for (i = 0; i < 41; i++)
622                 ASSERT (offsets[i] == (i < 1 ? i :
623                                        i == 1 ? (size_t)(-1) :
624                                        i < 13 ? i - 1 :
625                                        i == 13 ? (size_t)(-1) :
626                                        i < 20 ? i - 2 :
627                                        i == 20 ? (size_t)(-1) :
628                                        i < 40 ? i - 3 :
629                                        (size_t)(-1)));
630               ASSERT (offsets[41] == MAGIC);
631               free (offsets);
632             }
633           free (result);
634         }
635     }
636
637   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
638   for (h = 0; h < SIZEOF (handlers); h++)
639     {
640       enum iconv_ilseq_handler handler = handlers[h];
641       static const char input[] = "Rafa\305\202 Maszkowski"; /* Rafał Maszkowski */
642       for (o = 0; o < 2; o++)
643         {
644           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
645           char *result = NULL;
646           size_t length = 0;
647           int retval = mem_iconveh (input, strlen (input),
648                                     "UTF-8", "ISO-8859-1",
649                                     handler,
650                                     offsets,
651                                     &result, &length);
652           switch (handler)
653             {
654             case iconveh_error:
655               ASSERT (retval == -1 && errno == EILSEQ);
656               ASSERT (result == NULL);
657               if (o)
658                 free (offsets);
659               break;
660             case iconveh_question_mark:
661               {
662                 static const char expected[] = "Rafa? Maszkowski";
663                 ASSERT (retval == 0);
664                 ASSERT (length == strlen (expected));
665                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
666                 if (o)
667                   {
668                     for (i = 0; i < 17; i++)
669                       ASSERT (offsets[i] == (i < 5 ? i :
670                                              i == 5 ? (size_t)(-1) :
671                                              i - 1));
672                     ASSERT (offsets[17] == MAGIC);
673                     free (offsets);
674                   }
675                 free (result);
676               }
677               break;
678             case iconveh_escape_sequence:
679               {
680                 static const char expected[] = "Rafa\\u0142 Maszkowski";
681                 ASSERT (retval == 0);
682                 ASSERT (length == strlen (expected));
683                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
684                 if (o)
685                   {
686                     for (i = 0; i < 17; i++)
687                       ASSERT (offsets[i] == (i < 5 ? i :
688                                              i == 5 ? (size_t)(-1) :
689                                              i + 4));
690                     ASSERT (offsets[17] == MAGIC);
691                     free (offsets);
692                   }
693                 free (result);
694               }
695               break;
696             }
697         }
698     }
699
700   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
701   for (h = 0; h < SIZEOF (handlers); h++)
702     {
703       enum iconv_ilseq_handler handler = handlers[h];
704       static const char input[] = "\342";
705       for (o = 0; o < 2; o++)
706         {
707           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
708           char *result = NULL;
709           size_t length = 0;
710           int retval = mem_iconveh (input, strlen (input),
711                                     "UTF-8", "ISO-8859-1",
712                                     handler,
713                                     offsets,
714                                     &result, &length);
715           ASSERT (retval == 0);
716           ASSERT (length == 0);
717           if (o)
718             {
719               ASSERT (offsets[0] == 0);
720               ASSERT (offsets[1] == MAGIC);
721               free (offsets);
722             }
723           if (result != NULL)
724             free (result);
725         }
726     }
727
728   /* ------------------------- Test str_iconveh() ------------------------- */
729
730   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
731   for (h = 0; h < SIZEOF (handlers); h++)
732     {
733       enum iconv_ilseq_handler handler = handlers[h];
734       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
735       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
736       char *result = str_iconveh (input, "ISO-8859-2", "ISO-8859-1", handler);
737       ASSERT (result != NULL);
738       ASSERT (strcmp (result, expected) == 0);
739       free (result);
740     }
741
742   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
743   for (h = 0; h < SIZEOF (handlers); h++)
744     {
745       enum iconv_ilseq_handler handler = handlers[h];
746       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
747       char *result = str_iconveh (input, "ISO-8859-2", "ISO-8859-1", handler);
748       switch (handler)
749         {
750         case iconveh_error:
751           ASSERT (result == NULL && errno == EILSEQ);
752           break;
753         case iconveh_question_mark:
754           {
755             static const char expected[] = "Rafa? Maszkowski";
756             ASSERT (result != NULL);
757             ASSERT (strcmp (result, expected) == 0);
758             free (result);
759           }
760           break;
761         case iconveh_escape_sequence:
762           {
763             static const char expected[] = "Rafa\\u0142 Maszkowski";
764             ASSERT (result != NULL);
765             ASSERT (strcmp (result, expected) == 0);
766             free (result);
767           }
768           break;
769         }
770     }
771
772   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
773   for (h = 0; h < SIZEOF (handlers); h++)
774     {
775       enum iconv_ilseq_handler handler = handlers[h];
776       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
777       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
778       char *result = str_iconveh (input, "ISO-8859-1", "UTF-8", handler);
779       ASSERT (result != NULL);
780       ASSERT (strcmp (result, expected) == 0);
781       free (result);
782     }
783
784   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
785   for (h = 0; h < SIZEOF (handlers); h++)
786     {
787       enum iconv_ilseq_handler handler = handlers[h];
788       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
789       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
790       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
791       ASSERT (result != NULL);
792       ASSERT (strcmp (result, expected) == 0);
793       free (result);
794     }
795
796   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
797   for (h = 0; h < SIZEOF (handlers); h++)
798     {
799       enum iconv_ilseq_handler handler = handlers[h];
800       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
801       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
802       switch (handler)
803         {
804         case iconveh_error:
805           ASSERT (result == NULL && errno == EILSEQ);
806           break;
807         case iconveh_question_mark:
808           {
809             static const char expected[] = "Costs: 27 ?";
810             ASSERT (result != NULL);
811             ASSERT (strcmp (result, expected) == 0);
812             free (result);
813           }
814           break;
815         case iconveh_escape_sequence:
816           {
817             static const char expected[] = "Costs: 27 \\u20AC";
818             ASSERT (result != NULL);
819             ASSERT (strcmp (result, expected) == 0);
820             free (result);
821           }
822           break;
823         }
824     }
825
826   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
827   for (h = 0; h < SIZEOF (handlers); h++)
828     {
829       enum iconv_ilseq_handler handler = handlers[h];
830       static const char input[] = "\342";
831       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
832       ASSERT (result != NULL);
833       ASSERT (strcmp (result, "") == 0);
834       free (result);
835     }
836
837 #endif
838
839   return 0;
840 }