Change copyright notice from GPLv2+ to GPLv3+.
[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 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           if (result != NULL)
334             free (result);
335         }
336     }
337
338   /* ------------------------ Test str_cd_iconveh() ------------------------ */
339
340   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
341   for (h = 0; h < SIZEOF (handlers); h++)
342     {
343       enum iconv_ilseq_handler handler = handlers[h];
344       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
345       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
346       char *result = str_cd_iconveh (input,
347                                      cd_88592_to_88591,
348                                      cd_88592_to_utf8, cd_utf8_to_88591,
349                                      handler);
350       ASSERT (result != NULL);
351       ASSERT (strcmp (result, expected) == 0);
352       free (result);
353     }
354
355   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
356   for (h = 0; h < SIZEOF (handlers); h++)
357     {
358       enum iconv_ilseq_handler handler = handlers[h];
359       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
360       char *result = str_cd_iconveh (input,
361                                      cd_88592_to_88591,
362                                      cd_88592_to_utf8, cd_utf8_to_88591,
363                                      handler);
364       switch (handler)
365         {
366         case iconveh_error:
367           ASSERT (result == NULL && errno == EILSEQ);
368           break;
369         case iconveh_question_mark:
370           {
371             static const char expected[] = "Rafa? Maszkowski";
372             ASSERT (result != NULL);
373             ASSERT (strcmp (result, expected) == 0);
374             free (result);
375           }
376           break;
377         case iconveh_escape_sequence:
378           {
379             static const char expected[] = "Rafa\\u0142 Maszkowski";
380             ASSERT (result != NULL);
381             ASSERT (strcmp (result, expected) == 0);
382             free (result);
383           }
384           break;
385         }
386     }
387
388   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
389   for (h = 0; h < SIZEOF (handlers); h++)
390     {
391       enum iconv_ilseq_handler handler = handlers[h];
392       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
393       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
394       char *result = str_cd_iconveh (input,
395                                      cd_88591_to_utf8,
396                                      cd_88591_to_utf8, (iconv_t)(-1),
397                                      handler);
398       ASSERT (result != NULL);
399       ASSERT (strcmp (result, expected) == 0);
400       free (result);
401     }
402
403   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
404   for (h = 0; h < SIZEOF (handlers); h++)
405     {
406       enum iconv_ilseq_handler handler = handlers[h];
407       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
408       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
409       char *result = str_cd_iconveh (input,
410                                      cd_utf8_to_88591,
411                                      (iconv_t)(-1), cd_utf8_to_88591,
412                                      handler);
413       ASSERT (result != NULL);
414       ASSERT (strcmp (result, expected) == 0);
415       free (result);
416     }
417
418   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
419   for (h = 0; h < SIZEOF (handlers); h++)
420     {
421       enum iconv_ilseq_handler handler = handlers[h];
422       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
423       char *result = str_cd_iconveh (input,
424                                      cd_utf8_to_88591,
425                                      (iconv_t)(-1), cd_utf8_to_88591,
426                                      handler);
427       switch (handler)
428         {
429         case iconveh_error:
430           ASSERT (result == NULL && errno == EILSEQ);
431           break;
432         case iconveh_question_mark:
433           {
434             static const char expected[] = "Costs: 27 ?";
435             ASSERT (result != NULL);
436             ASSERT (strcmp (result, expected) == 0);
437             free (result);
438           }
439           break;
440         case iconveh_escape_sequence:
441           {
442             static const char expected[] = "Costs: 27 \\u20AC";
443             ASSERT (result != NULL);
444             ASSERT (strcmp (result, expected) == 0);
445             free (result);
446           }
447           break;
448         }
449     }
450
451   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
452   for (h = 0; h < SIZEOF (handlers); h++)
453     {
454       enum iconv_ilseq_handler handler = handlers[h];
455       static const char input[] = "\342";
456       char *result = str_cd_iconveh (input,
457                                      cd_utf8_to_88591,
458                                      (iconv_t)(-1), cd_utf8_to_88591,
459                                      handler);
460       ASSERT (result != NULL);
461       ASSERT (strcmp (result, "") == 0);
462       free (result);
463     }
464
465   if (cd_88591_to_88592 != (iconv_t)(-1))
466     iconv_close (cd_88591_to_88592);
467   if (cd_88592_to_88591 != (iconv_t)(-1))
468     iconv_close (cd_88592_to_88591);
469   iconv_close (cd_88591_to_utf8);
470   iconv_close (cd_utf8_to_88591);
471   iconv_close (cd_88592_to_utf8);
472   iconv_close (cd_utf8_to_88592);
473
474   /* ------------------------- Test mem_iconveh() ------------------------- */
475
476   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
477   for (h = 0; h < SIZEOF (handlers); h++)
478     {
479       enum iconv_ilseq_handler handler = handlers[h];
480       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
481       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
482       for (o = 0; o < 2; o++)
483         {
484           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
485           char *result = NULL;
486           size_t length = 0;
487           int retval = mem_iconveh (input, strlen (input),
488                                     "ISO-8859-2", "ISO-8859-1",
489                                     handler,
490                                     offsets,
491                                     &result, &length);
492           ASSERT (retval == 0);
493           ASSERT (length == strlen (expected));
494           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
495           if (o)
496             {
497               for (i = 0; i < 37; i++)
498                 ASSERT (offsets[i] == i);
499               ASSERT (offsets[37] == MAGIC);
500               free (offsets);
501             }
502           free (result);
503         }
504     }
505
506   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
507   for (h = 0; h < SIZEOF (handlers); h++)
508     {
509       enum iconv_ilseq_handler handler = handlers[h];
510       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
511       for (o = 0; o < 2; o++)
512         {
513           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
514           char *result = NULL;
515           size_t length = 0;
516           int retval = mem_iconveh (input, strlen (input),
517                                     "ISO-8859-2", "ISO-8859-1",
518                                     handler,
519                                     offsets,
520                                     &result, &length);
521           switch (handler)
522             {
523             case iconveh_error:
524               ASSERT (retval == -1 && errno == EILSEQ);
525               ASSERT (result == NULL);
526               if (o)
527                 free (offsets);
528               break;
529             case iconveh_question_mark:
530               {
531                 static const char expected[] = "Rafa? Maszkowski";
532                 ASSERT (retval == 0);
533                 ASSERT (length == strlen (expected));
534                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
535                 if (o)
536                   {
537                     for (i = 0; i < 16; i++)
538                       ASSERT (offsets[i] == i);
539                     ASSERT (offsets[16] == MAGIC);
540                     free (offsets);
541                   }
542                 free (result);
543               }
544               break;
545             case iconveh_escape_sequence:
546               {
547                 static const char expected[] = "Rafa\\u0142 Maszkowski";
548                 ASSERT (retval == 0);
549                 ASSERT (length == strlen (expected));
550                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
551                 if (o)
552                   {
553                     for (i = 0; i < 16; i++)
554                       ASSERT (offsets[i] == (i < 5 ? i :
555                                              i + 5));
556                     ASSERT (offsets[16] == MAGIC);
557                     free (offsets);
558                   }
559                 free (result);
560               }
561               break;
562             }
563         }
564     }
565
566   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
567   for (h = 0; h < SIZEOF (handlers); h++)
568     {
569       enum iconv_ilseq_handler handler = handlers[h];
570       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
571       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
572       for (o = 0; o < 2; o++)
573         {
574           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
575           char *result = NULL;
576           size_t length = 0;
577           int retval = mem_iconveh (input, strlen (input),
578                                     "ISO-8859-1", "UTF-8",
579                                     handler,
580                                     offsets,
581                                     &result, &length);
582           ASSERT (retval == 0);
583           ASSERT (length == strlen (expected));
584           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
585           if (o)
586             {
587               for (i = 0; i < 37; i++)
588                 ASSERT (offsets[i] == (i < 1 ? i :
589                                        i < 12 ? i + 1 :
590                                        i < 18 ? i + 2 :
591                                        i + 3));
592               ASSERT (offsets[37] == MAGIC);
593               free (offsets);
594             }
595           free (result);
596         }
597     }
598
599   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
600   for (h = 0; h < SIZEOF (handlers); h++)
601     {
602       enum iconv_ilseq_handler handler = handlers[h];
603       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
604       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
605       for (o = 0; o < 2; o++)
606         {
607           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
608           char *result = NULL;
609           size_t length = 0;
610           int retval = mem_iconveh (input, strlen (input),
611                                     "UTF-8", "ISO-8859-1",
612                                     handler,
613                                     offsets,
614                                     &result, &length);
615           ASSERT (retval == 0);
616           ASSERT (length == strlen (expected));
617           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
618           if (o)
619             {
620               for (i = 0; i < 41; i++)
621                 ASSERT (offsets[i] == (i < 1 ? i :
622                                        i == 1 ? (size_t)(-1) :
623                                        i < 13 ? i - 1 :
624                                        i == 13 ? (size_t)(-1) :
625                                        i < 20 ? i - 2 :
626                                        i == 20 ? (size_t)(-1) :
627                                        i < 40 ? i - 3 :
628                                        (size_t)(-1)));
629               ASSERT (offsets[41] == MAGIC);
630               free (offsets);
631             }
632           free (result);
633         }
634     }
635
636   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
637   for (h = 0; h < SIZEOF (handlers); h++)
638     {
639       enum iconv_ilseq_handler handler = handlers[h];
640       static const char input[] = "Rafa\305\202 Maszkowski"; /* Rafał Maszkowski */
641       for (o = 0; o < 2; o++)
642         {
643           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
644           char *result = NULL;
645           size_t length = 0;
646           int retval = mem_iconveh (input, strlen (input),
647                                     "UTF-8", "ISO-8859-1",
648                                     handler,
649                                     offsets,
650                                     &result, &length);
651           switch (handler)
652             {
653             case iconveh_error:
654               ASSERT (retval == -1 && errno == EILSEQ);
655               ASSERT (result == NULL);
656               if (o)
657                 free (offsets);
658               break;
659             case iconveh_question_mark:
660               {
661                 static const char expected[] = "Rafa? Maszkowski";
662                 ASSERT (retval == 0);
663                 ASSERT (length == strlen (expected));
664                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
665                 if (o)
666                   {
667                     for (i = 0; i < 17; i++)
668                       ASSERT (offsets[i] == (i < 5 ? i :
669                                              i == 5 ? (size_t)(-1) :
670                                              i - 1));
671                     ASSERT (offsets[17] == MAGIC);
672                     free (offsets);
673                   }
674                 free (result);
675               }
676               break;
677             case iconveh_escape_sequence:
678               {
679                 static const char expected[] = "Rafa\\u0142 Maszkowski";
680                 ASSERT (retval == 0);
681                 ASSERT (length == strlen (expected));
682                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
683                 if (o)
684                   {
685                     for (i = 0; i < 17; i++)
686                       ASSERT (offsets[i] == (i < 5 ? i :
687                                              i == 5 ? (size_t)(-1) :
688                                              i + 4));
689                     ASSERT (offsets[17] == MAGIC);
690                     free (offsets);
691                   }
692                 free (result);
693               }
694               break;
695             }
696         }
697     }
698
699   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
700   for (h = 0; h < SIZEOF (handlers); h++)
701     {
702       enum iconv_ilseq_handler handler = handlers[h];
703       static const char input[] = "\342";
704       for (o = 0; o < 2; o++)
705         {
706           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
707           char *result = NULL;
708           size_t length = 0;
709           int retval = mem_iconveh (input, strlen (input),
710                                     "UTF-8", "ISO-8859-1",
711                                     handler,
712                                     offsets,
713                                     &result, &length);
714           ASSERT (retval == 0);
715           ASSERT (length == 0);
716           if (o)
717             {
718               ASSERT (offsets[0] == 0);
719               ASSERT (offsets[1] == MAGIC);
720               free (offsets);
721             }
722           if (result != NULL)
723             free (result);
724         }
725     }
726
727   /* ------------------------- Test str_iconveh() ------------------------- */
728
729   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
730   for (h = 0; h < SIZEOF (handlers); h++)
731     {
732       enum iconv_ilseq_handler handler = handlers[h];
733       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
734       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
735       char *result = str_iconveh (input, "ISO-8859-2", "ISO-8859-1", handler);
736       ASSERT (result != NULL);
737       ASSERT (strcmp (result, expected) == 0);
738       free (result);
739     }
740
741   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
742   for (h = 0; h < SIZEOF (handlers); h++)
743     {
744       enum iconv_ilseq_handler handler = handlers[h];
745       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
746       char *result = str_iconveh (input, "ISO-8859-2", "ISO-8859-1", handler);
747       switch (handler)
748         {
749         case iconveh_error:
750           ASSERT (result == NULL && errno == EILSEQ);
751           break;
752         case iconveh_question_mark:
753           {
754             static const char expected[] = "Rafa? Maszkowski";
755             ASSERT (result != NULL);
756             ASSERT (strcmp (result, expected) == 0);
757             free (result);
758           }
759           break;
760         case iconveh_escape_sequence:
761           {
762             static const char expected[] = "Rafa\\u0142 Maszkowski";
763             ASSERT (result != NULL);
764             ASSERT (strcmp (result, expected) == 0);
765             free (result);
766           }
767           break;
768         }
769     }
770
771   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
772   for (h = 0; h < SIZEOF (handlers); h++)
773     {
774       enum iconv_ilseq_handler handler = handlers[h];
775       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
776       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
777       char *result = str_iconveh (input, "ISO-8859-1", "UTF-8", handler);
778       ASSERT (result != NULL);
779       ASSERT (strcmp (result, expected) == 0);
780       free (result);
781     }
782
783   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
784   for (h = 0; h < SIZEOF (handlers); h++)
785     {
786       enum iconv_ilseq_handler handler = handlers[h];
787       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
788       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
789       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
790       ASSERT (result != NULL);
791       ASSERT (strcmp (result, expected) == 0);
792       free (result);
793     }
794
795   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
796   for (h = 0; h < SIZEOF (handlers); h++)
797     {
798       enum iconv_ilseq_handler handler = handlers[h];
799       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
800       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
801       switch (handler)
802         {
803         case iconveh_error:
804           ASSERT (result == NULL && errno == EILSEQ);
805           break;
806         case iconveh_question_mark:
807           {
808             static const char expected[] = "Costs: 27 ?";
809             ASSERT (result != NULL);
810             ASSERT (strcmp (result, expected) == 0);
811             free (result);
812           }
813           break;
814         case iconveh_escape_sequence:
815           {
816             static const char expected[] = "Costs: 27 \\u20AC";
817             ASSERT (result != NULL);
818             ASSERT (strcmp (result, expected) == 0);
819             free (result);
820           }
821           break;
822         }
823     }
824
825   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
826   for (h = 0; h < SIZEOF (handlers); h++)
827     {
828       enum iconv_ilseq_handler handler = handlers[h];
829       static const char input[] = "\342";
830       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
831       ASSERT (result != NULL);
832       ASSERT (strcmp (result, "") == 0);
833       free (result);
834     }
835
836 #endif
837
838   return 0;
839 }