chiark / gitweb /
gpg agent threading bugs: Add some `xxx' comments.
[gnupg2.git] / common / t-stringhelp.c
1 /* t-stringhelp.c - Regression tests for stringhelp.c
2  * Copyright (C) 2007 Free Software Foundation, Inc.
3  *               2015  g10 Code GmbH
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify it
8  * under the terms of either
9  *
10  *   - the GNU Lesser General Public License as published by the Free
11  *     Software Foundation; either version 3 of the License, or (at
12  *     your option) any later version.
13  *
14  * or
15  *
16  *   - the GNU General Public License as published by the Free
17  *     Software Foundation; either version 2 of the License, or (at
18  *     your option) any later version.
19  *
20  * or both in parallel, as here.
21  *
22  * GnuPG is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * General Public License for more details.
26  *
27  * You should have received a copies of the GNU General Public License
28  * and the GNU Lesser General Public License along with this program;
29  * if not, see <https://www.gnu.org/licenses/>.
30  */
31
32 #include <config.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <assert.h>
38 #ifdef HAVE_PWD_H
39 # include <pwd.h>
40 #endif
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <limits.h>
44
45 #include "t-support.h"
46 #include "stringhelp.h"
47
48
49 static char *home_buffer;
50
51
52 const char *
53 gethome (void)
54 {
55   if (!home_buffer)
56     {
57       char *home = getenv("HOME");
58
59       if(home)
60         home_buffer = xstrdup (home);
61 #if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H)
62       else
63         {
64           struct passwd *pwd;
65
66           pwd = getpwuid (getuid());
67           if (pwd)
68             home_buffer = xstrdup (pwd->pw_dir);
69         }
70 #endif
71     }
72   return home_buffer;
73 }
74
75
76 static char *
77 mygetcwd (void)
78 {
79   char *buffer;
80   size_t size = 100;
81
82   for (;;)
83     {
84       buffer = xmalloc (size+1);
85 #ifdef HAVE_W32CE_SYSTEM
86       strcpy (buffer, "/");  /* Always "/".  */
87       return buffer;
88 #else
89       if (getcwd (buffer, size) == buffer)
90         return buffer;
91       xfree (buffer);
92       if (errno != ERANGE)
93         {
94           fprintf (stderr,"error getting current cwd: %s\n",
95                    strerror (errno));
96           exit (2);
97         }
98       size *= 2;
99 #endif
100     }
101 }
102
103
104 static void
105 test_percent_escape (void)
106 {
107   char *result;
108   static struct {
109     const char *extra;
110     const char *value;
111     const char *expected;
112   } tests[] =
113     {
114       { NULL, "", "" },
115       { NULL, "%", "%25" },
116       { NULL, "%%", "%25%25" },
117       { NULL, " %", " %25" },
118       { NULL, ":", "%3a" },
119       { NULL, " :", " %3a" },
120       { NULL, ": ", "%3a " },
121       { NULL, " : ", " %3a " },
122       { NULL, "::", "%3a%3a" },
123       { NULL, ": :", "%3a %3a" },
124       { NULL, "%:", "%25%3a" },
125       { NULL, ":%", "%3a%25" },
126       { "\\\n:", ":%", "%3a%25" },
127       { "\\\n:", "\\:%", "%5c%3a%25" },
128       { "\\\n:", "\n:%", "%0a%3a%25" },
129       { "\\\n:", "\xff:%", "\xff%3a%25" },
130       { "\\\n:", "\xfe:%", "\xfe%3a%25" },
131       { "\\\n:", "\x01:%", "\x01%3a%25" },
132       { "\x01",  "\x01:%", "%01%3a%25" },
133       { "\xfe",  "\xfe:%", "%fe%3a%25" },
134       { "\xfe",  "\xff:%", "\xff%3a%25" },
135
136       { NULL, NULL, NULL }
137     };
138   int testno;
139
140   result = percent_escape (NULL, NULL);
141   if (result)
142     fail (0);
143   for (testno=0; tests[testno].value; testno++)
144     {
145       result = percent_escape (tests[testno].value, tests[testno].extra);
146       if (!result)
147         fail (testno);
148       else if (strcmp (result, tests[testno].expected))
149         fail (testno);
150       xfree (result);
151     }
152
153 }
154
155
156 static void
157 test_compare_filenames (void)
158 {
159   struct {
160     const char *a;
161     const char *b;
162     int result;
163   } tests[] = {
164     { "", "", 0 },
165     { "", "a", -1 },
166     { "a", "", 1 },
167     { "a", "a", 0 },
168     { "a", "aa", -1 },
169     { "aa", "a", 1 },
170     { "a",  "b", -1  },
171
172 #ifdef HAVE_W32_SYSTEM
173     { "a", "A", 0 },
174     { "A", "a", 0 },
175     { "foo/bar", "foo\\bar", 0 },
176     { "foo\\bar", "foo/bar", 0 },
177     { "foo\\", "foo/", 0 },
178     { "foo/", "foo\\", 0 },
179 #endif /*HAVE_W32_SYSTEM*/
180     { NULL, NULL, 0}
181   };
182   int testno, result;
183
184   for (testno=0; tests[testno].a; testno++)
185     {
186       result = compare_filenames (tests[testno].a, tests[testno].b);
187       result = result < 0? -1 : result > 0? 1 : 0;
188       if (result != tests[testno].result)
189         fail (testno);
190     }
191 }
192
193
194 static void
195 test_strconcat (void)
196 {
197   char *out;
198
199   out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
200                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
201                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
202                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
203                    "1", "2", "3", "4", "5", "6", "7", NULL);
204   if (!out)
205     fail (0);
206   else
207     xfree (out);
208   out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
209                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
210                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
211                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
212                    "1", "2", "3", "4", "5", "6", "7", "8", NULL);
213   if (out)
214     fail (0);
215   else if (errno != EINVAL)
216     fail (0);
217
218   out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
219                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
220                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
221                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
222                    "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL);
223   if (out)
224     fail (0);
225   else if (errno != EINVAL)
226     fail (0);
227   xfree (out);
228
229 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute.  */
230   out = strconcat (NULL);
231   if (!out || *out)
232     fail (1);
233 #endif
234   out = strconcat (NULL, NULL);
235   if (!out || *out)
236     fail (1);
237   xfree (out);
238
239   out = strconcat ("", NULL);
240   if (!out || *out)
241     fail (1);
242   xfree (out);
243
244   out = strconcat ("", "", NULL);
245   if (!out || *out)
246     fail (2);
247   xfree (out);
248
249   out = strconcat ("a", "b", NULL);
250   if (!out || strcmp (out, "ab"))
251     fail (3);
252   xfree (out);
253   out = strconcat ("a", "b", "c", NULL);
254   if (!out || strcmp (out, "abc"))
255     fail (3);
256   xfree (out);
257
258   out = strconcat ("a", "b", "cc", NULL);
259   if (!out || strcmp (out, "abcc"))
260     fail (4);
261   xfree (out);
262   out = strconcat ("a1", "b1", "c1", NULL);
263   if (!out || strcmp (out, "a1b1c1"))
264     fail (4);
265   xfree (out);
266
267   out = strconcat ("", " long b ", "", "--even-longer--", NULL);
268   if (!out || strcmp (out, " long b --even-longer--"))
269     fail (5);
270   xfree (out);
271
272   out = strconcat ("", " long b ", "", "--even-longer--", NULL);
273   if (!out || strcmp (out, " long b --even-longer--"))
274     fail (5);
275   xfree (out);
276 }
277
278 static void
279 test_xstrconcat (void)
280 {
281   char *out;
282
283   out = xstrconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
284                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
285                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
286                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
287                    "1", "2", "3", "4", "5", "6", "7", NULL);
288   if (!out)
289     fail (0);
290   xfree (out);
291
292 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute.  */
293   out = xstrconcat (NULL);
294   if (!out)
295     fail (1);
296 #endif
297   out = xstrconcat (NULL, NULL);
298   if (!out)
299     fail (1);
300   xfree (out);
301
302   out = xstrconcat ("", NULL);
303   if (!out || *out)
304     fail (1);
305   xfree (out);
306
307   out = xstrconcat ("", "", NULL);
308   if (!out || *out)
309     fail (2);
310   xfree (out);
311
312   out = xstrconcat ("a", "b", NULL);
313   if (!out || strcmp (out, "ab"))
314     fail (3);
315   xfree (out);
316   out = xstrconcat ("a", "b", "c", NULL);
317   if (!out || strcmp (out, "abc"))
318     fail (3);
319   xfree (out);
320
321   out = xstrconcat ("a", "b", "cc", NULL);
322   if (!out || strcmp (out, "abcc"))
323     fail (4);
324   xfree (out);
325   out = xstrconcat ("a1", "b1", "c1", NULL);
326   if (!out || strcmp (out, "a1b1c1"))
327     fail (4);
328   xfree (out);
329
330   out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
331   if (!out || strcmp (out, " long b --even-longer--"))
332     fail (5);
333   xfree (out);
334
335   out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
336   if (!out || strcmp (out, " long b --even-longer--"))
337     fail (5);
338   xfree (out);
339 }
340
341
342 static void
343 test_make_filename_try (void)
344 {
345   char *out;
346   const char *home = gethome ();
347   size_t homelen = home? strlen (home):0;
348
349   out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
350                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
351                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
352                            "1", "2", "3", NULL);
353   if (out)
354     fail (0);
355   else if (errno != EINVAL)
356     fail (0);
357   xfree (out);
358   out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
359                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
360                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
361                            "1", "2", "3", "4", NULL);
362   if (out)
363     fail (0);
364   else if (errno != EINVAL)
365     fail (0);
366   xfree (out);
367
368   out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
369                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
370                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
371                            "1", "2", NULL);
372   if (!out || strcmp (out,
373                       "1/2/3/4/5/6/7/8/9/10/"
374                       "1/2/3/4/5/6/7/8/9/10/"
375                       "1/2/3/4/5/6/7/8/9/10/"
376                       "1/2"))
377     fail (0);
378   xfree (out);
379
380   out = make_filename_try ("foo", "~/bar", "baz/cde", NULL);
381   if (!out || strcmp (out, "foo/~/bar/baz/cde"))
382     fail (1);
383   xfree (out);
384
385   out = make_filename_try ("foo", "~/bar", "baz/cde/", NULL);
386   if (!out || strcmp (out, "foo/~/bar/baz/cde/"))
387     fail (1);
388   xfree (out);
389
390   out = make_filename_try ("/foo", "~/bar", "baz/cde/", NULL);
391   if (!out || strcmp (out, "/foo/~/bar/baz/cde/"))
392     fail (1);
393   xfree (out);
394
395   out = make_filename_try ("//foo", "~/bar", "baz/cde/", NULL);
396   if (!out || strcmp (out, "//foo/~/bar/baz/cde/"))
397     fail (1);
398   xfree (out);
399
400   out = make_filename_try ("", "~/bar", "baz/cde", NULL);
401   if (!out || strcmp (out, "/~/bar/baz/cde"))
402     fail (1);
403   xfree (out);
404
405
406   out = make_filename_try ("~/foo", "bar", NULL);
407   if (!out)
408     fail (2);
409   else if (home)
410     {
411       if (strlen (out) < homelen + 7)
412         fail (2);
413       else if (strncmp (out, home, homelen))
414         fail (2);
415       else if (strcmp (out+homelen, "/foo/bar"))
416         fail (2);
417     }
418   else
419     {
420       if (strcmp (out, "~/foo/bar"))
421         fail (2);
422     }
423   xfree (out);
424
425   out = make_filename_try ("~", "bar", NULL);
426   if (!out)
427     fail (2);
428   else if (home)
429     {
430       if (strlen (out) < homelen + 3)
431         fail (2);
432       else if (strncmp (out, home, homelen))
433         fail (2);
434       else if (strcmp (out+homelen, "/bar"))
435         fail (2);
436     }
437   else
438     {
439       if (strcmp (out, "~/bar"))
440         fail (2);
441     }
442   xfree (out);
443 }
444
445
446 static void
447 test_make_absfilename_try (void)
448 {
449   char *out;
450   char *cwd = mygetcwd ();
451   size_t cwdlen = strlen (cwd);
452
453   out = make_absfilename_try ("foo", "bar", NULL);
454   if (!out)
455     fail (0);
456   else if (strlen (out) < cwdlen + 7)
457     fail (0);
458   else if (strncmp (out, cwd, cwdlen))
459     fail (0);
460   else if (strcmp (out+cwdlen, "/foo/bar"))
461     fail (0);
462   xfree (out);
463
464   out = make_absfilename_try ("./foo", NULL);
465   if (!out)
466     fail (1);
467   else if (strlen (out) < cwdlen + 5)
468     fail (1);
469   else if (strncmp (out, cwd, cwdlen))
470     fail (1);
471   else if (strcmp (out+cwdlen, "/./foo"))
472     fail (1);
473   xfree (out);
474
475   out = make_absfilename_try (".", NULL);
476   if (!out)
477     fail (2);
478   else if (strlen (out) < cwdlen)
479     fail (2);
480   else if (strncmp (out, cwd, cwdlen))
481     fail (2);
482   else if (strcmp (out+cwdlen, ""))
483     fail (2);
484   xfree (out);
485
486   xfree (cwd);
487 }
488
489 static void
490 test_strsplit (void)
491 {
492   struct {
493     const char *s;
494     char delim;
495     char replacement;
496     const char *fields_expected[10];
497   } tv[] = {
498     {
499       "a:bc:cde:fghi:jklmn::foo:", ':', '\0',
500       { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
501     },
502     {
503       ",a,bc,,def,", ',', '!',
504       { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL }
505     },
506     {
507       "", ':', ',',
508       { "", NULL }
509     }
510   };
511
512   int tidx;
513
514   for (tidx = 0; tidx < DIM(tv); tidx++)
515     {
516       char *s2;
517       int field_count;
518       char **fields;
519       int field_count_expected;
520       int i;
521
522       /* Count the fields.  */
523       for (field_count_expected = 0;
524            tv[tidx].fields_expected[field_count_expected];
525            field_count_expected ++)
526         ;
527
528       /* We need to copy s since strsplit modifies it in place.  */
529       s2 = xstrdup (tv[tidx].s);
530       fields = strsplit (s2, tv[tidx].delim, tv[tidx].replacement,
531                          &field_count);
532
533       if (field_count != field_count_expected)
534         fail (tidx * 1000);
535
536       for (i = 0; i < field_count_expected; i ++)
537         if (strcmp (tv[tidx].fields_expected[i], fields[i]) != 0)
538           {
539             printf ("For field %d, expected '%s', but got '%s'\n",
540                     i, tv[tidx].fields_expected[i], fields[i]);
541             fail (tidx * 1000 + i + 1);
542           }
543
544       xfree (fields);
545       xfree (s2);
546     }
547 }
548
549
550
551 static void
552 test_strtokenize (void)
553 {
554   struct {
555     const char *s;
556     const char *delim;
557     const char *fields_expected[10];
558   } tv[] = {
559     {
560       "", ":",
561       { "", NULL }
562     },
563     {
564       "a", ":",
565       { "a", NULL }
566     },
567     {
568       ":", ":",
569       { "", "", NULL }
570     },
571     {
572       "::", ":",
573       { "", "", "", NULL }
574     },
575     {
576       "a:b:c", ":",
577       { "a", "b", "c", NULL }
578     },
579     {
580       "a:b:", ":",
581       { "a", "b", "", NULL }
582     },
583     {
584       "a:b", ":",
585       { "a", "b", NULL }
586     },
587     {
588       "aa:b:cd", ":",
589       { "aa", "b", "cd", NULL }
590     },
591     {
592       "aa::b:cd", ":",
593       { "aa", "", "b", "cd", NULL }
594     },
595     {
596       "::b:cd", ":",
597       { "", "", "b", "cd", NULL }
598     },
599     {
600       "aa:   : b:cd ", ":",
601       { "aa", "", "b", "cd", NULL }
602     },
603     {
604       "  aa:   : b:  cd ", ":",
605       { "aa", "", "b", "cd", NULL }
606     },
607     {
608       "  ", ":",
609       { "", NULL }
610     },
611     {
612       "  :", ":",
613       { "", "", NULL }
614     },
615     {
616       "  : ", ":",
617       { "", "", NULL }
618     },
619     {
620       ": ", ":",
621       { "", "", NULL }
622     },
623     {
624       ": x ", ":",
625       { "", "x", NULL }
626     },
627     {
628       "a:bc:cde:fghi:jklmn::foo:", ":",
629       { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
630     },
631     {
632       ",a,bc,,def,", ",",
633       { "", "a", "bc", "", "def", "", NULL }
634     },
635     {
636       " a ", " ",
637       { "", "a", "", NULL }
638     },
639     {
640       " ", " ",
641       { "", "", NULL }
642     },
643     {
644       "", " ",
645       { "", NULL }
646     }
647   };
648
649   int tidx;
650
651   for (tidx = 0; tidx < DIM(tv); tidx++)
652     {
653       char **fields;
654       int field_count;
655       int field_count_expected;
656       int i;
657
658       for (field_count_expected = 0;
659            tv[tidx].fields_expected[field_count_expected];
660            field_count_expected ++)
661         ;
662
663       fields = strtokenize (tv[tidx].s, tv[tidx].delim);
664       if (!fields)
665         fail (tidx * 1000);
666       else
667         {
668           for (field_count = 0; fields[field_count]; field_count++)
669             ;
670           if (field_count != field_count_expected)
671             fail (tidx * 1000);
672           else
673             {
674               for (i = 0; i < field_count_expected; i++)
675                 if (strcmp (tv[tidx].fields_expected[i], fields[i]))
676                   {
677                     printf ("For field %d, expected '%s', but got '%s'\n",
678                             i, tv[tidx].fields_expected[i], fields[i]);
679                     fail (tidx * 1000 + i + 1);
680                   }
681             }
682           }
683
684       xfree (fields);
685     }
686 }
687
688
689 static void
690 test_split_fields (void)
691 {
692   struct {
693     const char *s;
694     int nfields;
695     const char *fields_expected[10];
696   } tv[] = {
697     {
698       "a bc cde fghi jklmn   foo ", 6,
699       { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL }
700     },
701     {
702       " a bc  def ", 2,
703       { "a", "bc", "def", NULL }
704     },
705     {
706       " a bc  def ", 3,
707       { "a", "bc", "def", NULL }
708     },
709     {
710       " a bc  def ", 4,
711       { "a", "bc", "def", NULL }
712     },
713     {
714       "", 0,
715       { NULL }
716     }
717   };
718
719   int tidx;
720   char *fields[10];
721   int field_count_expected, nfields, field_count, i;
722   char *s2;
723
724   for (tidx = 0; tidx < DIM(tv); tidx++)
725     {
726       nfields = tv[tidx].nfields;
727       assert (nfields <= DIM (fields));
728
729       /* Count the fields.  */
730       for (field_count_expected = 0;
731            tv[tidx].fields_expected[field_count_expected];
732            field_count_expected ++)
733         ;
734       if (field_count_expected > nfields)
735         field_count_expected = nfields;
736
737       /* We need to copy s since split_fields modifies in place.  */
738       s2 = xstrdup (tv[tidx].s);
739       field_count = split_fields (s2, fields, nfields);
740
741       if (field_count != field_count_expected)
742         {
743           printf ("%s: tidx %d: expected %d, got %d\n",
744                   __func__, tidx, field_count_expected, field_count);
745           fail (tidx * 1000);
746         }
747       else
748         {
749           for (i = 0; i < field_count_expected; i ++)
750             if (strcmp (tv[tidx].fields_expected[i], fields[i]))
751               {
752                 printf ("%s: tidx %d, field %d: expected '%s', got '%s'\n",
753                         __func__,
754                         tidx, i, tv[tidx].fields_expected[i], fields[i]);
755                 fail (tidx * 1000 + i + 1);
756               }
757         }
758
759       xfree (s2);
760     }
761 }
762
763
764 static char *
765 stresc (char *s)
766 {
767   char *p;
768   int l = strlen (s) + 1;
769
770   for (p = s; *p; p ++)
771     if (*p == '\n')
772       l ++;
773
774   p = xmalloc (l);
775   for (l = 0; *s; s ++, l ++)
776     {
777       if (*s == ' ')
778         p[l] = '_';
779       else if (*p == '\n')
780         {
781           p[l ++] = '\\';
782           p[l ++] = 'n';
783           p[l] = '\n';
784         }
785       else
786         p[l] = *s;
787     }
788   p[l] = *s;
789
790   return p;
791 }
792
793
794 static void
795 test_format_text (void)
796 {
797   struct test
798   {
799     int target_cols, max_cols;
800     char *input;
801     char *expected;
802   };
803
804   struct test tests[] = {
805     {
806       10, 12,
807       "",
808       "",
809     },
810     {
811       10, 12,
812       " ",
813       "",
814     },
815     {
816       10, 12,
817       "  ",
818       "",
819     },
820     {
821       10, 12,
822       " \n ",
823       " \n",
824     },
825     {
826       10, 12,
827       " \n  \n ",
828       " \n  \n",
829     },
830     {
831       10, 12,
832       "0123456789 0123456789 0",
833       "0123456789\n0123456789\n0",
834     },
835     {
836       10, 12,
837       "   0123456789   0123456789   0  ",
838       "   0123456789\n0123456789\n0",
839     },
840     {
841       10, 12,
842       "01 34 67 90 23 56  89 12 45 67 89 1",
843       "01 34 67\n90 23 56\n89 12 45\n67 89 1"
844     },
845     {
846       10, 12,
847       "01 34 67 90 23 56  89 12 45 67 89 1",
848       "01 34 67\n90 23 56\n89 12 45\n67 89 1"
849     },
850     {
851       72, 80,
852       "Warning: if you think you've seen more than 10 messages "
853       "signed by this key, then this key might be a forgery!  "
854       "Carefully examine the email address for small variations "
855       "(e.g., additional white space).  If the key is suspect, "
856       "then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as being bad.\n",
857       "Warning: if you think you've seen more than 10 messages signed by this\n"
858       "key, then this key might be a forgery!  Carefully examine the email\n"
859       "address for small variations (e.g., additional white space).  If the key\n"
860       "is suspect, then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as\n"
861       "being bad.\n"
862
863     },
864     {
865       72, 80,
866       "Normally, there is only a single key associated with an email "
867       "address.  However, people sometimes generate a new key if "
868       "their key is too old or they think it might be compromised.  "
869       "Alternatively, a new key may indicate a man-in-the-middle "
870       "attack!  Before accepting this key, you should talk to or "
871       "call the person to make sure this new key is legitimate.",
872       "Normally, there is only a single key associated with an email "
873       "address.\nHowever, people sometimes generate a new key if "
874       "their key is too old or\nthey think it might be compromised.  "
875       "Alternatively, a new key may indicate\na man-in-the-middle "
876       "attack!  Before accepting this key, you should talk\nto or "
877       "call the person to make sure this new key is legitimate.",
878     }
879   };
880
881   int i;
882   int failed = 0;
883
884   for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i ++)
885     {
886       struct test *test = &tests[i];
887       char *result =
888         format_text (test->input, 0, test->target_cols, test->max_cols);
889       if (strcmp (result, test->expected) != 0)
890         {
891           printf ("%s: Test #%d failed.\nExpected: '%s'\nResult: '%s'\n",
892                   __func__, i + 1, stresc (test->expected), stresc (result));
893           failed ++;
894         }
895       xfree (result);
896     }
897
898   if (failed)
899     fail(0);
900 }
901
902
903 static void
904 test_compare_version_strings (void)
905 {
906   struct { const char *a; const char *b; int okay; } tests[] = {
907     { "1.0.0",   "1.0.0", 0 },
908     { "1.0.0-",  "1.0.0", 1 },
909     { "1.0.0-1", "1.0.0", 1 },
910     { "1.0.0.1", "1.0.0", 1 },
911     { "1.0.0",   "1.0.1", -1 },
912     { "1.0.0-",  "1.0.1", -1 },
913     { "1.0.0-1", "1.0.1", -1 },
914     { "1.0.0.1", "1.0.1", -1 },
915     { "1.0.0",   "1.1.0", -1 },
916     { "1.0.0-",  "1.1.0", -1 },
917     { "1.0.0-1", "1.1.0", -1 },
918     { "1.0.0.1", "1.1.0", -1 },
919
920     { "1.0.0",   "1.0.0-", -1 },
921     { "1.0.0",   "1.0.0-1", -1 },
922     { "1.0.0",   "1.0.0.1", -1 },
923     { "1.1.0",   "1.0.0", 1 },
924     { "1.1.1",   "1.1.0", 1 },
925     { "1.1.2",   "1.1.2", 0 },
926     { "1.1.2",   "1.0.2", 1 },
927     { "1.1.2",   "0.0.2", 1 },
928     { "1.1.2",   "1.1.3", -1 },
929
930     { "0.99.1",  "0.9.9", 1 },
931     { "0.9.1",   "0.91.0", -1 },
932
933     { "1.5.3",   "1.5",  1 },
934     { "1.5.0",   "1.5",  0 },
935     { "1.4.99",  "1.5",  -1 },
936     { "1.5",     "1.4.99",  1 },
937     { "1.5",     "1.5.0",  0 },
938     { "1.5",     "1.5.1",  -1 },
939
940     { "1.5.3-x17",   "1.5-23",  1 },
941
942     { "1.5.3a",   "1.5.3",  1 },
943     { "1.5.3a",   "1.5.3b",  -1 },
944
945     { "3.1.4-ab", "3.1.4-ab", 0 },
946     { "3.1.4-ab", "3.1.4-ac", -1 },
947     { "3.1.4-ac", "3.1.4-ab", 1 },
948     { "3.1.4-ab", "3.1.4-abb", -1 },
949     { "3.1.4-abb", "3.1.4-ab", 1 },
950
951     { "",       "",   INT_MIN },
952     { NULL,     "",   INT_MIN },
953     { "1.2.3",  "",   INT_MIN },
954     { "1.2.3",  "2",  INT_MIN },
955
956     /* Test cases for validity of A.  */
957     { "",      NULL, INT_MIN },
958     { "1",     NULL, INT_MIN },
959     { "1.",    NULL, 0       },
960     { "1.0",   NULL, 0       },
961     { "1.0.",  NULL, 0       },
962     { "a1.2",  NULL, INT_MIN },
963     { NULL,    NULL, INT_MIN }
964   };
965   int idx;
966   int res;
967
968   for (idx=0; idx < DIM(tests); idx++)
969     {
970       res = compare_version_strings (tests[idx].a, tests[idx].b);
971       /* printf ("test %d: '%s'  '%s'  %d  ->  %d\n", */
972       /*         idx, tests[idx].a, tests[idx].b, tests[idx].okay, res); */
973       if (res != tests[idx].okay)
974         fail (idx);
975     }
976 }
977
978
979 int
980 main (int argc, char **argv)
981 {
982   (void)argc;
983   (void)argv;
984
985   test_percent_escape ();
986   test_compare_filenames ();
987   test_strconcat ();
988   test_xstrconcat ();
989   test_make_filename_try ();
990   test_make_absfilename_try ();
991   test_strsplit ();
992   test_strtokenize ();
993   test_split_fields ();
994   test_compare_version_strings ();
995   test_format_text ();
996
997   xfree (home_buffer);
998   return !!errcount;
999 }