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