| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "testutil.h" |
| #include "apr_file_info.h" |
| #include "apr_fnmatch.h" |
| #include "apr_tables.h" |
| |
| /* XXX NUM_FILES must be equal to the nummber of expected files with a |
| * .txt extension in the data directory at the time testfnmatch |
| * happens to be run (!?!). */ |
| |
| #define NUM_FILES (2) |
| |
| #define APR_FNM_BITS 15 |
| #define APR_FNM_FAILBIT 256 |
| |
| #define FAILS_IF(X) 0, X |
| #define SUCCEEDS_IF(X) X, 256 |
| #define SUCCEEDS 0, 256 |
| #define FAILS 256, 0 |
| |
| static struct pattern_s { |
| const char *pattern; |
| const char *string; |
| int require_flags; |
| int fail_flags; |
| } patterns[] = { |
| |
| /* Pattern, String to Test, Flags to Match */ |
| {"", "test", FAILS}, |
| {"", "*", FAILS}, |
| {"test", "*", FAILS}, |
| {"test", "test", SUCCEEDS}, |
| |
| /* Remember C '\\' is a single backslash in pattern */ |
| {"te\\st", "test", FAILS_IF(APR_FNM_NOESCAPE)}, |
| {"te\\\\st", "te\\st", FAILS_IF(APR_FNM_NOESCAPE)}, |
| {"te\\*t", "te*t", FAILS_IF(APR_FNM_NOESCAPE)}, |
| {"te\\*t", "test", FAILS}, |
| {"te\\?t", "te?t", FAILS_IF(APR_FNM_NOESCAPE)}, |
| {"te\\?t", "test", FAILS}, |
| |
| {"tesT", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, |
| {"test", "Test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, |
| {"tEst", "teSt", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, |
| |
| {"?est", "test", SUCCEEDS}, |
| {"te?t", "test", SUCCEEDS}, |
| {"tes?", "test", SUCCEEDS}, |
| {"test?", "test", FAILS}, |
| |
| {"*", "", SUCCEEDS}, |
| {"*", "test", SUCCEEDS}, |
| {"*test", "test", SUCCEEDS}, |
| {"*est", "test", SUCCEEDS}, |
| {"*st", "test", SUCCEEDS}, |
| {"t*t", "test", SUCCEEDS}, |
| {"te*t", "test", SUCCEEDS}, |
| {"te*st", "test", SUCCEEDS}, |
| {"te*", "test", SUCCEEDS}, |
| {"tes*", "test", SUCCEEDS}, |
| {"test*", "test", SUCCEEDS}, |
| |
| {".[\\-\\t]", ".t", SUCCEEDS}, |
| {"test*?*[a-z]*", "testgoop", SUCCEEDS}, |
| {"te[^x]t", "test", SUCCEEDS}, |
| {"te[^abc]t", "test", SUCCEEDS}, |
| {"te[^x]t", "test", SUCCEEDS}, |
| {"te[!x]t", "test", SUCCEEDS}, |
| {"te[^x]t", "text", FAILS}, |
| {"te[^\\x]t", "text", FAILS}, |
| {"te[^x\\", "text", FAILS}, |
| {"te[/]t", "text", FAILS}, |
| {"te[S]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, |
| {"te[r-t]t", "test", SUCCEEDS}, |
| {"te[r-t]t", "teSt", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, |
| {"te[r-T]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, |
| {"te[R-T]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, |
| {"te[r-Tz]t", "tezt", SUCCEEDS}, |
| {"te[R-T]t", "tent", FAILS}, |
| {"tes[]t]", "test", SUCCEEDS}, |
| {"tes[t-]", "test", SUCCEEDS}, |
| {"tes[t-]]", "test]", SUCCEEDS}, |
| {"tes[t-]]", "test", FAILS}, |
| {"tes[u-]", "test", FAILS}, |
| {"tes[t-]", "tes[t-]", FAILS}, |
| {"test[/-/]", "test[/-/]", SUCCEEDS_IF(APR_FNM_PATHNAME)}, |
| {"test[\\/-/]", "test[/-/]", APR_FNM_PATHNAME, APR_FNM_NOESCAPE}, |
| {"test[/-\\/]", "test[/-/]", APR_FNM_PATHNAME, APR_FNM_NOESCAPE}, |
| {"test[/-/]", "test/", FAILS_IF(APR_FNM_PATHNAME)}, |
| {"test[\\/-/]", "test/", FAILS_IF(APR_FNM_PATHNAME)}, |
| {"test[/-\\/]", "test/", FAILS_IF(APR_FNM_PATHNAME)}, |
| |
| {"/", "", FAILS}, |
| {"", "/", FAILS}, |
| {"/test", "test", FAILS}, |
| {"test", "/test", FAILS}, |
| {"test/", "test", FAILS}, |
| {"test", "test/", FAILS}, |
| {"\\/test", "/test", FAILS_IF(APR_FNM_NOESCAPE)}, |
| {"*test", "/test", FAILS_IF(APR_FNM_PATHNAME)}, |
| {"/*/test/", "/test", FAILS}, |
| {"/*/test/", "/test/test/", SUCCEEDS}, |
| {"test/this", "test/", FAILS}, |
| {"test/", "test/this", FAILS}, |
| {"test*/this", "test/this", SUCCEEDS}, |
| {"test*/this", "test/that", FAILS}, |
| {"test/*this", "test/this", SUCCEEDS}, |
| |
| {".*", ".this", SUCCEEDS}, |
| {"*", ".this", FAILS_IF(APR_FNM_PERIOD)}, |
| {"?this", ".this", FAILS_IF(APR_FNM_PERIOD)}, |
| {"[.]this", ".this", FAILS_IF(APR_FNM_PERIOD)}, |
| |
| {"test/this", "test/this", SUCCEEDS}, |
| {"test?this", "test/this", FAILS_IF(APR_FNM_PATHNAME)}, |
| {"test*this", "test/this", FAILS_IF(APR_FNM_PATHNAME)}, |
| {"test[/]this", "test/this", FAILS_IF(APR_FNM_PATHNAME)}, |
| |
| {"test/.*", "test/.this", SUCCEEDS}, |
| {"test/*", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)}, |
| {"test/?this", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)}, |
| {"test/[.]this", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)}, |
| |
| {NULL, NULL, 0} |
| }; |
| |
| |
| |
| static void test_fnmatch(abts_case *tc, void *data) |
| { |
| struct pattern_s *test = patterns; |
| char buf[80]; |
| int i = APR_FNM_BITS + 1; |
| int res; |
| |
| for (test = patterns; test->pattern; ++test) |
| { |
| for (i = 0; i <= APR_FNM_BITS; ++i) |
| { |
| res = apr_fnmatch(test->pattern, test->string, i); |
| if (((i & test->require_flags) != test->require_flags) |
| || ((i & test->fail_flags) == test->fail_flags)) { |
| if (res != APR_FNM_NOMATCH) |
| break; |
| } |
| else { |
| if (res != 0) |
| break; |
| } |
| } |
| if (i <= APR_FNM_BITS) |
| break; |
| } |
| |
| if (i <= APR_FNM_BITS) { |
| sprintf(buf, "apr_fnmatch(\"%s\", \"%s\", %d) returns %d\n", |
| test->pattern, test->string, i, res); |
| abts_fail(tc, buf, __LINE__); |
| } |
| } |
| |
| static void test_fnmatch_test(abts_case *tc, void *data) |
| { |
| static const struct test { |
| const char *pattern; |
| int result; |
| } ft_tests[] = { |
| { "a*b", 1 }, |
| { "a?", 1 }, |
| { "a\\b?", 1 }, |
| { "a[b-c]", 1 }, |
| { "a", 0 }, |
| { "a\\", 0 }, |
| { NULL, 0 } |
| }; |
| const struct test *t; |
| |
| for (t = ft_tests; t->pattern != NULL; t++) { |
| int res = apr_fnmatch_test(t->pattern); |
| |
| if (res != t->result) { |
| char buf[128]; |
| |
| sprintf(buf, "apr_fnmatch_test(\"%s\") = %d, expected %d\n", |
| t->pattern, res, t->result); |
| abts_fail(tc, buf, __LINE__); |
| } |
| } |
| } |
| |
| static void test_glob(abts_case *tc, void *data) |
| { |
| int i; |
| char **list; |
| apr_array_header_t *result; |
| |
| APR_ASSERT_SUCCESS(tc, "glob match against data/*.txt", |
| apr_match_glob("data\\*.txt", &result, p)); |
| |
| ABTS_INT_EQUAL(tc, NUM_FILES, result->nelts); |
| |
| list = (char **)result->elts; |
| for (i = 0; i < result->nelts; i++) { |
| char *dot = strrchr(list[i], '.'); |
| ABTS_STR_EQUAL(tc, ".txt", dot); |
| } |
| } |
| |
| static void test_glob_currdir(abts_case *tc, void *data) |
| { |
| int i; |
| char **list; |
| apr_array_header_t *result; |
| apr_filepath_set("data", p); |
| |
| APR_ASSERT_SUCCESS(tc, "glob match against *.txt with data as current", |
| apr_match_glob("*.txt", &result, p)); |
| |
| |
| ABTS_INT_EQUAL(tc, NUM_FILES, result->nelts); |
| |
| list = (char **)result->elts; |
| for (i = 0; i < result->nelts; i++) { |
| char *dot = strrchr(list[i], '.'); |
| ABTS_STR_EQUAL(tc, ".txt", dot); |
| } |
| apr_filepath_set("..", p); |
| } |
| |
| abts_suite *testfnmatch(abts_suite *suite) |
| { |
| suite = ADD_SUITE(suite) |
| |
| abts_run_test(suite, test_fnmatch, NULL); |
| abts_run_test(suite, test_fnmatch_test, NULL); |
| abts_run_test(suite, test_glob, NULL); |
| abts_run_test(suite, test_glob_currdir, NULL); |
| |
| return suite; |
| } |
| |