1 /* Test of public API for GNU gettext PO files.
2    Copyright (C) 2010 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2010.
4 
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include "gettext-po.h"
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 /* Use the system functions, not the gnulib overrides in this file.  */
29 #undef fflush
30 #undef fprintf
31 #undef printf
32 #undef strdup
33 
34 #define ASSERT(expr) \
35   do                                                                         \
36     {                                                                        \
37       if (!(expr))                                                           \
38         {                                                                    \
39           fprintf (stderr, "%s:%d: assertion failed\n",                      \
40                    __FILE__, __LINE__);                                      \
41           fflush (stderr);                                                   \
42           abort ();                                                          \
43         }                                                                    \
44     }                                                                        \
45   while (0)
46 
47 static char *
xstrdup(const char * s)48 xstrdup (const char *s)
49 {
50   char *result = strdup (s);
51   if (result == NULL)
52     {
53       fprintf (stderr, "memory exhausted\n");
54       fflush (stderr);
55       exit (1);
56     }
57   return result;
58 }
59 
60 static int num_errors;
61 
62 static void
my_xerror(int severity,po_message_t message,const char * filename,size_t lineno,size_t column,int multiline_p,const char * message_text)63 my_xerror (int severity,
64            po_message_t message,
65            const char *filename, size_t lineno, size_t column,
66            int multiline_p, const char *message_text)
67 {
68   printf ("xerror called:\n  %s\n", message_text);
69   if (severity == PO_SEVERITY_FATAL_ERROR)
70     abort ();
71   num_errors++;
72 }
73 
74   /* Signal a problem that refers to two messages.
75      Similar to two calls to xerror.
76      If possible, a "..." can be appended to MESSAGE_TEXT1 and prepended to
77      MESSAGE_TEXT2.  */
78 static void
my_xerror2(int severity,po_message_t message1,const char * filename1,size_t lineno1,size_t column1,int multiline_p1,const char * message_text1,po_message_t message2,const char * filename2,size_t lineno2,size_t column2,int multiline_p2,const char * message_text2)79 my_xerror2 (int severity,
80             po_message_t message1,
81             const char *filename1, size_t lineno1, size_t column1,
82             int multiline_p1, const char *message_text1,
83             po_message_t message2,
84             const char *filename2, size_t lineno2, size_t column2,
85             int multiline_p2, const char *message_text2)
86 {
87   printf ("xerror2 called:\n  %s\n  %s\n", message_text1, message_text2);
88   if (severity == PO_SEVERITY_FATAL_ERROR)
89     abort ();
90   num_errors++;
91 }
92 
93 static const struct po_xerror_handler my_xerror_handler =
94   {
95     my_xerror,
96     my_xerror2
97   };
98 
99 int
main(int argc,char * argv[])100 main (int argc, char *argv[])
101 {
102   const char *input_filename;
103 
104   ASSERT (argc == 2);
105   input_filename = argv[1];
106 
107   /* Test LIBGETTEXTPO_VERSION.  */
108   {
109     enum { version = LIBGETTEXTPO_VERSION };
110   }
111 
112   /* Test libgettextpo_version.  */
113   ASSERT (libgettextpo_version == LIBGETTEXTPO_VERSION);
114 
115   /* Test po_file_read.  */
116   {
117     po_file_t file = po_file_read ("/nonexist/ent", &my_xerror_handler);
118     ASSERT (file == NULL);
119   }
120 
121   {
122     po_file_t file = po_file_read (input_filename, &my_xerror_handler);
123     ASSERT (file != NULL);
124 
125     /* Test po_file_domains.  */
126     {
127       const char * const * domains = po_file_domains (file);
128       ASSERT (domains[0] != NULL);
129       ASSERT (strcmp (domains[0], "messages") == 0);
130       ASSERT (domains[1] == NULL);
131     }
132 
133     /* Test po_file_write.  */
134     ASSERT (po_file_write (file, "gtpo-1-copied.po", &my_xerror_handler)
135             == file);
136 
137     /* Test po_file_domain_header.  */
138     {
139       static const char expected[] =
140         "Project-Id-Version: libgettextpo 0.18.1\n"
141         "Report-Msgid-Bugs-To: bug-gnu-gettext@gnu.org\n"
142         "POT-Creation-Date: 2010-06-04 01:57+0200\n"
143         "PO-Revision-Date: 2010-06-05 14:39+0200\n"
144         "Last-Translator: Bruno Haible <bruno@clisp.org>\n"
145         "Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
146         "Language: de\n"
147         "MIME-Version: 1.0\n"
148         "Content-Type: text/plain; charset=UTF-8\n"
149         "Content-Transfer-Encoding: 8bit\n"
150         "Plural-Forms: nplurals=2; plural=(n != 1);\n";
151       const char *header;
152 
153       header = po_file_domain_header (file, NULL);
154       ASSERT (header != NULL);
155       ASSERT (strcmp (header, expected) == 0);
156 
157       header = po_file_domain_header (file, "messages");
158       ASSERT (header != NULL);
159       ASSERT (strcmp (header, expected) == 0);
160 
161       header = po_file_domain_header (file, "anything");
162       ASSERT (header == NULL);
163 
164       /* Test po_header_field.  */
165       {
166         char *value;
167 
168         header = po_file_domain_header (file, NULL);
169 
170         value = po_header_field (header, "Report-Msgid-Bugs-To");
171         ASSERT (value != NULL);
172         ASSERT (strcmp (value, "bug-gnu-gettext@gnu.org") == 0);
173 
174         value = po_header_field (header, "X-Generator");
175         ASSERT (value == NULL);
176       }
177 
178       /* Test po_header_set_field.  */
179       {
180         char *augmented_header;
181         const char *augmented_expected;
182 
183         header = po_file_domain_header (file, NULL);
184         augmented_header =
185           po_header_set_field (header, "Last-Translator",
186                                "Karl Eichwalder <ke@suse.de>");
187         augmented_expected =
188           "Project-Id-Version: libgettextpo 0.18.1\n"
189           "Report-Msgid-Bugs-To: bug-gnu-gettext@gnu.org\n"
190           "POT-Creation-Date: 2010-06-04 01:57+0200\n"
191           "PO-Revision-Date: 2010-06-05 14:39+0200\n"
192           "Last-Translator: Karl Eichwalder <ke@suse.de>\n"
193           "Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
194           "Language: de\n"
195           "MIME-Version: 1.0\n"
196           "Content-Type: text/plain; charset=UTF-8\n"
197           "Content-Transfer-Encoding: 8bit\n"
198           "Plural-Forms: nplurals=2; plural=(n != 1);\n";
199         ASSERT (strcmp (augmented_header, augmented_expected) == 0);
200         free (augmented_header);
201 
202         /* Verify that there was no side effect.  */
203         ASSERT (strcmp (header, expected) == 0);
204         ASSERT (strcmp (po_file_domain_header (file, NULL), expected) == 0);
205 
206         header = po_file_domain_header (file, NULL);
207         augmented_header =
208           po_header_set_field (header, "X-Generator", "KBabel 1.11.4");
209         augmented_expected =
210           "Project-Id-Version: libgettextpo 0.18.1\n"
211           "Report-Msgid-Bugs-To: bug-gnu-gettext@gnu.org\n"
212           "POT-Creation-Date: 2010-06-04 01:57+0200\n"
213           "PO-Revision-Date: 2010-06-05 14:39+0200\n"
214           "Last-Translator: Bruno Haible <bruno@clisp.org>\n"
215           "Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
216           "Language: de\n"
217           "MIME-Version: 1.0\n"
218           "Content-Type: text/plain; charset=UTF-8\n"
219           "Content-Transfer-Encoding: 8bit\n"
220           "Plural-Forms: nplurals=2; plural=(n != 1);\n"
221           "X-Generator: KBabel 1.11.4\n";
222         ASSERT (strcmp (augmented_header, augmented_expected) == 0);
223         free (augmented_header);
224 
225         /* Verify that there was no side effect.  */
226         ASSERT (strcmp (header, expected) == 0);
227         ASSERT (strcmp (po_file_domain_header (file, NULL), expected) == 0);
228       }
229     }
230 
231     /* Test po_message_iterator.  */
232     {
233       po_message_iterator_t iter = po_message_iterator (file, NULL);
234       int min;
235       int max;
236 
237       /* Test po_next_message and the po_message_* accessors.  */
238       {
239         po_message_t msg = po_next_message (iter);
240         ASSERT (msg != NULL);
241         ASSERT (po_message_msgctxt (msg) == NULL);
242         ASSERT (strcmp (po_message_msgid (msg), "") == 0);
243         ASSERT (po_message_msgid_plural (msg) == NULL);
244         ASSERT (strcmp (po_message_msgstr (msg),
245                         po_file_domain_header (file, NULL)) == 0);
246         ASSERT (po_message_msgstr_plural (msg, 0) == NULL);
247         ASSERT (strcmp (po_message_comments (msg),
248                         "Test case for the libgettextpo library.\n") == 0);
249         ASSERT (strcmp (po_message_extracted_comments (msg), "") == 0);
250         ASSERT (po_message_filepos (msg, 0) == NULL);
251         ASSERT (po_message_prev_msgctxt (msg) == NULL);
252         ASSERT (po_message_prev_msgid (msg) == NULL);
253         ASSERT (po_message_prev_msgid_plural (msg) == NULL);
254         ASSERT (!po_message_is_obsolete (msg));
255         ASSERT (!po_message_is_fuzzy (msg));
256         ASSERT (!po_message_is_format (msg, "c-format"));
257         ASSERT (!po_message_is_format (msg, "java-format"));
258         ASSERT (!po_message_is_range (msg, &min, &max));
259       }
260       {
261         po_message_t msg = po_next_message (iter);
262         ASSERT (msg != NULL);
263         ASSERT (po_message_msgctxt (msg) == NULL);
264         ASSERT (strcmp (po_message_msgid (msg),
265                         "cannot restore fd %d: dup2 failed") == 0);
266         ASSERT (po_message_msgid_plural (msg) == NULL);
267         ASSERT (strcmp (po_message_msgstr (msg),
268                         "Ausgabedatei \302\273%s\302\253 kann nicht erstellt werden")
269                 == 0);
270         ASSERT (po_message_msgstr_plural (msg, 0) == NULL);
271         ASSERT (strcmp (po_message_comments (msg), "") == 0);
272         ASSERT (strcmp (po_message_extracted_comments (msg), "") == 0);
273         {
274           po_filepos_t pos = po_message_filepos (msg, 0);
275           ASSERT (pos != NULL);
276           ASSERT (strcmp (po_filepos_file (pos), "gnulib-lib/w32spawn.h") == 0);
277           ASSERT (po_filepos_start_line (pos) == 81);
278         }
279         ASSERT (po_message_filepos (msg, 1) == NULL);
280         ASSERT (po_message_prev_msgctxt (msg) == NULL);
281         ASSERT (po_message_prev_msgid (msg) == NULL);
282         ASSERT (po_message_prev_msgid_plural (msg) == NULL);
283         ASSERT (!po_message_is_obsolete (msg));
284         ASSERT (po_message_is_fuzzy (msg));
285         ASSERT (po_message_is_format (msg, "c-format"));
286         ASSERT (!po_message_is_format (msg, "java-format"));
287         ASSERT (!po_message_is_range (msg, &min, &max));
288       }
289       {
290         po_message_t msg = po_next_message (iter);
291         ASSERT (msg != NULL);
292         ASSERT (po_message_msgctxt (msg) == NULL);
293         ASSERT (strcmp (po_message_msgid (msg), "%s subprocess") == 0);
294         ASSERT (po_message_msgid_plural (msg) == NULL);
295         ASSERT (strcmp (po_message_msgstr (msg), "Subproze\303\237 %s") == 0);
296         ASSERT (po_message_msgstr_plural (msg, 0) == NULL);
297         ASSERT (strcmp (po_message_comments (msg), "") == 0);
298         ASSERT (strcmp (po_message_extracted_comments (msg), "") == 0);
299         {
300           po_filepos_t pos = po_message_filepos (msg, 0);
301           ASSERT (pos != NULL);
302           ASSERT (strcmp (po_filepos_file (pos), "gnulib-lib/wait-process.c")
303                   == 0);
304           ASSERT (po_filepos_start_line (pos) == 223);
305         }
306         {
307           po_filepos_t pos = po_message_filepos (msg, 1);
308           ASSERT (pos != NULL);
309           ASSERT (strcmp (po_filepos_file (pos), "gnulib-lib/wait-process.c")
310                   == 0);
311           ASSERT (po_filepos_start_line (pos) == 255);
312         }
313         {
314           po_filepos_t pos = po_message_filepos (msg, 2);
315           ASSERT (pos != NULL);
316           ASSERT (strcmp (po_filepos_file (pos), "gnulib-lib/wait-process.c")
317                   == 0);
318           ASSERT (po_filepos_start_line (pos) == 317);
319         }
320         ASSERT (po_message_filepos (msg, 3) == NULL);
321         ASSERT (po_message_prev_msgctxt (msg) == NULL);
322         ASSERT (po_message_prev_msgid (msg) == NULL);
323         ASSERT (po_message_prev_msgid_plural (msg) == NULL);
324         ASSERT (!po_message_is_obsolete (msg));
325         ASSERT (!po_message_is_fuzzy (msg));
326         ASSERT (po_message_is_format (msg, "c-format"));
327         ASSERT (!po_message_is_format (msg, "java-format"));
328         ASSERT (!po_message_is_range (msg, &min, &max));
329       }
330       {
331         po_message_t msg = po_next_message (iter);
332         ASSERT (msg != NULL);
333         ASSERT (strcmp (po_message_msgctxt (msg), "Lock state") == 0);
334         ASSERT (strcmp (po_message_msgid (msg), "Open") == 0);
335         ASSERT (po_message_msgid_plural (msg) == NULL);
336         ASSERT (strcmp (po_message_msgstr (msg), "Ge\303\266ffnet") == 0);
337         ASSERT (po_message_msgstr_plural (msg, 0) == NULL);
338         ASSERT (strcmp (po_message_comments (msg),
339                         "Adjektiv, kein ganzer Satz!\n") == 0);
340         ASSERT (strcmp (po_message_extracted_comments (msg),
341                         "Denote a lock's state\n") == 0);
342         ASSERT (po_message_filepos (msg, 0) == NULL);
343         ASSERT (po_message_prev_msgctxt (msg) == NULL);
344         ASSERT (po_message_prev_msgid (msg) == NULL);
345         ASSERT (po_message_prev_msgid_plural (msg) == NULL);
346         ASSERT (!po_message_is_obsolete (msg));
347         ASSERT (!po_message_is_fuzzy (msg));
348         ASSERT (!po_message_is_format (msg, "c-format"));
349         ASSERT (!po_message_is_format (msg, "java-format"));
350         ASSERT (!po_message_is_range (msg, &min, &max));
351       }
352       {
353         po_message_t msg = po_next_message (iter);
354         ASSERT (msg != NULL);
355         ASSERT (po_message_msgctxt (msg) == NULL);
356         ASSERT (strcmp (po_message_msgid (msg), "a bottle of wine") == 0);
357         ASSERT (strcmp (po_message_msgid_plural (msg),
358                         "{0,number} bottles of wine") == 0);
359         ASSERT (strcmp (po_message_msgstr (msg), "eine Flasche Wein") == 0);
360         ASSERT (strcmp (po_message_msgstr_plural (msg, 0),
361                         "eine Flasche Wein") == 0);
362         ASSERT (strcmp (po_message_msgstr_plural (msg, 1),
363                         "{0,number} Weinflaschen") == 0);
364         ASSERT (po_message_msgstr_plural (msg, 2) == NULL);
365         ASSERT (po_message_msgstr_plural (msg, 100000000) == NULL);
366         ASSERT (po_message_msgstr_plural (msg, -1) == NULL);
367         ASSERT (strcmp (po_message_comments (msg),
368                         "Franz\303\266sische Weine sind die besten der Welt.\n")
369                 == 0);
370         ASSERT (strcmp (po_message_extracted_comments (msg), "") == 0);
371         ASSERT (po_message_filepos (msg, 0) == NULL);
372         ASSERT (po_message_prev_msgctxt (msg) == NULL);
373         ASSERT (po_message_prev_msgid (msg) == NULL);
374         ASSERT (po_message_prev_msgid_plural (msg) == NULL);
375         ASSERT (!po_message_is_obsolete (msg));
376         ASSERT (!po_message_is_fuzzy (msg));
377         ASSERT (!po_message_is_format (msg, "c-format"));
378         ASSERT (po_message_is_format (msg, "java-format"));
379         ASSERT (!po_message_is_range (msg, &min, &max));
380       }
381       {
382         po_message_t msg = po_next_message (iter);
383         ASSERT (msg != NULL);
384         ASSERT (strcmp (po_message_msgctxt (msg), "Lock state") == 0);
385         ASSERT (strcmp (po_message_msgid (msg), "Closed") == 0);
386         ASSERT (po_message_msgid_plural (msg) == NULL);
387         ASSERT (strcmp (po_message_msgstr (msg), "Geschlossen") == 0);
388         ASSERT (po_message_msgstr_plural (msg, 0) == NULL);
389         ASSERT (strcmp (po_message_comments (msg), "") == 0);
390         ASSERT (strcmp (po_message_extracted_comments (msg),
391                         "Denote a lock's state\n") == 0);
392         ASSERT (po_message_filepos (msg, 0) == NULL);
393         ASSERT (po_message_prev_msgctxt (msg) == NULL);
394         ASSERT (po_message_prev_msgid (msg) == NULL);
395         ASSERT (po_message_prev_msgid_plural (msg) == NULL);
396         ASSERT (po_message_is_obsolete (msg));
397         ASSERT (!po_message_is_fuzzy (msg));
398         ASSERT (!po_message_is_format (msg, "c-format"));
399         ASSERT (!po_message_is_format (msg, "java-format"));
400         ASSERT (!po_message_is_range (msg, &min, &max));
401       }
402       {
403         po_message_t msg = po_next_message (iter);
404         ASSERT (msg == NULL);
405       }
406 
407       /* Test po_message_iterator_free.  */
408       po_message_iterator_free (iter);
409     }
410 
411     /* Test po_file_check_all.  */
412     num_errors = 0;
413     po_file_check_all (file, &my_xerror_handler);
414     ASSERT (num_errors == 0);
415 
416     /* Test po_file_free.  */
417     po_file_free (file);
418   }
419 
420   /* Test po_file_create.  */
421   {
422     po_file_t file = po_file_create ();
423 
424     {
425       po_message_iterator_t iter = po_message_iterator (file, NULL);
426 
427       /* Test po_message_insert, po_message_create, and the po_message_set_*
428          setters.  Check that the string arguments are copied.  */
429       {
430         po_message_t msg = po_message_create ();
431         {
432           char *arg = xstrdup ("");
433           po_message_set_msgid (msg, arg);
434           free (arg);
435         }
436         {
437           static const char header[] =
438             "Project-Id-Version: libgettextpo 0.18.1\n"
439             "Report-Msgid-Bugs-To: bug-gnu-gettext@gnu.org\n"
440             "POT-Creation-Date: 2010-06-04 01:57+0200\n"
441             "PO-Revision-Date: 2010-06-05 14:39+0200\n"
442             "Last-Translator: Bruno Haible <bruno@clisp.org>\n"
443             "Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
444             "Language: de\n"
445             "MIME-Version: 1.0\n"
446             "Content-Type: text/plain; charset=UTF-8\n"
447             "Content-Transfer-Encoding: 8bit\n"
448             "Plural-Forms: nplurals=2; plural=(n != 1);\n";
449           char *arg = xstrdup (header);
450           po_message_set_msgstr (msg, arg);
451           free (arg);
452         }
453         {
454           char *arg = xstrdup ("Test case for the libgettextpo library.\n");
455           po_message_set_comments (msg, arg);
456           free (arg);
457         }
458         po_message_insert (iter, msg);
459       }
460       {
461         po_message_t msg = po_message_create ();
462         {
463           char *arg = xstrdup ("cannot restore fd %d: dup2 failed");
464           po_message_set_msgid (msg, arg);
465           free (arg);
466         }
467         {
468           char *arg =
469             xstrdup ("Ausgabedatei \302\273%s\302\253 kann nicht erstellt werden");
470           po_message_set_msgstr (msg, arg);
471           free (arg);
472         }
473         {
474           char *arg = xstrdup ("gnulib-lib/w32spawn.h");
475           po_message_add_filepos (msg, arg, 81);
476           free (arg);
477         }
478         po_message_set_fuzzy (msg, 1);
479         po_message_set_format (msg, "c-format", 1);
480         po_message_insert (iter, msg);
481       }
482       {
483         po_message_t msg = po_message_create ();
484         {
485           char *arg = xstrdup ("%s subprocess");
486           po_message_set_msgid (msg, arg);
487           free (arg);
488         }
489         {
490           char *arg = xstrdup ("Subproze\303\237 %s");
491           po_message_set_msgstr (msg, arg);
492           free (arg);
493         }
494         {
495           char *arg = xstrdup ("gnulib-lib/wait-process.c");
496           po_message_add_filepos (msg, arg, 223);
497           free (arg);
498         }
499         {
500           char *arg = xstrdup ("gnulib-lib/wait-process.c");
501           po_message_add_filepos (msg, arg, 255);
502           free (arg);
503         }
504         {
505           char *arg = xstrdup ("gnulib-lib/wait-process.c");
506           po_message_add_filepos (msg, arg, 317);
507           free (arg);
508         }
509         po_message_set_format (msg, "c-format", 1);
510         po_message_insert (iter, msg);
511       }
512       {
513         po_message_t msg = po_message_create ();
514         {
515           char *arg = xstrdup ("Lock state");
516           po_message_set_msgctxt (msg, arg);
517           free (arg);
518         }
519         {
520           char *arg = xstrdup ("Open");
521           po_message_set_msgid (msg, arg);
522           free (arg);
523         }
524         {
525           char *arg = xstrdup ("Ge\303\266ffnet");
526           po_message_set_msgstr (msg, arg);
527           free (arg);
528         }
529         {
530           char *arg = xstrdup ("Adjektiv, kein ganzer Satz!\n");
531           po_message_set_comments (msg, arg);
532           free (arg);
533         }
534         {
535           char *arg = xstrdup ("Denote a lock's state\n");
536           po_message_set_extracted_comments (msg, arg);
537           free (arg);
538         }
539         po_message_insert (iter, msg);
540       }
541       {
542         po_message_t msg = po_message_create ();
543         {
544           char *arg = xstrdup ("a bottle of wine");
545           po_message_set_msgid (msg, arg);
546           free (arg);
547         }
548         {
549           char *arg = xstrdup ("{0,number} bottles of wine");
550           po_message_set_msgid_plural (msg, arg);
551           free (arg);
552         }
553         {
554           char *arg = xstrdup ("eine Flasche Wein");
555           po_message_set_msgstr_plural (msg, 0, arg);
556           free (arg);
557         }
558         {
559           char *arg = xstrdup ("{0,number} Weinflaschen");
560           po_message_set_msgstr_plural (msg, 1, arg);
561           free (arg);
562         }
563         {
564           char *arg =
565             xstrdup ("Franz\303\266sische Weine sind die besten der Welt.\n");
566           po_message_set_comments (msg, arg);
567           free (arg);
568         }
569         po_message_set_format (msg, "java-format", 1);
570         po_message_insert (iter, msg);
571       }
572       {
573         po_message_t msg = po_message_create ();
574         {
575           char *arg = xstrdup ("Lock state");
576           po_message_set_msgctxt (msg, arg);
577           free (arg);
578         }
579         {
580           char *arg = xstrdup ("Closed");
581           po_message_set_msgid (msg, arg);
582           free (arg);
583         }
584         {
585           char *arg = xstrdup ("Geschlossen");
586           po_message_set_msgstr (msg, arg);
587           free (arg);
588         }
589         {
590           char *arg = xstrdup ("Denote a lock's state\n");
591           po_message_set_extracted_comments (msg, arg);
592           free (arg);
593         }
594         po_message_set_obsolete (msg, 1);
595         po_message_insert (iter, msg);
596       }
597 
598       po_message_iterator_free (iter);
599     }
600 
601     /* Test po_file_write.  */
602     ASSERT (po_file_write (file, "gtpo-1-created.po", &my_xerror_handler)
603             == file);
604   }
605 
606   /* Test po_next_message after po_message_insert.  */
607   {
608     po_file_t file = po_file_create ();
609     {
610       po_message_iterator_t iter = po_message_iterator (file, NULL);
611       {
612         po_message_t msg = po_message_create ();
613         po_message_set_msgid (msg, "");
614         po_message_insert (iter, msg);
615       }
616       {
617         po_message_t msg = po_message_create ();
618         po_message_set_msgid (msg, "Closed");
619         po_message_insert (iter, msg);
620       }
621       po_message_iterator_free (iter);
622     }
623     {
624       po_message_iterator_t iter = po_message_iterator (file, NULL);
625       po_next_message (iter);
626       {
627         po_message_t msg = po_message_create ();
628         po_message_set_msgid (msg, "Open");
629         po_message_insert (iter, msg);
630       }
631       po_message_iterator_free (iter);
632     }
633     {
634       po_message_iterator_t iter = po_message_iterator (file, NULL);
635       {
636         po_message_t msg = po_next_message (iter);
637         ASSERT (msg != NULL);
638         ASSERT (strcmp (po_message_msgid (msg), "") == 0);
639       }
640       {
641         po_message_t msg = po_next_message (iter);
642         ASSERT (msg != NULL);
643         ASSERT (strcmp (po_message_msgid (msg), "Open") == 0);
644       }
645       {
646         po_message_t msg = po_next_message (iter);
647         ASSERT (msg != NULL);
648         ASSERT (strcmp (po_message_msgid (msg), "Closed") == 0);
649       }
650       ASSERT (po_next_message (iter) == NULL);
651       po_message_iterator_free (iter);
652     }
653     po_file_free (file);
654   }
655 
656   /* Test po_message_set_msgctxt.  */
657   {
658     po_message_t msg = po_message_create ();
659     po_message_set_msgctxt (msg, "Menu");
660     ASSERT (strcmp (po_message_msgctxt (msg), "Menu") == 0);
661     po_message_set_msgctxt (msg, "Demo");
662     ASSERT (strcmp (po_message_msgctxt (msg), "Demo") == 0);
663     po_message_set_msgctxt (msg, NULL);
664     ASSERT (po_message_msgctxt (msg) == NULL);
665   }
666 
667   /* Test po_message_set_msgid.  */
668   {
669     po_message_t msg = po_message_create ();
670     po_message_set_msgid (msg, "operation failed");
671     ASSERT (strcmp (po_message_msgid (msg), "operation failed") == 0);
672     po_message_set_msgid (msg, "operation succeeded");
673     ASSERT (strcmp (po_message_msgid (msg), "operation succeeded") == 0);
674   }
675 
676   /* Test po_message_set_msgid_plural.  */
677   {
678     po_message_t msg = po_message_create ();
679     ASSERT (po_message_msgid_plural (msg) == NULL);
680     po_message_set_msgid (msg, "an error");
681     ASSERT (strcmp (po_message_msgid (msg), "an error") == 0);
682     ASSERT (po_message_msgid_plural (msg) == NULL);
683     po_message_set_msgid_plural (msg, "%u errors");
684     ASSERT (strcmp (po_message_msgid (msg), "an error") == 0);
685     ASSERT (strcmp (po_message_msgid_plural (msg), "%u errors") == 0);
686     po_message_set_msgid_plural (msg, NULL);
687     ASSERT (strcmp (po_message_msgid (msg), "an error") == 0);
688     ASSERT (po_message_msgid_plural (msg) == NULL);
689   }
690 
691   /* Test po_message_set_msgstr.  */
692   {
693     po_message_t msg = po_message_create ();
694     ASSERT (strcmp (po_message_msgstr (msg), "") == 0);
695     po_message_set_msgid (msg, "an error");
696     ASSERT (strcmp (po_message_msgstr (msg), "") == 0);
697     po_message_set_msgstr (msg, "une erreur");
698     ASSERT (strcmp (po_message_msgstr (msg), "une erreur") == 0);
699     po_message_set_msgstr (msg, "catastrophe");
700     ASSERT (strcmp (po_message_msgstr (msg), "catastrophe") == 0);
701   }
702 
703   /* Test po_message_set_msgstr_plural.  */
704   {
705     po_message_t msg = po_message_create ();
706     po_message_set_msgid (msg, "an error");
707     po_message_set_msgid_plural (msg, "%u errors");
708     ASSERT (strcmp (po_message_msgstr_plural (msg, 0), "") == 0);
709     ASSERT (po_message_msgstr_plural (msg, 1) == NULL);
710     po_message_set_msgstr_plural (msg, 1, "%u erreurs");
711     ASSERT (strcmp (po_message_msgstr_plural (msg, 0), "") == 0);
712     ASSERT (strcmp (po_message_msgstr_plural (msg, 1), "%u erreurs") == 0);
713     ASSERT (po_message_msgstr_plural (msg, 2) == NULL);
714     po_message_set_msgstr_plural (msg, 0, "une erreur");
715     ASSERT (strcmp (po_message_msgstr_plural (msg, 0), "une erreur") == 0);
716     ASSERT (strcmp (po_message_msgstr_plural (msg, 1), "%u erreurs") == 0);
717     ASSERT (po_message_msgstr_plural (msg, 2) == NULL);
718     po_message_set_msgstr_plural (msg, 1, "des erreurs");
719     ASSERT (strcmp (po_message_msgstr_plural (msg, 0), "une erreur") == 0);
720     ASSERT (strcmp (po_message_msgstr_plural (msg, 1), "des erreurs") == 0);
721     ASSERT (po_message_msgstr_plural (msg, 2) == NULL);
722     po_message_set_msgstr_plural (msg, 2, "beaucoup d'erreurs");
723     ASSERT (strcmp (po_message_msgstr_plural (msg, 0), "une erreur") == 0);
724     ASSERT (strcmp (po_message_msgstr_plural (msg, 1), "des erreurs") == 0);
725     ASSERT (strcmp (po_message_msgstr_plural (msg, 2), "beaucoup d'erreurs")
726             == 0);
727     ASSERT (po_message_msgstr_plural (msg, 3) == NULL);
728     po_message_set_msgstr_plural (msg, 2, NULL);
729     ASSERT (strcmp (po_message_msgstr_plural (msg, 0), "une erreur") == 0);
730     ASSERT (strcmp (po_message_msgstr_plural (msg, 1), "des erreurs") == 0);
731     ASSERT (po_message_msgstr_plural (msg, 2) == NULL);
732     ASSERT (po_message_msgstr_plural (msg, 3) == NULL);
733   }
734 
735   /* Test po_message_set_comments.  */
736   {
737     po_message_t msg = po_message_create ();
738     ASSERT (strcmp (po_message_comments (msg), "") == 0);
739     po_message_set_comments (msg, "Not clear.");
740     ASSERT (strcmp (po_message_comments (msg), "Not clear.\n") == 0);
741     po_message_set_comments (msg, "To be reviewed.\n");
742     ASSERT (strcmp (po_message_comments (msg), "To be reviewed.\n") == 0);
743   }
744 
745   /* Test po_message_set_extracted_comments.  */
746   {
747     po_message_t msg = po_message_create ();
748     ASSERT (strcmp (po_message_extracted_comments (msg), "") == 0);
749     po_message_set_extracted_comments (msg, "Translate carefully.");
750     ASSERT (strcmp (po_message_extracted_comments (msg),
751                     "Translate carefully.\n") == 0);
752     po_message_set_extracted_comments (msg, "Translate very\ncarefully!\n");
753     ASSERT (strcmp (po_message_extracted_comments (msg),
754                     "Translate very\ncarefully!\n") == 0);
755   }
756 
757   /* Test po_message_add_filepos, po_message_remove_filepos.  */
758   {
759     po_message_t msg = po_message_create ();
760     ASSERT (po_message_filepos (msg, 0) == NULL);
761     po_message_remove_filepos (msg, 2);
762     ASSERT (po_message_filepos (msg, 0) == NULL);
763     {
764       char *arg = xstrdup ("hello.c");
765       po_message_add_filepos (msg, arg, 81);
766       free (arg);
767     }
768     {
769       po_filepos_t pos = po_message_filepos (msg, 0);
770       ASSERT (pos != NULL);
771       ASSERT (strcmp (po_filepos_file (pos), "hello.c") == 0);
772       ASSERT (po_filepos_start_line (pos) == 81);
773     }
774     ASSERT (po_message_filepos (msg, 1) == NULL);
775     /* Adding the same filepos once again has no effect.  */
776     {
777       char *arg = xstrdup ("hello.c");
778       po_message_add_filepos (msg, arg, 81);
779       free (arg);
780     }
781     {
782       po_filepos_t pos = po_message_filepos (msg, 0);
783       ASSERT (pos != NULL);
784       ASSERT (strcmp (po_filepos_file (pos), "hello.c") == 0);
785       ASSERT (po_filepos_start_line (pos) == 81);
786     }
787     ASSERT (po_message_filepos (msg, 1) == NULL);
788     {
789       char *arg = xstrdup ("hello.c");
790       po_message_add_filepos (msg, arg, 1024);
791       free (arg);
792     }
793     {
794       po_filepos_t pos = po_message_filepos (msg, 0);
795       ASSERT (pos != NULL);
796       ASSERT (strcmp (po_filepos_file (pos), "hello.c") == 0);
797       ASSERT (po_filepos_start_line (pos) == 81);
798     }
799     {
800       po_filepos_t pos = po_message_filepos (msg, 1);
801       ASSERT (pos != NULL);
802       ASSERT (strcmp (po_filepos_file (pos), "hello.c") == 0);
803       ASSERT (po_filepos_start_line (pos) == 1024);
804     }
805     ASSERT (po_message_filepos (msg, 2) == NULL);
806     {
807       char *arg = xstrdup ("../src/bar.c");
808       po_message_add_filepos (msg, arg, 17);
809       free (arg);
810     }
811     {
812       po_filepos_t pos = po_message_filepos (msg, 0);
813       ASSERT (pos != NULL);
814       ASSERT (strcmp (po_filepos_file (pos), "hello.c") == 0);
815       ASSERT (po_filepos_start_line (pos) == 81);
816     }
817     {
818       po_filepos_t pos = po_message_filepos (msg, 1);
819       ASSERT (pos != NULL);
820       ASSERT (strcmp (po_filepos_file (pos), "hello.c") == 0);
821       ASSERT (po_filepos_start_line (pos) == 1024);
822     }
823     {
824       po_filepos_t pos = po_message_filepos (msg, 2);
825       ASSERT (pos != NULL);
826       ASSERT (strcmp (po_filepos_file (pos), "../src/bar.c") == 0);
827       ASSERT (po_filepos_start_line (pos) == 17);
828     }
829     ASSERT (po_message_filepos (msg, 3) == NULL);
830     po_message_remove_filepos (msg, 1);
831     {
832       po_filepos_t pos = po_message_filepos (msg, 0);
833       ASSERT (pos != NULL);
834       ASSERT (strcmp (po_filepos_file (pos), "hello.c") == 0);
835       ASSERT (po_filepos_start_line (pos) == 81);
836     }
837     {
838       po_filepos_t pos = po_message_filepos (msg, 1);
839       ASSERT (pos != NULL);
840       ASSERT (strcmp (po_filepos_file (pos), "../src/bar.c") == 0);
841       ASSERT (po_filepos_start_line (pos) == 17);
842     }
843     ASSERT (po_message_filepos (msg, 2) == NULL);
844     ASSERT (po_message_filepos (msg, 3) == NULL);
845   }
846 
847   /* Test po_message_set_prev_msgctxt.  */
848   {
849     po_message_t msg = po_message_create ();
850     ASSERT (po_message_prev_msgctxt (msg) == NULL);
851     po_message_set_prev_msgctxt (msg, "Menu");
852     ASSERT (strcmp (po_message_prev_msgctxt (msg), "Menu") == 0);
853     po_message_set_prev_msgctxt (msg, "Demo");
854     ASSERT (strcmp (po_message_prev_msgctxt (msg), "Demo") == 0);
855     po_message_set_prev_msgctxt (msg, NULL);
856     ASSERT (po_message_prev_msgctxt (msg) == NULL);
857   }
858 
859   /* Test po_message_set_prev_msgid.  */
860   {
861     po_message_t msg = po_message_create ();
862     ASSERT (po_message_prev_msgid (msg) == NULL);
863     po_message_set_prev_msgid (msg, "operation failed");
864     ASSERT (strcmp (po_message_prev_msgid (msg), "operation failed") == 0);
865     po_message_set_prev_msgid (msg, "operation succeeded");
866     ASSERT (strcmp (po_message_prev_msgid (msg), "operation succeeded") == 0);
867   }
868 
869   /* Test po_message_set_prev_msgid_plural.  */
870   {
871     po_message_t msg = po_message_create ();
872     ASSERT (po_message_prev_msgid_plural (msg) == NULL);
873     po_message_set_prev_msgid (msg, "an error");
874     ASSERT (strcmp (po_message_prev_msgid (msg), "an error") == 0);
875     ASSERT (po_message_prev_msgid_plural (msg) == NULL);
876     po_message_set_prev_msgid_plural (msg, "%u errors");
877     ASSERT (strcmp (po_message_prev_msgid (msg), "an error") == 0);
878     ASSERT (strcmp (po_message_prev_msgid_plural (msg), "%u errors") == 0);
879     po_message_set_prev_msgid_plural (msg, NULL);
880     ASSERT (strcmp (po_message_prev_msgid (msg), "an error") == 0);
881     ASSERT (po_message_prev_msgid_plural (msg) == NULL);
882   }
883 
884   /* Test po_message_set_obsolete.  */
885   {
886     po_message_t msg = po_message_create ();
887     ASSERT (!po_message_is_obsolete (msg));
888     po_message_set_obsolete (msg, 1);
889     ASSERT (po_message_is_obsolete (msg));
890     po_message_set_obsolete (msg, 1);
891     ASSERT (po_message_is_obsolete (msg));
892     po_message_set_obsolete (msg, 0);
893     ASSERT (!po_message_is_obsolete (msg));
894   }
895 
896   /* Test po_message_set_fuzzy.  */
897   {
898     po_message_t msg = po_message_create ();
899     ASSERT (!po_message_is_fuzzy (msg));
900     po_message_set_fuzzy (msg, 1);
901     ASSERT (po_message_is_fuzzy (msg));
902     po_message_set_fuzzy (msg, 1);
903     ASSERT (po_message_is_fuzzy (msg));
904     po_message_set_fuzzy (msg, 0);
905     ASSERT (!po_message_is_fuzzy (msg));
906   }
907 
908   /* Test po_message_set_format.  */
909   {
910     po_message_t msg = po_message_create ();
911     ASSERT (!po_message_is_format (msg, "c-format"));
912     ASSERT (!po_message_is_format (msg, "java-format"));
913     ASSERT (!po_message_is_format (msg, "xyzzy-format"));
914     po_message_set_format (msg, "c-format", 1);
915     ASSERT (po_message_is_format (msg, "c-format"));
916     ASSERT (!po_message_is_format (msg, "java-format"));
917     ASSERT (!po_message_is_format (msg, "xyzzy-format"));
918     po_message_set_format (msg, "c-format", 1);
919     ASSERT (po_message_is_format (msg, "c-format"));
920     ASSERT (!po_message_is_format (msg, "java-format"));
921     ASSERT (!po_message_is_format (msg, "xyzzy-format"));
922     po_message_set_format (msg, "java-format", 1);
923     ASSERT (po_message_is_format (msg, "c-format"));
924     ASSERT (po_message_is_format (msg, "java-format"));
925     ASSERT (!po_message_is_format (msg, "xyzzy-format"));
926     po_message_set_format (msg, "c-format", 0);
927     ASSERT (!po_message_is_format (msg, "c-format"));
928     ASSERT (po_message_is_format (msg, "java-format"));
929     ASSERT (!po_message_is_format (msg, "xyzzy-format"));
930     po_message_set_format (msg, "xyzzy-format", 1);
931     ASSERT (!po_message_is_format (msg, "c-format"));
932     ASSERT (po_message_is_format (msg, "java-format"));
933     ASSERT (!po_message_is_format (msg, "xyzzy-format"));
934   }
935 
936   /* Test po_message_set_range.  */
937   {
938     po_message_t msg = po_message_create ();
939     int min;
940     int max;
941     ASSERT (!po_message_is_range (msg, &min, &max));
942     po_message_set_range (msg, 1, 100);
943     ASSERT (po_message_is_range (msg, &min, &max));
944     ASSERT (min == 1);
945     ASSERT (max == 100);
946     po_message_set_range (msg, 5, 1000);
947     ASSERT (po_message_is_range (msg, &min, &max));
948     ASSERT (min == 5);
949     ASSERT (max == 1000);
950     po_message_set_range (msg, -1, -1);
951     ASSERT (!po_message_is_range (msg, &min, &max));
952   }
953 
954   /* Test po_message_check_all.  */
955   {
956     po_file_t file = po_file_create ();
957     po_message_iterator_t iter = po_message_iterator (file, NULL);
958     {
959       po_message_t msg = po_message_create ();
960       po_message_set_msgid (msg, "cannot write %s");
961       num_errors = 0;
962       po_message_check_all (msg, iter, &my_xerror_handler);
963       ASSERT (num_errors == 0);
964     }
965     {
966       po_message_t msg = po_message_create ();
967       po_message_set_msgid (msg, "an error");
968       po_message_set_msgid_plural (msg, "%u errors\n");
969       num_errors = 0;
970       po_message_check_all (msg, iter, &my_xerror_handler);
971       ASSERT (num_errors == 0);
972       po_message_set_msgstr (msg, "Fehler");
973       num_errors = 0;
974       po_message_check_all (msg, iter, &my_xerror_handler);
975       ASSERT (num_errors == 2);
976     }
977     {
978       po_message_t msg = po_message_create ();
979       po_message_set_msgid (msg, "");
980       po_message_set_msgstr (msg,
981         "Content-Type: text/plain; charset=CHARSET\n"
982         "Content-Transfer-Encoding: 8bit\n");
983       num_errors = 0;
984       po_message_check_all (msg, iter, &my_xerror_handler);
985       ASSERT (num_errors == 7);
986     }
987     {
988       po_message_t msg = po_message_create ();
989       po_message_set_msgid (msg, "encountered %d errors");
990       po_message_set_format (msg, "c-format", 1);
991       po_message_set_msgstr (msg, "rencontr\303\251 %ld erreurs");
992       num_errors = 0;
993       po_message_check_all (msg, iter, &my_xerror_handler);
994       ASSERT (num_errors == 1);
995     }
996     po_message_iterator_free (iter);
997     po_file_free (file);
998   }
999 
1000   /* Test po_message_check_format.  */
1001   {
1002     po_message_t msg = po_message_create ();
1003     po_message_set_msgid (msg, "encountered %d errors");
1004     po_message_set_format (msg, "c-format", 1);
1005     po_message_set_msgstr (msg, "rencontr\303\251 %ld erreurs");
1006     num_errors = 0;
1007     po_message_check_format (msg, &my_xerror_handler);
1008     ASSERT (num_errors == 1);
1009   }
1010 
1011   /* Test po_format_list.  */
1012   {
1013     const char * const *format_types = po_format_list ();
1014 
1015     ASSERT (strcmp (format_types[0], "c-format") == 0);
1016 
1017     while (*format_types != NULL)
1018       format_types++;
1019   }
1020 
1021   /* Test po_format_pretty_name.  */
1022   ASSERT (strcmp (po_format_pretty_name ("c-format"), "C") == 0);
1023   ASSERT (strcmp (po_format_pretty_name ("csharp-format"), "C#") == 0);
1024   ASSERT (po_format_pretty_name ("xyzzy-format") == NULL);
1025 
1026   return 0;
1027 }
1028