1 /* t-stringhelp.c - Regression tests for stringhelp.c
2 * Copyright (C) 2007 Free Software Foundation, Inc.
3 * 2015, 2021 g10 Code GmbH
4 *
5 * This file is part of GnuPG.
6 *
7 * GnuPG is free software; you can redistribute and/or modify this
8 * part of GnuPG 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 * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
31 */
32
33 #include <config.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.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 "sysutils.h"
47 #include "stringhelp.h"
48
49
50 static char *home_buffer;
51
52
53 const char *
gethome(void)54 gethome (void)
55 {
56 if (!home_buffer)
57 {
58 char *home = getenv("HOME");
59
60 if(home)
61 home_buffer = xstrdup (home);
62 #if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H)
63 else
64 {
65 struct passwd *pwd;
66
67 pwd = getpwuid (getuid());
68 if (pwd)
69 home_buffer = xstrdup (pwd->pw_dir);
70 }
71 #endif
72 }
73 return home_buffer;
74 }
75
76
77 static char *
mygetcwd(void)78 mygetcwd (void)
79 {
80 char *buffer;
81 size_t size = 100;
82
83 for (;;)
84 {
85 buffer = xmalloc (size+1);
86 #ifdef HAVE_W32CE_SYSTEM
87 strcpy (buffer, "/"); /* Always "/". */
88 return buffer;
89 #else
90 if (getcwd (buffer, size) == buffer)
91 return buffer;
92 xfree (buffer);
93 if (errno != ERANGE)
94 {
95 fprintf (stderr,"error getting current cwd: %s\n",
96 strerror (errno));
97 exit (2);
98 }
99 size *= 2;
100 #endif
101 }
102 }
103
104
105 static void
test_percent_escape(void)106 test_percent_escape (void)
107 {
108 char *result;
109 static struct {
110 const char *extra;
111 const char *value;
112 const char *expected;
113 } tests[] =
114 {
115 { NULL, "", "" },
116 { NULL, "%", "%25" },
117 { NULL, "%%", "%25%25" },
118 { NULL, " %", " %25" },
119 { NULL, ":", "%3a" },
120 { NULL, " :", " %3a" },
121 { NULL, ": ", "%3a " },
122 { NULL, " : ", " %3a " },
123 { NULL, "::", "%3a%3a" },
124 { NULL, ": :", "%3a %3a" },
125 { NULL, "%:", "%25%3a" },
126 { NULL, ":%", "%3a%25" },
127 { "\\\n:", ":%", "%3a%25" },
128 { "\\\n:", "\\:%", "%5c%3a%25" },
129 { "\\\n:", "\n:%", "%0a%3a%25" },
130 { "\\\n:", "\xff:%", "\xff%3a%25" },
131 { "\\\n:", "\xfe:%", "\xfe%3a%25" },
132 { "\\\n:", "\x01:%", "\x01%3a%25" },
133 { "\x01", "\x01:%", "%01%3a%25" },
134 { "\xfe", "\xfe:%", "%fe%3a%25" },
135 { "\xfe", "\xff:%", "\xff%3a%25" },
136
137 { NULL, NULL, NULL }
138 };
139 int testno;
140
141 result = percent_escape (NULL, NULL);
142 if (result)
143 fail (0);
144 for (testno=0; tests[testno].value; testno++)
145 {
146 result = percent_escape (tests[testno].value, tests[testno].extra);
147 if (!result)
148 fail (testno);
149 else if (strcmp (result, tests[testno].expected))
150 fail (testno);
151 xfree (result);
152 }
153
154 }
155
156
157 static void
test_compare_filenames(void)158 test_compare_filenames (void)
159 {
160 struct {
161 const char *a;
162 const char *b;
163 int result;
164 } tests[] = {
165 { "", "", 0 },
166 { "", "a", -1 },
167 { "a", "", 1 },
168 { "a", "a", 0 },
169 { "a", "aa", -1 },
170 { "aa", "a", 1 },
171 { "a", "b", -1 },
172
173 #ifdef HAVE_W32_SYSTEM
174 { "a", "A", 0 },
175 { "A", "a", 0 },
176 { "foo/bar", "foo\\bar", 0 },
177 { "foo\\bar", "foo/bar", 0 },
178 { "foo\\", "foo/", 0 },
179 { "foo/", "foo\\", 0 },
180 #endif /*HAVE_W32_SYSTEM*/
181 { NULL, NULL, 0}
182 };
183 int testno, result;
184
185 for (testno=0; tests[testno].a; testno++)
186 {
187 result = compare_filenames (tests[testno].a, tests[testno].b);
188 result = result < 0? -1 : result > 0? 1 : 0;
189 if (result != tests[testno].result)
190 fail (testno);
191 }
192 }
193
194
195 static void
test_strconcat(void)196 test_strconcat (void)
197 {
198 char *out;
199
200 out = strconcat ("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", "8", "9", "10",
204 "1", "2", "3", "4", "5", "6", "7", NULL);
205 if (!out)
206 fail (0);
207 else
208 xfree (out);
209 out = strconcat ("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", "9", "10",
213 "1", "2", "3", "4", "5", "6", "7", "8", NULL);
214 if (out)
215 fail (0);
216 else if (errno != EINVAL)
217 fail (0);
218
219 out = strconcat ("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", "10",
223 "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL);
224 if (out)
225 fail (0);
226 else if (errno != EINVAL)
227 fail (0);
228 xfree (out);
229
230 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
231 out = strconcat (NULL);
232 if (!out || *out)
233 fail (1);
234 #endif
235 out = strconcat (NULL, NULL);
236 if (!out || *out)
237 fail (1);
238 xfree (out);
239
240 out = strconcat ("", NULL);
241 if (!out || *out)
242 fail (1);
243 xfree (out);
244
245 out = strconcat ("", "", NULL);
246 if (!out || *out)
247 fail (2);
248 xfree (out);
249
250 out = strconcat ("a", "b", NULL);
251 if (!out || strcmp (out, "ab"))
252 fail (3);
253 xfree (out);
254 out = strconcat ("a", "b", "c", NULL);
255 if (!out || strcmp (out, "abc"))
256 fail (3);
257 xfree (out);
258
259 out = strconcat ("a", "b", "cc", NULL);
260 if (!out || strcmp (out, "abcc"))
261 fail (4);
262 xfree (out);
263 out = strconcat ("a1", "b1", "c1", NULL);
264 if (!out || strcmp (out, "a1b1c1"))
265 fail (4);
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 out = strconcat ("", " long b ", "", "--even-longer--", NULL);
274 if (!out || strcmp (out, " long b --even-longer--"))
275 fail (5);
276 xfree (out);
277 }
278
279 static void
test_xstrconcat(void)280 test_xstrconcat (void)
281 {
282 char *out;
283
284 out = xstrconcat ("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", "8", "9", "10",
288 "1", "2", "3", "4", "5", "6", "7", NULL);
289 if (!out)
290 fail (0);
291 xfree (out);
292
293 #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
294 out = xstrconcat (NULL);
295 if (!out)
296 fail (1);
297 #endif
298 out = xstrconcat (NULL, NULL);
299 if (!out)
300 fail (1);
301 xfree (out);
302
303 out = xstrconcat ("", NULL);
304 if (!out || *out)
305 fail (1);
306 xfree (out);
307
308 out = xstrconcat ("", "", NULL);
309 if (!out || *out)
310 fail (2);
311 xfree (out);
312
313 out = xstrconcat ("a", "b", NULL);
314 if (!out || strcmp (out, "ab"))
315 fail (3);
316 xfree (out);
317 out = xstrconcat ("a", "b", "c", NULL);
318 if (!out || strcmp (out, "abc"))
319 fail (3);
320 xfree (out);
321
322 out = xstrconcat ("a", "b", "cc", NULL);
323 if (!out || strcmp (out, "abcc"))
324 fail (4);
325 xfree (out);
326 out = xstrconcat ("a1", "b1", "c1", NULL);
327 if (!out || strcmp (out, "a1b1c1"))
328 fail (4);
329 xfree (out);
330
331 out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
332 if (!out || strcmp (out, " long b --even-longer--"))
333 fail (5);
334 xfree (out);
335
336 out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
337 if (!out || strcmp (out, " long b --even-longer--"))
338 fail (5);
339 xfree (out);
340 }
341
342
343 static void
test_make_filename_try(void)344 test_make_filename_try (void)
345 {
346 char *out;
347 const char *home = gethome ();
348 size_t homelen = home? strlen (home):0;
349
350 out = make_filename_try ("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", "4", "5", "6", "7", "8", "9", "10",
353 "1", "2", "3", NULL);
354 if (out)
355 fail (0);
356 else if (errno != EINVAL)
357 fail (0);
358 xfree (out);
359 out = make_filename_try ("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", "5", "6", "7", "8", "9", "10",
362 "1", "2", "3", "4", NULL);
363 if (out)
364 fail (0);
365 else if (errno != EINVAL)
366 fail (0);
367 xfree (out);
368
369 out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
370 "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
371 "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
372 "1", "2", NULL);
373 if (!out || strcmp (out,
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/3/4/5/6/7/8/9/10/"
377 "1/2"))
378 fail (0);
379 xfree (out);
380
381 out = make_filename_try ("foo", "~/bar", "baz/cde", NULL);
382 if (!out || strcmp (out, "foo/~/bar/baz/cde"))
383 fail (1);
384 xfree (out);
385
386 out = make_filename_try ("foo", "~/bar", "baz/cde/", NULL);
387 if (!out || strcmp (out, "foo/~/bar/baz/cde/"))
388 fail (1);
389 xfree (out);
390
391 out = make_filename_try ("/foo", "~/bar", "baz/cde/", NULL);
392 if (!out || strcmp (out, "/foo/~/bar/baz/cde/"))
393 fail (1);
394 xfree (out);
395
396 out = make_filename_try ("//foo", "~/bar", "baz/cde/", NULL);
397 if (!out || strcmp (out, "//foo/~/bar/baz/cde/"))
398 fail (1);
399 xfree (out);
400
401 out = make_filename_try ("", "~/bar", "baz/cde", NULL);
402 if (!out || strcmp (out, "/~/bar/baz/cde"))
403 fail (1);
404 xfree (out);
405
406
407 out = make_filename_try ("~/foo", "bar", NULL);
408 if (!out)
409 fail (2);
410 else if (home)
411 {
412 if (strlen (out) < homelen + 7)
413 fail (2);
414 else if (strncmp (out, home, homelen))
415 fail (2);
416 else if (strcmp (out+homelen, "/foo/bar"))
417 fail (2);
418 }
419 else
420 {
421 if (strcmp (out, "~/foo/bar"))
422 fail (2);
423 }
424 xfree (out);
425
426 out = make_filename_try ("~", "bar", NULL);
427 if (!out)
428 fail (2);
429 else if (home)
430 {
431 if (strlen (out) < homelen + 3)
432 fail (2);
433 else if (strncmp (out, home, homelen))
434 fail (2);
435 else if (strcmp (out+homelen, "/bar"))
436 fail (2);
437 }
438 else
439 {
440 if (strcmp (out, "~/bar"))
441 fail (2);
442 }
443 xfree (out);
444 }
445
446
447 static void
test_make_absfilename_try(void)448 test_make_absfilename_try (void)
449 {
450 char *out;
451 char *cwd = mygetcwd ();
452 size_t cwdlen = strlen (cwd);
453
454 out = make_absfilename_try ("foo", "bar", NULL);
455 if (!out)
456 fail (0);
457 else if (strlen (out) < cwdlen + 7)
458 fail (0);
459 else if (strncmp (out, cwd, cwdlen))
460 fail (0);
461 else if (strcmp (out+cwdlen, "/foo/bar"))
462 fail (0);
463 xfree (out);
464
465 out = make_absfilename_try ("./foo", NULL);
466 if (!out)
467 fail (1);
468 else if (strlen (out) < cwdlen + 5)
469 fail (1);
470 else if (strncmp (out, cwd, cwdlen))
471 fail (1);
472 else if (strcmp (out+cwdlen, "/./foo"))
473 fail (1);
474 xfree (out);
475
476 out = make_absfilename_try (".", NULL);
477 if (!out)
478 fail (2);
479 else if (strlen (out) < cwdlen)
480 fail (2);
481 else if (strncmp (out, cwd, cwdlen))
482 fail (2);
483 else if (strcmp (out+cwdlen, ""))
484 fail (2);
485 xfree (out);
486
487 xfree (cwd);
488 }
489
490 static void
test_strsplit(void)491 test_strsplit (void)
492 {
493 struct {
494 const char *s;
495 char delim;
496 char replacement;
497 const char *fields_expected[10];
498 } tv[] = {
499 {
500 "a:bc:cde:fghi:jklmn::foo:", ':', '\0',
501 { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
502 },
503 {
504 ",a,bc,,def,", ',', '!',
505 { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL }
506 },
507 {
508 "", ':', ',',
509 { "", NULL }
510 }
511 };
512
513 int tidx;
514
515 for (tidx = 0; tidx < DIM(tv); tidx++)
516 {
517 char *s2;
518 int field_count;
519 char **fields;
520 int field_count_expected;
521 int i;
522
523 /* Count the fields. */
524 for (field_count_expected = 0;
525 tv[tidx].fields_expected[field_count_expected];
526 field_count_expected ++)
527 ;
528
529 /* We need to copy s since strsplit modifies it in place. */
530 s2 = xstrdup (tv[tidx].s);
531 fields = strsplit (s2, tv[tidx].delim, tv[tidx].replacement,
532 &field_count);
533
534 if (field_count != field_count_expected)
535 fail (tidx * 1000);
536
537 for (i = 0; i < field_count_expected; i ++)
538 if (strcmp (tv[tidx].fields_expected[i], fields[i]) != 0)
539 {
540 printf ("For field %d, expected '%s', but got '%s'\n",
541 i, tv[tidx].fields_expected[i], fields[i]);
542 fail (tidx * 1000 + i + 1);
543 }
544
545 xfree (fields);
546 xfree (s2);
547 }
548 }
549
550
551
552 static void
test_strtokenize(void)553 test_strtokenize (void)
554 {
555 struct {
556 const char *s;
557 const char *delim;
558 const char *fields_expected[10];
559 } tv[] = {
560 {
561 "", ":",
562 { "", NULL }
563 },
564 {
565 "a", ":",
566 { "a", NULL }
567 },
568 {
569 ":", ":",
570 { "", "", NULL }
571 },
572 {
573 "::", ":",
574 { "", "", "", NULL }
575 },
576 {
577 "a:b:c", ":",
578 { "a", "b", "c", NULL }
579 },
580 {
581 "a:b:", ":",
582 { "a", "b", "", NULL }
583 },
584 {
585 "a:b", ":",
586 { "a", "b", NULL }
587 },
588 {
589 "aa:b:cd", ":",
590 { "aa", "b", "cd", NULL }
591 },
592 {
593 "aa::b:cd", ":",
594 { "aa", "", "b", "cd", NULL }
595 },
596 {
597 "::b:cd", ":",
598 { "", "", "b", "cd", NULL }
599 },
600 {
601 "aa: : b:cd ", ":",
602 { "aa", "", "b", "cd", NULL }
603 },
604 {
605 " aa: : b: cd ", ":",
606 { "aa", "", "b", "cd", NULL }
607 },
608 {
609 " ", ":",
610 { "", NULL }
611 },
612 {
613 " :", ":",
614 { "", "", NULL }
615 },
616 {
617 " : ", ":",
618 { "", "", NULL }
619 },
620 {
621 ": ", ":",
622 { "", "", NULL }
623 },
624 {
625 ": x ", ":",
626 { "", "x", NULL }
627 },
628 {
629 "a:bc:cde:fghi:jklmn::foo:", ":",
630 { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
631 },
632 {
633 ",a,bc,,def,", ",",
634 { "", "a", "bc", "", "def", "", NULL }
635 },
636 {
637 " a ", " ",
638 { "", "a", "", NULL }
639 },
640 {
641 " ", " ",
642 { "", "", NULL }
643 },
644 {
645 "", " ",
646 { "", NULL }
647 }
648 };
649
650 int tidx;
651
652 for (tidx = 0; tidx < DIM(tv); tidx++)
653 {
654 char **fields;
655 int field_count;
656 int field_count_expected;
657 int i;
658
659 for (field_count_expected = 0;
660 tv[tidx].fields_expected[field_count_expected];
661 field_count_expected ++)
662 ;
663
664 fields = strtokenize (tv[tidx].s, tv[tidx].delim);
665 if (!fields)
666 fail (tidx * 1000);
667 else
668 {
669 for (field_count = 0; fields[field_count]; field_count++)
670 ;
671 if (field_count != field_count_expected)
672 fail (tidx * 1000);
673 else
674 {
675 for (i = 0; i < field_count_expected; i++)
676 if (strcmp (tv[tidx].fields_expected[i], fields[i]))
677 {
678 printf ("For field %d, expected '%s', but got '%s'\n",
679 i, tv[tidx].fields_expected[i], fields[i]);
680 fail (tidx * 1000 + i + 1);
681 }
682 }
683 }
684
685 xfree (fields);
686 }
687 }
688
689
690 static void
test_strtokenize_nt(void)691 test_strtokenize_nt (void)
692 {
693 struct {
694 const char *s;
695 const char *delim;
696 const char *fields_expected[10];
697 } tv[] = {
698 {
699 "", ":",
700 { "", NULL }
701 },
702 {
703 "a", ":",
704 { "a", NULL }
705 },
706 {
707 ":", ":",
708 { "", "", NULL }
709 },
710 {
711 "::", ":",
712 { "", "", "", NULL }
713 },
714 {
715 "a:b:c", ":",
716 { "a", "b", "c", NULL }
717 },
718 {
719 "a:b:", ":",
720 { "a", "b", "", NULL }
721 },
722 {
723 "a:b", ":",
724 { "a", "b", NULL }
725 },
726 {
727 "aa:b:cd", ":",
728 { "aa", "b", "cd", NULL }
729 },
730 {
731 "aa::b:cd", ":",
732 { "aa", "", "b", "cd", NULL }
733 },
734 {
735 "::b:cd", ":",
736 { "", "", "b", "cd", NULL }
737 },
738 {
739 "aa: : b:cd ", ":",
740 { "aa", " ", " b", "cd ", NULL }
741 },
742 {
743 " aa: : b: cd ", ":",
744 { " aa", " ", " b", " cd ", NULL }
745 },
746 {
747 " ", ":",
748 { " ", NULL }
749 },
750 {
751 " :", ":",
752 { " ", "", NULL }
753 },
754 {
755 " : ", ":",
756 { " ", " ", NULL }
757 },
758 {
759 ": ", ":",
760 { "", " ", NULL }
761 },
762 {
763 ": x ", ":",
764 { "", " x ", NULL }
765 },
766 {
767 "a:bc:cde:fghi:jklmn::foo:", ":",
768 { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
769 },
770 {
771 ",a,bc,,def,", ",",
772 { "", "a", "bc", "", "def", "", NULL }
773 },
774 {
775 " a ", " ",
776 { "", "a", "", NULL }
777 },
778 {
779 " ", " ",
780 { "", "", NULL }
781 },
782 {
783 "", " ",
784 { "", NULL }
785 }
786 };
787
788 int tidx;
789
790 for (tidx = 0; tidx < DIM(tv); tidx++)
791 {
792 char **fields;
793 int field_count;
794 int field_count_expected;
795 int i;
796
797 for (field_count_expected = 0;
798 tv[tidx].fields_expected[field_count_expected];
799 field_count_expected ++)
800 ;
801
802 fields = strtokenize_nt (tv[tidx].s, tv[tidx].delim);
803 if (!fields)
804 fail (tidx * 1000);
805 else
806 {
807 for (field_count = 0; fields[field_count]; field_count++)
808 ;
809 if (field_count != field_count_expected)
810 fail (tidx * 1000);
811 else
812 {
813 for (i = 0; i < field_count_expected; i++)
814 if (strcmp (tv[tidx].fields_expected[i], fields[i]))
815 {
816 printf ("For field %d, expected '%s', but got '%s'\n",
817 i, tv[tidx].fields_expected[i], fields[i]);
818 fail (tidx * 1000 + i + 1);
819 }
820 }
821 }
822
823 xfree (fields);
824 }
825 }
826
827
828 static void
test_split_fields(void)829 test_split_fields (void)
830 {
831 struct {
832 const char *s;
833 int nfields;
834 const char *fields_expected[10];
835 } tv[] = {
836 {
837 "a bc cde fghi jklmn foo ", 6,
838 { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL }
839 },
840 {
841 " a bc def ", 2,
842 { "a", "bc", "def", NULL }
843 },
844 {
845 " a bc def ", 3,
846 { "a", "bc", "def", NULL }
847 },
848 {
849 " a bc def ", 4,
850 { "a", "bc", "def", NULL }
851 },
852 {
853 "", 0,
854 { NULL }
855 }
856 };
857
858 int tidx;
859 const char *fields[10];
860 int field_count_expected, nfields, field_count, i;
861 char *s2;
862
863 for (tidx = 0; tidx < DIM(tv); tidx++)
864 {
865 nfields = tv[tidx].nfields;
866 log_assert (nfields <= DIM (fields));
867
868 /* Count the fields. */
869 for (field_count_expected = 0;
870 tv[tidx].fields_expected[field_count_expected];
871 field_count_expected ++)
872 ;
873 if (field_count_expected > nfields)
874 field_count_expected = nfields;
875
876 /* We need to copy s since split_fields modifies in place. */
877 s2 = xstrdup (tv[tidx].s);
878 field_count = split_fields (s2, fields, nfields);
879
880 if (field_count != field_count_expected)
881 {
882 printf ("%s: tidx %d: expected %d, got %d\n",
883 __func__, tidx, field_count_expected, field_count);
884 fail (tidx * 1000);
885 }
886 else
887 {
888 for (i = 0; i < field_count_expected; i ++)
889 if (strcmp (tv[tidx].fields_expected[i], fields[i]))
890 {
891 printf ("%s: tidx %d, field %d: expected '%s', got '%s'\n",
892 __func__,
893 tidx, i, tv[tidx].fields_expected[i], fields[i]);
894 fail (tidx * 1000 + i + 1);
895 }
896 }
897
898 xfree (s2);
899 }
900 }
901
902
903 static void
test_split_fields_colon(void)904 test_split_fields_colon (void)
905 {
906 struct {
907 const char *s;
908 int nfields;
909 const char *fields_expected[10];
910 } tv[] = {
911 {
912 "a:bc:cde:fghi:jklmn: foo ", 6,
913 { "a", "bc", "cde", "fghi", "jklmn", " foo ", NULL }
914 },
915 {
916 " a:bc: def ", 2,
917 { " a", "bc", NULL }
918 },
919 {
920 " a:bc :def ", 3,
921 { " a", "bc ", "def ", NULL }
922 },
923 {
924 " a:bc: def ", 4,
925 { " a", "bc", " def ", NULL }
926 },
927 {
928 "", 0,
929 { NULL }
930 }
931 };
932
933 int tidx;
934 const char *fields[10];
935 int field_count_expected, nfields, field_count, i;
936 char *s2;
937
938 for (tidx = 0; tidx < DIM(tv); tidx++)
939 {
940 nfields = tv[tidx].nfields;
941 log_assert (nfields <= DIM (fields));
942
943 /* Count the fields. */
944 for (field_count_expected = 0;
945 tv[tidx].fields_expected[field_count_expected];
946 field_count_expected ++)
947 ;
948 if (field_count_expected > nfields)
949 field_count_expected = nfields;
950
951 /* We need to copy s since split_fields modifies in place. */
952 s2 = xstrdup (tv[tidx].s);
953 field_count = split_fields_colon (s2, fields, nfields);
954
955 if (field_count != field_count_expected)
956 {
957 printf ("%s: tidx %d: expected %d, got %d\n",
958 __func__, tidx, field_count_expected, field_count);
959 fail (tidx * 1000);
960 }
961 else
962 {
963 for (i = 0; i < field_count_expected; i ++)
964 if (strcmp (tv[tidx].fields_expected[i], fields[i]))
965 {
966 printf ("%s: tidx %d, field %d: expected '%s', got '%s'\n",
967 __func__,
968 tidx, i, tv[tidx].fields_expected[i], fields[i]);
969 fail (tidx * 1000 + i + 1);
970 }
971 }
972
973 xfree (s2);
974 }
975 }
976
977
978 static char *
stresc(char * s)979 stresc (char *s)
980 {
981 char *p;
982 int l = strlen (s) + 1;
983
984 for (p = s; *p; p ++)
985 if (*p == '\n')
986 l ++;
987
988 p = xmalloc (l);
989 for (l = 0; *s; s ++, l ++)
990 {
991 if (*s == ' ')
992 p[l] = '_';
993 else if (*p == '\n')
994 {
995 p[l ++] = '\\';
996 p[l ++] = 'n';
997 p[l] = '\n';
998 }
999 else
1000 p[l] = *s;
1001 }
1002 p[l] = *s;
1003
1004 return p;
1005 }
1006
1007
1008 static void
test_format_text(void)1009 test_format_text (void)
1010 {
1011 struct test
1012 {
1013 int target_cols, max_cols;
1014 char *input;
1015 char *expected;
1016 };
1017
1018 struct test tests[] = {
1019 {
1020 10, 12,
1021 "",
1022 "",
1023 },
1024 {
1025 10, 12,
1026 " ",
1027 "",
1028 },
1029 {
1030 10, 12,
1031 " ",
1032 "",
1033 },
1034 {
1035 10, 12,
1036 " \n ",
1037 " \n",
1038 },
1039 {
1040 10, 12,
1041 " \n \n ",
1042 " \n \n",
1043 },
1044 {
1045 10, 12,
1046 "0123456789 0123456789 0",
1047 "0123456789\n0123456789\n0",
1048 },
1049 {
1050 10, 12,
1051 " 0123456789 0123456789 0 ",
1052 " 0123456789\n0123456789\n0",
1053 },
1054 {
1055 10, 12,
1056 "01 34 67 90 23 56 89 12 45 67 89 1",
1057 "01 34 67\n90 23 56\n89 12 45\n67 89 1"
1058 },
1059 {
1060 10, 12,
1061 "01 34 67 90 23 56 89 12 45 67 89 1",
1062 "01 34 67\n90 23 56\n89 12 45\n67 89 1"
1063 },
1064 {
1065 72, 80,
1066 "Warning: if you think you've seen more than 10 messages "
1067 "signed by this key, then this key might be a forgery! "
1068 "Carefully examine the email address for small variations "
1069 "(e.g., additional white space). If the key is suspect, "
1070 "then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as being bad.\n",
1071 "Warning: if you think you've seen more than 10 messages signed by this\n"
1072 "key, then this key might be a forgery! Carefully examine the email\n"
1073 "address for small variations (e.g., additional white space). If the key\n"
1074 "is suspect, then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as\n"
1075 "being bad.\n"
1076
1077 },
1078 {
1079 72, 80,
1080 "Normally, there is only a single key associated with an email "
1081 "address. However, people sometimes generate a new key if "
1082 "their key is too old or they think it might be compromised. "
1083 "Alternatively, a new key may indicate a man-in-the-middle "
1084 "attack! Before accepting this key, you should talk to or "
1085 "call the person to make sure this new key is legitimate.",
1086 "Normally, there is only a single key associated with an email "
1087 "address.\nHowever, people sometimes generate a new key if "
1088 "their key is too old or\nthey think it might be compromised. "
1089 "Alternatively, a new key may indicate\na man-in-the-middle "
1090 "attack! Before accepting this key, you should talk\nto or "
1091 "call the person to make sure this new key is legitimate.",
1092 }
1093 };
1094
1095 int i;
1096 int failed = 0;
1097
1098 for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i ++)
1099 {
1100 struct test *test = &tests[i];
1101 char *result =
1102 format_text (test->input, test->target_cols, test->max_cols);
1103 if (!result)
1104 {
1105 fail (1);
1106 exit (2);
1107 }
1108 if (strcmp (result, test->expected) != 0)
1109 {
1110 printf ("%s: Test #%d failed.\nExpected: '%s'\nResult: '%s'\n",
1111 __func__, i + 1, stresc (test->expected), stresc (result));
1112 failed ++;
1113 }
1114 xfree (result);
1115 }
1116
1117 if (failed)
1118 fail(0);
1119 }
1120
1121
1122 static void
test_compare_version_strings(void)1123 test_compare_version_strings (void)
1124 {
1125 struct { const char *a; const char *b; int okay; } tests[] = {
1126 { "1.0.0", "1.0.0", 0 },
1127 { "1.0.0-", "1.0.0", 1 },
1128 { "1.0.0-1", "1.0.0", 1 },
1129 { "1.0.0.1", "1.0.0", 1 },
1130 { "1.0.0", "1.0.1", -1 },
1131 { "1.0.0-", "1.0.1", -1 },
1132 { "1.0.0-1", "1.0.1", -1 },
1133 { "1.0.0.1", "1.0.1", -1 },
1134 { "1.0.0", "1.1.0", -1 },
1135 { "1.0.0-", "1.1.0", -1 },
1136 { "1.0.0-1", "1.1.0", -1 },
1137 { "1.0.0.1", "1.1.0", -1 },
1138
1139 { "1.0.0", "1.0.0-", -1 },
1140 { "1.0.0", "1.0.0-1", -1 },
1141 { "1.0.0", "1.0.0.1", -1 },
1142 { "1.1.0", "1.0.0", 1 },
1143 { "1.1.1", "1.1.0", 1 },
1144 { "1.1.2", "1.1.2", 0 },
1145 { "1.1.2", "1.0.2", 1 },
1146 { "1.1.2", "0.0.2", 1 },
1147 { "1.1.2", "1.1.3", -1 },
1148
1149 { "0.99.1", "0.9.9", 1 },
1150 { "0.9.1", "0.91.0", -1 },
1151
1152 { "1.5.3", "1.5", 1 },
1153 { "1.5.0", "1.5", 0 },
1154 { "1.4.99", "1.5", -1 },
1155 { "1.5", "1.4.99", 1 },
1156 { "1.5", "1.5.0", 0 },
1157 { "1.5", "1.5.1", -1 },
1158
1159 { "1.5.3-x17", "1.5-23", 1 },
1160
1161 { "1.5.3a", "1.5.3", 1 },
1162 { "1.5.3a", "1.5.3b", -1 },
1163
1164 { "3.1.4-ab", "3.1.4-ab", 0 },
1165 { "3.1.4-ab", "3.1.4-ac", -1 },
1166 { "3.1.4-ac", "3.1.4-ab", 1 },
1167 { "3.1.4-ab", "3.1.4-abb", -1 },
1168 { "3.1.4-abb", "3.1.4-ab", 1 },
1169
1170 { "", "", INT_MIN },
1171 { NULL, "", INT_MIN },
1172 { "1.2.3", "", INT_MIN },
1173 { "1.2.3", "2", INT_MIN },
1174
1175 /* Test cases for validity of A. */
1176 { "", NULL, INT_MIN },
1177 { "1", NULL, INT_MIN },
1178 { "1.", NULL, 0 },
1179 { "1.0", NULL, 0 },
1180 { "1.0.", NULL, 0 },
1181 { "a1.2", NULL, INT_MIN },
1182 { NULL, NULL, INT_MIN }
1183 };
1184 int idx;
1185 int res;
1186
1187 for (idx=0; idx < DIM(tests); idx++)
1188 {
1189 res = compare_version_strings (tests[idx].a, tests[idx].b);
1190 /* printf ("test %d: '%s' '%s' %d -> %d\n", */
1191 /* idx, tests[idx].a, tests[idx].b, tests[idx].okay, res); */
1192 if (res != tests[idx].okay)
1193 fail (idx);
1194 }
1195 }
1196
1197
1198 static void
test_substitute_envvars(void)1199 test_substitute_envvars (void)
1200 {
1201 struct {
1202 const char *name;
1203 const char *value;
1204 } envvars[] = {
1205 { "HOME", "/home/joe" },
1206 { "AVAR", "avar" },
1207 { "AVAR1", "avarx" },
1208 { "AVAR2", "avarxy" },
1209 { "AVAR3", "avarxyz" },
1210 { "AVAR0", "ava" },
1211 { "MY_VAR", "my_vars_value" },
1212 { "STRANGE{X}VAR", "strange{x}vars-value" },
1213 { "ZERO", "" }
1214 };
1215 struct {
1216 const char *string;
1217 const char *result;
1218 } tests[] = {
1219 { "foo bar",
1220 "foo bar"
1221 },
1222 { "foo $HOME",
1223 "foo /home/joe"
1224 },
1225 { "foo $HOME ",
1226 "foo /home/joe "
1227 },
1228 { "foo $HOME$$",
1229 "foo /home/joe$"
1230 },
1231 { "foo ${HOME}/.ssh",
1232 "foo /home/joe/.ssh"
1233 },
1234 { "foo $HOME/.ssh",
1235 "foo /home/joe/.ssh"
1236 },
1237 { "foo $HOME_/.ssh",
1238 "foo /.ssh"
1239 },
1240 { "foo $HOME/.ssh/$MY_VAR:1",
1241 "foo /home/joe/.ssh/my_vars_value:1"
1242 },
1243 { "foo $HOME${MY_VAR}:1",
1244 "foo /home/joemy_vars_value:1"
1245 },
1246 { "${STRANGE{X}VAR}-bla",
1247 "strange{x}vars-value-bla"
1248 },
1249 { "${STRANGE{X}{VAR}-bla", /* missing "}" */
1250 "${STRANGE{X}{VAR}-bla"
1251 },
1252 { "zero->$ZERO<-",
1253 "zero-><-"
1254 },
1255 { "->$AVAR.$AVAR1.$AVAR2.$AVAR3.$AVAR0<-",
1256 "->avar.avarx.avarxy.avarxyz.ava<-"
1257 },
1258 { "",
1259 ""
1260 }
1261 };
1262 int idx;
1263 char *res;
1264
1265 for (idx=0; idx < DIM(envvars); idx++)
1266 if (gnupg_setenv (envvars[idx].name, envvars[idx].value, 1))
1267 {
1268 fprintf (stderr,"error setting envvar '%s' to '%s': %s\n",
1269 envvars[idx].name, envvars[idx].value,
1270 strerror (errno));
1271 exit (2);
1272 }
1273
1274 for (idx=0; idx < DIM(tests); idx++)
1275 {
1276 res = substitute_envvars (tests[idx].string);
1277 if (!res)
1278 {
1279 fprintf (stderr,"error substituting '%s' (test %d): %s\n",
1280 tests[idx].string, idx, strerror (errno));
1281 exit (2);
1282 }
1283 if (strcmp (res, tests[idx].result))
1284 {
1285 fprintf (stderr, "substituted '%s'\n", tests[idx].string);
1286 fprintf (stderr, " wanted '%s'\n", tests[idx].result);
1287 fprintf (stderr, " got '%s'\n", res);
1288 fail (idx);
1289 }
1290 xfree (res);
1291 }
1292 }
1293
1294
1295 int
main(int argc,char ** argv)1296 main (int argc, char **argv)
1297 {
1298 (void)argc;
1299 (void)argv;
1300
1301 test_percent_escape ();
1302 test_compare_filenames ();
1303 test_strconcat ();
1304 test_xstrconcat ();
1305 test_make_filename_try ();
1306 test_make_absfilename_try ();
1307 test_strsplit ();
1308 test_strtokenize ();
1309 test_strtokenize_nt ();
1310 test_split_fields ();
1311 test_split_fields_colon ();
1312 test_compare_version_strings ();
1313 test_format_text ();
1314 test_substitute_envvars ();
1315
1316 xfree (home_buffer);
1317 return !!errcount;
1318 }
1319