Ensure that the generator gets notified about an I/O error for the dir
[rsync.git] / wildtest.c
1 /*
2  * Test suite for the wildmatch code.
3  *
4  * Copyright (C) 2003-2009 Wayne Davison
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, visit the http://fsf.org website.
18  */
19
20 /*#define COMPARE_WITH_FNMATCH*/
21
22 #define WILD_TEST_ITERATIONS
23 #include "lib/wildmatch.c"
24
25 #include <popt.h>
26
27 #ifdef COMPARE_WITH_FNMATCH
28 #include <fnmatch.h>
29
30 int fnmatch_errors = 0;
31 #endif
32
33 int wildmatch_errors = 0;
34
35 typedef char bool;
36
37 int output_iterations = 0;
38 int explode_mod = 0;
39 int empties_mod = 0;
40 int empty_at_start = 0;
41 int empty_at_end = 0;
42
43 static struct poptOption long_options[] = {
44   /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
45   {"iterations",     'i', POPT_ARG_NONE,   &output_iterations, 0, 0, 0},
46   {"empties",        'e', POPT_ARG_STRING, 0, 'e', 0, 0},
47   {"explode",        'x', POPT_ARG_INT,    &explode_mod, 0, 0, 0},
48   {0,0,0,0, 0, 0, 0}
49 };
50
51 /* match just at the start of string (anchored tests) */
52 static void
53 run_test(int line, bool matches, bool same_as_fnmatch,
54          const char *text, const char *pattern)
55 {
56     bool matched;
57 #ifdef COMPARE_WITH_FNMATCH
58     bool fn_matched;
59     int flags = strstr(pattern, "**")? 0 : FNM_PATHNAME;
60 #else
61     same_as_fnmatch = 0; /* Get rid of unused-variable compiler warning. */
62 #endif
63
64     if (explode_mod) {
65         char buf[MAXPATHLEN*2], *texts[MAXPATHLEN];
66         int pos = 0, cnt = 0, ndx = 0, len = strlen(text);
67
68         if (empty_at_start)
69             texts[ndx++] = "";
70         /* An empty string must turn into at least one empty array item. */
71         while (1) {
72             texts[ndx] = buf + ndx * (explode_mod + 1);
73             strlcpy(texts[ndx++], text + pos, explode_mod + 1);
74             if (pos + explode_mod >= len)
75                 break;
76             pos += explode_mod;
77             if (!(++cnt % empties_mod))
78                 texts[ndx++] = "";
79         }
80         if (empty_at_end)
81             texts[ndx++] = "";
82         texts[ndx] = NULL;
83         matched = wildmatch_array(pattern, (const char**)texts, 0);
84     } else
85         matched = wildmatch(pattern, text);
86 #ifdef COMPARE_WITH_FNMATCH
87     fn_matched = !fnmatch(pattern, text, flags);
88 #endif
89     if (matched != matches) {
90         printf("wildmatch failure on line %d:\n  %s\n  %s\n  expected %s match\n",
91                line, text, pattern, matches? "a" : "NO");
92         wildmatch_errors++;
93     }
94 #ifdef COMPARE_WITH_FNMATCH
95     if (fn_matched != (matches ^ !same_as_fnmatch)) {
96         printf("fnmatch disagreement on line %d:\n  %s\n  %s\n  expected %s match\n",
97                line, text, pattern, matches ^ !same_as_fnmatch? "a" : "NO");
98         fnmatch_errors++;
99     }
100 #endif
101     if (output_iterations) {
102         printf("%d: \"%s\" iterations = %d\n", line, pattern,
103                wildmatch_iteration_count);
104     }
105 }
106
107 int
108 main(int argc, char **argv)
109 {
110     char buf[2048], *s, *string[2], *end[2];
111     const char *arg;
112     FILE *fp;
113     int opt, line, i, flag[2];
114     poptContext pc = poptGetContext("wildtest", argc, (const char**)argv,
115                                     long_options, 0);
116
117     while ((opt = poptGetNextOpt(pc)) != -1) {
118         switch (opt) {
119           case 'e':
120             arg = poptGetOptArg(pc);
121             empties_mod = atoi(arg);
122             if (strchr(arg, 's'))
123                 empty_at_start = 1;
124             if (strchr(arg, 'e'))
125                 empty_at_end = 1;
126             if (!explode_mod)
127                 explode_mod = 1024;
128             break;
129           default:
130             fprintf(stderr, "%s: %s\n",
131                     poptBadOption(pc, POPT_BADOPTION_NOALIAS),
132                     poptStrerror(opt));
133             exit(1);
134         }
135     }
136
137     if (explode_mod && !empties_mod)
138         empties_mod = 1024;
139
140     argv = (char**)poptGetArgs(pc);
141     if (!argv || argv[1]) {
142         fprintf(stderr, "Usage: wildtest [OPTIONS] TESTFILE\n");
143         exit(1);
144     }
145
146     if ((fp = fopen(*argv, "r")) == NULL) {
147         fprintf(stderr, "Unable to open %s\n", *argv);
148         exit(1);
149     }
150
151     line = 0;
152     while (fgets(buf, sizeof buf, fp)) {
153         line++;
154         if (*buf == '#' || *buf == '\n')
155             continue;
156         for (s = buf, i = 0; i <= 1; i++) {
157             if (*s == '1')
158                 flag[i] = 1;
159             else if (*s == '0')
160                 flag[i] = 0;
161             else
162                 flag[i] = -1;
163             if (*++s != ' ' && *s != '\t')
164                 flag[i] = -1;
165             if (flag[i] < 0) {
166                 fprintf(stderr, "Invalid flag syntax on line %d of %s:\n%s",
167                         line, *argv, buf);
168                 exit(1);
169             }
170             while (*++s == ' ' || *s == '\t') {}
171         }
172         for (i = 0; i <= 1; i++) {
173             if (*s == '\'' || *s == '"' || *s == '`') {
174                 char quote = *s++;
175                 string[i] = s;
176                 while (*s && *s != quote) s++;
177                 if (!*s) {
178                     fprintf(stderr, "Unmatched quote on line %d of %s:\n%s",
179                             line, *argv, buf);
180                     exit(1);
181                 }
182                 end[i] = s;
183             }
184             else {
185                 if (!*s || *s == '\n') {
186                     fprintf(stderr, "Not enough strings on line %d of %s:\n%s",
187                             line, *argv, buf);
188                     exit(1);
189                 }
190                 string[i] = s;
191                 while (*++s && *s != ' ' && *s != '\t' && *s != '\n') {}
192                 end[i] = s;
193             }
194             while (*++s == ' ' || *s == '\t') {}
195         }
196         *end[0] = *end[1] = '\0';
197         run_test(line, flag[0], flag[1], string[0], string[1]);
198     }
199
200     if (!wildmatch_errors)
201         fputs("No", stdout);
202     else
203         printf("%d", wildmatch_errors);
204     printf(" wildmatch error%s found.\n", wildmatch_errors == 1? "" : "s");
205
206 #ifdef COMPARE_WITH_FNMATCH
207     if (!fnmatch_errors)
208         fputs("No", stdout);
209     else
210         printf("%d", fnmatch_errors);
211     printf(" fnmatch error%s found.\n", fnmatch_errors == 1? "" : "s");
212
213 #endif
214
215     return 0;
216 }