1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "testutil.h"
18 #include "apr_file_info.h"
19 #include "apr_fnmatch.h"
20 #include "apr_tables.h"
21
22 /* XXX NUM_FILES must be equal to the nummber of expected files with a
23 * .txt extension in the data directory at the time testfnmatch
24 * happens to be run (!?!). */
25
26 #define NUM_FILES (5)
27
28 #define APR_FNM_BITS 15
29 #define APR_FNM_FAILBIT 256
30
31 #define FAILS_IF(X) 0, X
32 #define SUCCEEDS_IF(X) X, 256
33 #define SUCCEEDS 0, 256
34 #define FAILS 256, 0
35
36 static struct pattern_s {
37 const char *pattern;
38 const char *string;
39 int require_flags;
40 int fail_flags;
41 } patterns[] = {
42
43 /* Pattern, String to Test, Flags to Match */
44 {"", "test", FAILS},
45 {"", "*", FAILS},
46 {"test", "*", FAILS},
47 {"test", "test", SUCCEEDS},
48
49 /* Remember C '\\' is a single backslash in pattern */
50 {"te\\st", "test", FAILS_IF(APR_FNM_NOESCAPE)},
51 {"te\\\\st", "te\\st", FAILS_IF(APR_FNM_NOESCAPE)},
52 {"te\\*t", "te*t", FAILS_IF(APR_FNM_NOESCAPE)},
53 {"te\\*t", "test", FAILS},
54 {"te\\?t", "te?t", FAILS_IF(APR_FNM_NOESCAPE)},
55 {"te\\?t", "test", FAILS},
56
57 {"tesT", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
58 {"test", "Test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
59 {"tEst", "teSt", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
60
61 {"?est", "test", SUCCEEDS},
62 {"te?t", "test", SUCCEEDS},
63 {"tes?", "test", SUCCEEDS},
64 {"test?", "test", FAILS},
65
66 {"*", "", SUCCEEDS},
67 {"*", "test", SUCCEEDS},
68 {"*test", "test", SUCCEEDS},
69 {"*est", "test", SUCCEEDS},
70 {"*st", "test", SUCCEEDS},
71 {"t*t", "test", SUCCEEDS},
72 {"te*t", "test", SUCCEEDS},
73 {"te*st", "test", SUCCEEDS},
74 {"te*", "test", SUCCEEDS},
75 {"tes*", "test", SUCCEEDS},
76 {"test*", "test", SUCCEEDS},
77
78 {".[\\-\\t]", ".t", SUCCEEDS},
79 {"test*?*[a-z]*", "testgoop", SUCCEEDS},
80 {"te[^x]t", "test", SUCCEEDS},
81 {"te[^abc]t", "test", SUCCEEDS},
82 {"te[^x]t", "test", SUCCEEDS},
83 {"te[!x]t", "test", SUCCEEDS},
84 {"te[^x]t", "text", FAILS},
85 {"te[^\\x]t", "text", FAILS},
86 {"te[^x\\", "text", FAILS},
87 {"te[/]t", "text", FAILS},
88 {"te[S]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
89 {"te[r-t]t", "test", SUCCEEDS},
90 {"te[r-t]t", "teSt", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
91 {"te[r-T]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
92 {"te[R-T]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
93 {"te[r-Tz]t", "tezt", SUCCEEDS},
94 {"te[R-T]t", "tent", FAILS},
95 {"tes[]t]", "test", SUCCEEDS},
96 {"tes[t-]", "test", SUCCEEDS},
97 {"tes[t-]]", "test]", SUCCEEDS},
98 {"tes[t-]]", "test", FAILS},
99 {"tes[u-]", "test", FAILS},
100 {"tes[t-]", "tes[t-]", FAILS},
101 {"test[/-/]", "test[/-/]", SUCCEEDS_IF(APR_FNM_PATHNAME)},
102 {"test[\\/-/]", "test[/-/]", APR_FNM_PATHNAME, APR_FNM_NOESCAPE},
103 {"test[/-\\/]", "test[/-/]", APR_FNM_PATHNAME, APR_FNM_NOESCAPE},
104 {"test[/-/]", "test/", FAILS_IF(APR_FNM_PATHNAME)},
105 {"test[\\/-/]", "test/", FAILS_IF(APR_FNM_PATHNAME)},
106 {"test[/-\\/]", "test/", FAILS_IF(APR_FNM_PATHNAME)},
107
108 {"/", "", FAILS},
109 {"", "/", FAILS},
110 {"/test", "test", FAILS},
111 {"test", "/test", FAILS},
112 {"test/", "test", FAILS},
113 {"test", "test/", FAILS},
114 {"\\/test", "/test", FAILS_IF(APR_FNM_NOESCAPE)},
115 {"*test", "/test", FAILS_IF(APR_FNM_PATHNAME)},
116 {"/*/test/", "/test", FAILS},
117 {"/*/test/", "/test/test/", SUCCEEDS},
118 {"test/this", "test/", FAILS},
119 {"test/", "test/this", FAILS},
120 {"test*/this", "test/this", SUCCEEDS},
121 {"test*/this", "test/that", FAILS},
122 {"test/*this", "test/this", SUCCEEDS},
123
124 {".*", ".this", SUCCEEDS},
125 {"*", ".this", FAILS_IF(APR_FNM_PERIOD)},
126 {"?this", ".this", FAILS_IF(APR_FNM_PERIOD)},
127 {"[.]this", ".this", FAILS_IF(APR_FNM_PERIOD)},
128
129 {"test/this", "test/this", SUCCEEDS},
130 {"test?this", "test/this", FAILS_IF(APR_FNM_PATHNAME)},
131 {"test*this", "test/this", FAILS_IF(APR_FNM_PATHNAME)},
132 {"test[/]this", "test/this", FAILS_IF(APR_FNM_PATHNAME)},
133
134 {"test/.*", "test/.this", SUCCEEDS},
135 {"test/*", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)},
136 {"test/?this", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)},
137 {"test/[.]this", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)},
138
139 {NULL, NULL, 0}
140 };
141
142
143
test_fnmatch(abts_case * tc,void * data)144 static void test_fnmatch(abts_case *tc, void *data)
145 {
146 struct pattern_s *test = patterns;
147 char buf[80];
148 int i = APR_FNM_BITS + 1;
149 int res;
150
151 for (test = patterns; test->pattern; ++test)
152 {
153 for (i = 0; i <= APR_FNM_BITS; ++i)
154 {
155 res = apr_fnmatch(test->pattern, test->string, i);
156 if (((i & test->require_flags) != test->require_flags)
157 || ((i & test->fail_flags) == test->fail_flags)) {
158 if (res != APR_FNM_NOMATCH)
159 break;
160 }
161 else {
162 if (res != 0)
163 break;
164 }
165 }
166 if (i <= APR_FNM_BITS)
167 break;
168 }
169
170 if (i <= APR_FNM_BITS) {
171 sprintf(buf, "apr_fnmatch(\"%s\", \"%s\", %d) returns %d\n",
172 test->pattern, test->string, i, res);
173 abts_fail(tc, buf, __LINE__);
174 }
175 }
176
test_fnmatch_test(abts_case * tc,void * data)177 static void test_fnmatch_test(abts_case *tc, void *data)
178 {
179 static const struct test {
180 const char *pattern;
181 int result;
182 } ft_tests[] = {
183 { "a*b", 1 },
184 { "a?", 1 },
185 { "a\\b?", 1 },
186 { "a[b-c]", 1 },
187 { "a", 0 },
188 { "a\\", 0 },
189 { NULL, 0 }
190 };
191 const struct test *t;
192
193 for (t = ft_tests; t->pattern != NULL; t++) {
194 int res = apr_fnmatch_test(t->pattern);
195
196 if (res != t->result) {
197 char buf[128];
198
199 sprintf(buf, "apr_fnmatch_test(\"%s\") = %d, expected %d\n",
200 t->pattern, res, t->result);
201 abts_fail(tc, buf, __LINE__);
202 }
203 }
204 }
205
test_glob(abts_case * tc,void * data)206 static void test_glob(abts_case *tc, void *data)
207 {
208 int i;
209 char **list;
210 apr_array_header_t *result;
211
212 APR_ASSERT_SUCCESS(tc, "glob match against data/*.txt",
213 apr_match_glob("data\\*.txt", &result, p));
214
215 ABTS_INT_EQUAL(tc, NUM_FILES, result->nelts);
216
217 list = (char **)result->elts;
218 for (i = 0; i < result->nelts; i++) {
219 char *dot = strrchr(list[i], '.');
220 ABTS_STR_EQUAL(tc, ".txt", dot);
221 }
222 }
223
test_glob_currdir(abts_case * tc,void * data)224 static void test_glob_currdir(abts_case *tc, void *data)
225 {
226 int i;
227 char **list;
228 apr_array_header_t *result;
229 apr_filepath_set("data", p);
230
231 APR_ASSERT_SUCCESS(tc, "glob match against *.txt with data as current",
232 apr_match_glob("*.txt", &result, p));
233
234
235 ABTS_INT_EQUAL(tc, NUM_FILES, result->nelts);
236
237 list = (char **)result->elts;
238 for (i = 0; i < result->nelts; i++) {
239 char *dot = strrchr(list[i], '.');
240 ABTS_STR_EQUAL(tc, ".txt", dot);
241 }
242 apr_filepath_set("..", p);
243 }
244
testfnmatch(abts_suite * suite)245 abts_suite *testfnmatch(abts_suite *suite)
246 {
247 suite = ADD_SUITE(suite)
248
249 abts_run_test(suite, test_fnmatch, NULL);
250 abts_run_test(suite, test_fnmatch_test, NULL);
251 abts_run_test(suite, test_glob, NULL);
252 abts_run_test(suite, test_glob_currdir, NULL);
253
254 return suite;
255 }
256
257