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 36static 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 144static 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 177static 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 206static 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 224static 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 245abts_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