common: Add new helper function, strsplit.
[gnupg.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 JNLIB, which is a subsystem of GnuPG.
6  *
7  * JNLIB 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  * JNLIB 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 <http://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 #ifdef HAVE_PWD_H
38 # include <pwd.h>
39 #endif
40 #include <unistd.h>
41 #include <sys/types.h>
42
43 #include "stringhelp.h"
44
45 #include "t-support.h"
46
47
48 static char *home_buffer;
49
50
51 const char *
52 gethome (void)
53 {
54   if (!home_buffer)
55     {
56       char *home = getenv("HOME");
57
58       if(home)
59         home_buffer = xstrdup (home);
60 #if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H)
61       else
62         {
63           struct passwd *pwd;
64
65           pwd = getpwuid (getuid());
66           if (pwd)
67             home_buffer = xstrdup (pwd->pw_dir);
68         }
69 #endif
70     }
71   return home_buffer;
72 }
73
74
75 static char *
76 mygetcwd (void)
77 {
78   char *buffer;
79   size_t size = 100;
80
81   for (;;)
82     {
83       buffer = xmalloc (size+1);
84 #ifdef HAVE_W32CE_SYSTEM
85       strcpy (buffer, "/");  /* Always "/".  */
86       return buffer;
87 #else
88       if (getcwd (buffer, size) == buffer)
89         return buffer;
90       xfree (buffer);
91       if (errno != ERANGE)
92         {
93           fprintf (stderr,"error getting current cwd: %s\n",
94                    strerror (errno));
95           exit (2);
96         }
97       size *= 2;
98 #endif
99     }
100 }
101
102
103 static void
104 test_percent_escape (void)
105 {
106   char *result;
107   static struct {
108     const char *extra;
109     const char *value;
110     const char *expected;
111   } tests[] =
112     {
113       { NULL, "", "" },
114       { NULL, "%", "%25" },
115       { NULL, "%%", "%25%25" },
116       { NULL, " %", " %25" },
117       { NULL, ":", "%3a" },
118       { NULL, " :", " %3a" },
119       { NULL, ": ", "%3a " },
120       { NULL, " : ", " %3a " },
121       { NULL, "::", "%3a%3a" },
122       { NULL, ": :", "%3a %3a" },
123       { NULL, "%:", "%25%3a" },
124       { NULL, ":%", "%3a%25" },
125       { "\\\n:", ":%", "%3a%25" },
126       { "\\\n:", "\\:%", "%5c%3a%25" },
127       { "\\\n:", "\n:%", "%0a%3a%25" },
128       { "\\\n:", "\xff:%", "\xff%3a%25" },
129       { "\\\n:", "\xfe:%", "\xfe%3a%25" },
130       { "\\\n:", "\x01:%", "\x01%3a%25" },
131       { "\x01",  "\x01:%", "%01%3a%25" },
132       { "\xfe",  "\xfe:%", "%fe%3a%25" },
133       { "\xfe",  "\xff:%", "\xff%3a%25" },
134
135       { NULL, NULL, NULL }
136     };
137   int testno;
138
139   result = percent_escape (NULL, NULL);
140   if (result)
141     fail (0);
142   for (testno=0; tests[testno].value; testno++)
143     {
144       result = percent_escape (tests[testno].value, tests[testno].extra);
145       if (!result)
146         fail (testno);
147       if (strcmp (result, tests[testno].expected))
148         fail (testno);
149       xfree (result);
150     }
151
152 }
153
154
155 static void
156 test_compare_filenames (void)
157 {
158   struct {
159     const char *a;
160     const char *b;
161     int result;
162   } tests[] = {
163     { "", "", 0 },
164     { "", "a", -1 },
165     { "a", "", 1 },
166     { "a", "a", 0 },
167     { "a", "aa", -1 },
168     { "aa", "a", 1 },
169     { "a",  "b", -1  },
170
171 #ifdef HAVE_W32_SYSTEM
172     { "a", "A", 0 },
173     { "A", "a", 0 },
174     { "foo/bar", "foo\\bar", 0 },
175     { "foo\\bar", "foo/bar", 0 },
176     { "foo\\", "foo/", 0 },
177     { "foo/", "foo\\", 0 },
178 #endif /*HAVE_W32_SYSTEM*/
179     { NULL, NULL, 0}
180   };
181   int testno, result;
182
183   for (testno=0; tests[testno].a; testno++)
184     {
185       result = compare_filenames (tests[testno].a, tests[testno].b);
186       result = result < 0? -1 : result > 0? 1 : 0;
187       if (result != tests[testno].result)
188         fail (testno);
189     }
190 }
191
192
193 static void
194 test_strconcat (void)
195 {
196   char *out;
197
198   out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
199                    "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", NULL);
203   if (!out)
204     fail (0);
205   else
206     xfree (out);
207   out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
208                    "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", NULL);
212   if (out)
213     fail (0);
214   else if (errno != EINVAL)
215     fail (0);
216
217   out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
218                    "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", NULL);
222   if (out)
223     fail (0);
224   else if (errno != EINVAL)
225     fail (0);
226
227 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute.  */
228   out = strconcat (NULL);
229   if (!out || *out)
230     fail (1);
231 #endif
232   out = strconcat (NULL, NULL);
233   if (!out || *out)
234     fail (1);
235   out = strconcat ("", NULL);
236   if (!out || *out)
237     fail (1);
238   xfree (out);
239
240   out = strconcat ("", "", NULL);
241   if (!out || *out)
242     fail (2);
243   xfree (out);
244
245   out = strconcat ("a", "b", NULL);
246   if (!out || strcmp (out, "ab"))
247     fail (3);
248   xfree (out);
249   out = strconcat ("a", "b", "c", NULL);
250   if (!out || strcmp (out, "abc"))
251     fail (3);
252   xfree (out);
253
254   out = strconcat ("a", "b", "cc", NULL);
255   if (!out || strcmp (out, "abcc"))
256     fail (4);
257   xfree (out);
258   out = strconcat ("a1", "b1", "c1", NULL);
259   if (!out || strcmp (out, "a1b1c1"))
260     fail (4);
261   xfree (out);
262
263   out = strconcat ("", " long b ", "", "--even-longer--", NULL);
264   if (!out || strcmp (out, " long b --even-longer--"))
265     fail (5);
266   xfree (out);
267
268   out = strconcat ("", " long b ", "", "--even-longer--", NULL);
269   if (!out || strcmp (out, " long b --even-longer--"))
270     fail (5);
271   xfree (out);
272 }
273
274 static void
275 test_xstrconcat (void)
276 {
277   char *out;
278
279   out = xstrconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
280                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
281                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
282                    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
283                    "1", "2", "3", "4", "5", "6", "7", NULL);
284   if (!out)
285     fail (0);
286
287 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute.  */
288   out = xstrconcat (NULL);
289   if (!out)
290     fail (1);
291 #endif
292   out = xstrconcat (NULL, NULL);
293   if (!out)
294     fail (1);
295   out = xstrconcat ("", NULL);
296   if (!out || *out)
297     fail (1);
298   xfree (out);
299
300   out = xstrconcat ("", "", NULL);
301   if (!out || *out)
302     fail (2);
303   xfree (out);
304
305   out = xstrconcat ("a", "b", NULL);
306   if (!out || strcmp (out, "ab"))
307     fail (3);
308   xfree (out);
309   out = xstrconcat ("a", "b", "c", NULL);
310   if (!out || strcmp (out, "abc"))
311     fail (3);
312   xfree (out);
313
314   out = xstrconcat ("a", "b", "cc", NULL);
315   if (!out || strcmp (out, "abcc"))
316     fail (4);
317   xfree (out);
318   out = xstrconcat ("a1", "b1", "c1", NULL);
319   if (!out || strcmp (out, "a1b1c1"))
320     fail (4);
321   xfree (out);
322
323   out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
324   if (!out || strcmp (out, " long b --even-longer--"))
325     fail (5);
326   xfree (out);
327
328   out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
329   if (!out || strcmp (out, " long b --even-longer--"))
330     fail (5);
331   xfree (out);
332 }
333
334
335 static void
336 test_make_filename_try (void)
337 {
338   char *out;
339   const char *home = gethome ();
340   size_t homelen = home? strlen (home):0;
341
342   out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
343                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
344                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
345                            "1", "2", "3", NULL);
346   if (out)
347     fail (0);
348   else if (errno != EINVAL)
349     fail (0);
350   xfree (out);
351   out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
352                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
353                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
354                            "1", "2", "3", "4", NULL);
355   if (out)
356     fail (0);
357   else if (errno != EINVAL)
358     fail (0);
359   xfree (out);
360
361   out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
362                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
363                            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
364                            "1", "2", NULL);
365   if (!out || strcmp (out,
366                       "1/2/3/4/5/6/7/8/9/10/"
367                       "1/2/3/4/5/6/7/8/9/10/"
368                       "1/2/3/4/5/6/7/8/9/10/"
369                       "1/2"))
370     fail (0);
371   xfree (out);
372
373   out = make_filename_try ("foo", "~/bar", "baz/cde", NULL);
374   if (!out || strcmp (out, "foo/~/bar/baz/cde"))
375     fail (1);
376   xfree (out);
377
378   out = make_filename_try ("foo", "~/bar", "baz/cde/", NULL);
379   if (!out || strcmp (out, "foo/~/bar/baz/cde/"))
380     fail (1);
381   xfree (out);
382
383   out = make_filename_try ("/foo", "~/bar", "baz/cde/", NULL);
384   if (!out || strcmp (out, "/foo/~/bar/baz/cde/"))
385     fail (1);
386   xfree (out);
387
388   out = make_filename_try ("//foo", "~/bar", "baz/cde/", NULL);
389   if (!out || strcmp (out, "//foo/~/bar/baz/cde/"))
390     fail (1);
391   xfree (out);
392
393   out = make_filename_try ("", "~/bar", "baz/cde", NULL);
394   if (!out || strcmp (out, "/~/bar/baz/cde"))
395     fail (1);
396   xfree (out);
397
398
399   out = make_filename_try ("~/foo", "bar", NULL);
400   if (!out)
401     fail (2);
402   if (home)
403     {
404       if (strlen (out) < homelen + 7)
405         fail (2);
406       if (strncmp (out, home, homelen))
407         fail (2);
408       if (strcmp (out+homelen, "/foo/bar"))
409         fail (2);
410     }
411   else
412     {
413       if (strcmp (out, "~/foo/bar"))
414         fail (2);
415     }
416   xfree (out);
417
418   out = make_filename_try ("~", "bar", NULL);
419   if (!out)
420     fail (2);
421   if (home)
422     {
423       if (strlen (out) < homelen + 3)
424         fail (2);
425       if (strncmp (out, home, homelen))
426         fail (2);
427       if (strcmp (out+homelen, "/bar"))
428         fail (2);
429     }
430   else
431     {
432       if (strcmp (out, "~/bar"))
433         fail (2);
434     }
435   xfree (out);
436 }
437
438
439 static void
440 test_make_absfilename_try (void)
441 {
442   char *out;
443   char *cwd = mygetcwd ();
444   size_t cwdlen = strlen (cwd);
445
446   out = make_absfilename_try ("foo", "bar", NULL);
447   if (!out)
448     fail (0);
449   if (strlen (out) < cwdlen + 7)
450     fail (0);
451   if (strncmp (out, cwd, cwdlen))
452     fail (0);
453   if (strcmp (out+cwdlen, "/foo/bar"))
454     fail (0);
455   xfree (out);
456
457   out = make_absfilename_try ("./foo", NULL);
458   if (!out)
459     fail (1);
460   if (strlen (out) < cwdlen + 5)
461     fail (1);
462   if (strncmp (out, cwd, cwdlen))
463     fail (1);
464   if (strcmp (out+cwdlen, "/./foo"))
465     fail (1);
466   xfree (out);
467
468   out = make_absfilename_try (".", NULL);
469   if (!out)
470     fail (2);
471   if (strlen (out) < cwdlen)
472     fail (2);
473   if (strncmp (out, cwd, cwdlen))
474     fail (2);
475   if (strcmp (out+cwdlen, ""))
476     fail (2);
477   xfree (out);
478
479   xfree (cwd);
480 }
481
482 static void
483 test_strsplit (void)
484 {
485   int test_count = 0;
486   void test (const char *s, char delim, char replacement,
487              const char *fields_expected[])
488   {
489     char *s2;
490     int field_count;
491     char **fields;
492     int field_count_expected;
493     int i;
494
495     /* Count the fields.  */
496     for (field_count_expected = 0;
497          fields_expected[field_count_expected];
498          field_count_expected ++)
499       ;
500
501     test_count ++;
502
503     /* We need to copy s since strsplit modifies it in place.  */
504     s2 = xstrdup (s);
505     fields = strsplit (s2, delim, replacement, &field_count);
506
507     if (field_count != field_count_expected)
508       fail (test_count * 1000);
509
510     for (i = 0; i < field_count_expected; i ++)
511       if (strcmp (fields_expected[i], fields[i]) != 0)
512         {
513           printf ("For field %d, expected '%s', but got '%s'\n",
514                   i, fields_expected[i], fields[i]);
515           fail (test_count * 1000 + i + 1);
516         }
517
518     xfree (s2);
519   }
520
521   {
522     const char *expected_result[] =
523       { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL };
524     test ("a:bc:cde:fghi:jklmn::foo:", ':', '\0', expected_result);
525   }
526
527   {
528     const char *expected_result[] =
529       { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL };
530     test (",a,bc,,def,", ',', '!', expected_result);
531   }
532
533   {
534     const char *expected_result[] = { "", NULL };
535     test ("", ':', ',', expected_result);
536   }
537 }
538
539 int
540 main (int argc, char **argv)
541 {
542   (void)argc;
543   (void)argv;
544
545   test_percent_escape ();
546   test_compare_filenames ();
547   test_strconcat ();
548   test_xstrconcat ();
549   test_make_filename_try ();
550   test_make_absfilename_try ();
551   test_strsplit ();
552
553   xfree (home_buffer);
554   return 0;
555 }