1 /* t-stringhelp.c - Regression tests for stringhelp.c
2 * Copyright (C) 2007 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify it
8 * under the terms of either
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.
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.
20 * or both in parallel, as here.
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.
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/>.
42 #include <sys/types.h>
45 #include "t-support.h"
46 #include "stringhelp.h"
49 static char *home_buffer;
57 char *home = getenv("HOME");
60 home_buffer = xstrdup (home);
61 #if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H)
66 pwd = getpwuid (getuid());
68 home_buffer = xstrdup (pwd->pw_dir);
84 buffer = xmalloc (size+1);
85 #ifdef HAVE_W32CE_SYSTEM
86 strcpy (buffer, "/"); /* Always "/". */
89 if (getcwd (buffer, size) == buffer)
94 fprintf (stderr,"error getting current cwd: %s\n",
105 test_percent_escape (void)
111 const char *expected;
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" },
140 result = percent_escape (NULL, NULL);
143 for (testno=0; tests[testno].value; testno++)
145 result = percent_escape (tests[testno].value, tests[testno].extra);
148 else if (strcmp (result, tests[testno].expected))
157 test_compare_filenames (void)
172 #ifdef HAVE_W32_SYSTEM
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*/
184 for (testno=0; tests[testno].a; testno++)
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)
195 test_strconcat (void)
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);
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);
215 else if (errno != EINVAL)
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);
225 else if (errno != EINVAL)
229 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
230 out = strconcat (NULL);
234 out = strconcat (NULL, NULL);
239 out = strconcat ("", NULL);
244 out = strconcat ("", "", NULL);
249 out = strconcat ("a", "b", NULL);
250 if (!out || strcmp (out, "ab"))
253 out = strconcat ("a", "b", "c", NULL);
254 if (!out || strcmp (out, "abc"))
258 out = strconcat ("a", "b", "cc", NULL);
259 if (!out || strcmp (out, "abcc"))
262 out = strconcat ("a1", "b1", "c1", NULL);
263 if (!out || strcmp (out, "a1b1c1"))
267 out = strconcat ("", " long b ", "", "--even-longer--", NULL);
268 if (!out || strcmp (out, " long b --even-longer--"))
272 out = strconcat ("", " long b ", "", "--even-longer--", NULL);
273 if (!out || strcmp (out, " long b --even-longer--"))
279 test_xstrconcat (void)
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);
292 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
293 out = xstrconcat (NULL);
297 out = xstrconcat (NULL, NULL);
302 out = xstrconcat ("", NULL);
307 out = xstrconcat ("", "", NULL);
312 out = xstrconcat ("a", "b", NULL);
313 if (!out || strcmp (out, "ab"))
316 out = xstrconcat ("a", "b", "c", NULL);
317 if (!out || strcmp (out, "abc"))
321 out = xstrconcat ("a", "b", "cc", NULL);
322 if (!out || strcmp (out, "abcc"))
325 out = xstrconcat ("a1", "b1", "c1", NULL);
326 if (!out || strcmp (out, "a1b1c1"))
330 out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
331 if (!out || strcmp (out, " long b --even-longer--"))
335 out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
336 if (!out || strcmp (out, " long b --even-longer--"))
343 test_make_filename_try (void)
346 const char *home = gethome ();
347 size_t homelen = home? strlen (home):0;
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);
355 else if (errno != EINVAL)
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);
364 else if (errno != EINVAL)
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",
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/"
380 out = make_filename_try ("foo", "~/bar", "baz/cde", NULL);
381 if (!out || strcmp (out, "foo/~/bar/baz/cde"))
385 out = make_filename_try ("foo", "~/bar", "baz/cde/", NULL);
386 if (!out || strcmp (out, "foo/~/bar/baz/cde/"))
390 out = make_filename_try ("/foo", "~/bar", "baz/cde/", NULL);
391 if (!out || strcmp (out, "/foo/~/bar/baz/cde/"))
395 out = make_filename_try ("//foo", "~/bar", "baz/cde/", NULL);
396 if (!out || strcmp (out, "//foo/~/bar/baz/cde/"))
400 out = make_filename_try ("", "~/bar", "baz/cde", NULL);
401 if (!out || strcmp (out, "/~/bar/baz/cde"))
406 out = make_filename_try ("~/foo", "bar", NULL);
411 if (strlen (out) < homelen + 7)
413 else if (strncmp (out, home, homelen))
415 else if (strcmp (out+homelen, "/foo/bar"))
420 if (strcmp (out, "~/foo/bar"))
425 out = make_filename_try ("~", "bar", NULL);
430 if (strlen (out) < homelen + 3)
432 else if (strncmp (out, home, homelen))
434 else if (strcmp (out+homelen, "/bar"))
439 if (strcmp (out, "~/bar"))
447 test_make_absfilename_try (void)
450 char *cwd = mygetcwd ();
451 size_t cwdlen = strlen (cwd);
453 out = make_absfilename_try ("foo", "bar", NULL);
456 else if (strlen (out) < cwdlen + 7)
458 else if (strncmp (out, cwd, cwdlen))
460 else if (strcmp (out+cwdlen, "/foo/bar"))
464 out = make_absfilename_try ("./foo", NULL);
467 else if (strlen (out) < cwdlen + 5)
469 else if (strncmp (out, cwd, cwdlen))
471 else if (strcmp (out+cwdlen, "/./foo"))
475 out = make_absfilename_try (".", NULL);
478 else if (strlen (out) < cwdlen)
480 else if (strncmp (out, cwd, cwdlen))
482 else if (strcmp (out+cwdlen, ""))
496 const char *fields_expected[10];
499 "a:bc:cde:fghi:jklmn::foo:", ':', '\0',
500 { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
503 ",a,bc,,def,", ',', '!',
504 { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL }
514 for (tidx = 0; tidx < DIM(tv); tidx++)
519 int field_count_expected;
522 /* Count the fields. */
523 for (field_count_expected = 0;
524 tv[tidx].fields_expected[field_count_expected];
525 field_count_expected ++)
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,
533 if (field_count != field_count_expected)
536 for (i = 0; i < field_count_expected; i ++)
537 if (strcmp (tv[tidx].fields_expected[i], fields[i]) != 0)
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);
552 test_strtokenize (void)
557 const char *fields_expected[10];
577 { "a", "b", "c", NULL }
581 { "a", "b", "", NULL }
589 { "aa", "b", "cd", NULL }
593 { "aa", "", "b", "cd", NULL }
597 { "", "", "b", "cd", NULL }
601 { "aa", "", "b", "cd", NULL }
604 " aa: : b: cd ", ":",
605 { "aa", "", "b", "cd", NULL }
628 "a:bc:cde:fghi:jklmn::foo:", ":",
629 { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
633 { "", "a", "bc", "", "def", "", NULL }
637 { "", "a", "", NULL }
651 for (tidx = 0; tidx < DIM(tv); tidx++)
655 int field_count_expected;
658 for (field_count_expected = 0;
659 tv[tidx].fields_expected[field_count_expected];
660 field_count_expected ++)
663 fields = strtokenize (tv[tidx].s, tv[tidx].delim);
668 for (field_count = 0; fields[field_count]; field_count++)
670 if (field_count != field_count_expected)
674 for (i = 0; i < field_count_expected; i++)
675 if (strcmp (tv[tidx].fields_expected[i], fields[i]))
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);
690 test_split_fields (void)
695 const char *fields_expected[10];
698 "a bc cde fghi jklmn foo ", 6,
699 { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL }
703 { "a", "bc", "def", NULL }
707 { "a", "bc", "def", NULL }
711 { "a", "bc", "def", NULL }
721 int field_count_expected, nfields, field_count, i;
724 for (tidx = 0; tidx < DIM(tv); tidx++)
726 nfields = tv[tidx].nfields;
727 assert (nfields <= DIM (fields));
729 /* Count the fields. */
730 for (field_count_expected = 0;
731 tv[tidx].fields_expected[field_count_expected];
732 field_count_expected ++)
734 if (field_count_expected > nfields)
735 field_count_expected = nfields;
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);
741 if (field_count != field_count_expected)
743 printf ("%s: tidx %d: expected %d, got %d\n",
744 __func__, tidx, field_count_expected, field_count);
749 for (i = 0; i < field_count_expected; i ++)
750 if (strcmp (tv[tidx].fields_expected[i], fields[i]))
752 printf ("%s: tidx %d, field %d: expected '%s', got '%s'\n",
754 tidx, i, tv[tidx].fields_expected[i], fields[i]);
755 fail (tidx * 1000 + i + 1);
768 int l = strlen (s) + 1;
770 for (p = s; *p; p ++)
775 for (l = 0; *s; s ++, l ++)
795 test_format_text (void)
799 int target_cols, max_cols;
804 struct test tests[] = {
832 "0123456789 0123456789 0",
833 "0123456789\n0123456789\n0",
837 " 0123456789 0123456789 0 ",
838 " 0123456789\n0123456789\n0",
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"
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"
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"
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.",
884 for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i ++)
886 struct test *test = &tests[i];
888 format_text (test->input, 0, test->target_cols, test->max_cols);
889 if (strcmp (result, test->expected) != 0)
891 printf ("%s: Test #%d failed.\nExpected: '%s'\nResult: '%s'\n",
892 __func__, i + 1, stresc (test->expected), stresc (result));
904 test_compare_version_strings (void)
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 },
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 },
930 { "0.99.1", "0.9.9", 1 },
931 { "0.9.1", "0.91.0", -1 },
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 },
940 { "1.5.3-x17", "1.5-23", 1 },
942 { "1.5.3a", "1.5.3", 1 },
943 { "1.5.3a", "1.5.3b", -1 },
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 },
952 { NULL, "", INT_MIN },
953 { "1.2.3", "", INT_MIN },
954 { "1.2.3", "2", INT_MIN },
956 /* Test cases for validity of A. */
957 { "", NULL, INT_MIN },
958 { "1", NULL, INT_MIN },
962 { "a1.2", NULL, INT_MIN },
963 { NULL, NULL, INT_MIN }
968 for (idx=0; idx < DIM(tests); idx++)
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)
980 main (int argc, char **argv)
985 test_percent_escape ();
986 test_compare_filenames ();
989 test_make_filename_try ();
990 test_make_absfilename_try ();
993 test_split_fields ();
994 test_compare_version_strings ();