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