- Updated the address for the FSF in the opening comment.
[rsync/rsync.git] / wildtest.c
index 52797d2..5286b64 100644 (file)
 /*
-**  wildmatch test suite.
-*/
-
-#include "rsync.h"
-#include "lib/wildmatch.h"
-
-#define COMPARE_WITH_FNMATCH
+ * Test suite for the wildmatch code.
+ *
+ * Copyright (C) 2003, 2004, 2006 Wayne Davison
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*#define COMPARE_WITH_FNMATCH*/
+
+#define WILD_TEST_ITERATIONS
+#include "lib/wildmatch.c"
+
+#include <popt.h>
 
 #ifdef COMPARE_WITH_FNMATCH
 #include <fnmatch.h>
+
+int fnmatch_errors = 0;
 #endif
 
+int wildmatch_errors = 0;
+
 typedef char bool;
 
-#define false 0
-#define true 1
+int output_iterations = 0;
+int explode_mod = 0;
+int empties_mod = 0;
+int empty_at_start = 0;
+int empty_at_end = 0;
+
+static struct poptOption long_options[] = {
+  /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+  {"iterations",     'i', POPT_ARG_NONE,   &output_iterations, 0, 0, 0},
+  {"empties",        'e', POPT_ARG_STRING, 0, 'e', 0, 0},
+  {"explode",        'x', POPT_ARG_INT,    &explode_mod, 0, 0, 0},
+  {0,0,0,0, 0, 0, 0}
+};
 
 /* match just at the start of string (anchored tests) */
 static void
-beg(int n, const char *text, const char *pattern, bool matches, bool same_as_fnmatch)
+run_test(int line, bool matches, bool same_as_fnmatch,
+        const char *text, const char *pattern)
 {
     bool matched;
 #ifdef COMPARE_WITH_FNMATCH
     bool fn_matched;
     int flags = strstr(pattern, "**")? 0 : FNM_PATHNAME;
+#else
+    same_as_fnmatch = 0; /* Get rid of unused-variable compiler warning. */
 #endif
 
-    matched = wildmatch(pattern, text);
+    if (explode_mod) {
+       char buf[MAXPATHLEN*2], *texts[MAXPATHLEN];
+       int pos = 0, cnt = 0, ndx = 0, len = strlen(text);
+
+       if (empty_at_start)
+           texts[ndx++] = "";
+       /* An empty string must turn into at least one empty array item. */
+       while (1) {
+           texts[ndx] = buf + ndx * (explode_mod + 1);
+           strlcpy(texts[ndx++], text + pos, explode_mod + 1);
+           if (pos + explode_mod >= len)
+               break;
+           pos += explode_mod;
+           if (!(++cnt % empties_mod))
+               texts[ndx++] = "";
+       }
+       if (empty_at_end)
+           texts[ndx++] = "";
+       texts[ndx] = NULL;
+       matched = wildmatch_array(pattern, (const char**)texts, 0);
+    } else
+       matched = wildmatch(pattern, text);
 #ifdef COMPARE_WITH_FNMATCH
     fn_matched = !fnmatch(pattern, text, flags);
 #endif
     if (matched != matches) {
-       printf("wildmatch failure on #%d:\n  %s\n  %s\n  expected %d\n",
-              n, text, pattern, matches);
+       printf("wildmatch failure on line %d:\n  %s\n  %s\n  expected %s match\n",
+              line, text, pattern, matches? "a" : "NO");
+       wildmatch_errors++;
     }
 #ifdef COMPARE_WITH_FNMATCH
     if (fn_matched != (matches ^ !same_as_fnmatch)) {
-       printf("fnmatch disagreement on #%d:\n  %s\n  %s\n  expected %d\n",
-              n, text, pattern, matches ^ !same_as_fnmatch);
+       printf("fnmatch disagreement on line %d:\n  %s\n  %s\n  expected %s match\n",
+              line, text, pattern, matches ^ !same_as_fnmatch? "a" : "NO");
+       fnmatch_errors++;
     }
 #endif
+    if (output_iterations) {
+       printf("%d: \"%s\" iterations = %d\n", line, pattern,
+              wildmatch_iteration_count);
+    }
 }
 
-/* match after any slash (non-anchored tests) */
-static void
-end(int n, const char *text, const char *pattern, bool matches, bool same_as_fnmatch)
+int
+main(int argc, char **argv)
 {
-    bool matched = false;
-#ifdef COMPARE_WITH_FNMATCH
-    bool fn_matched = false;
-    int flags = strstr(pattern, "**")? 0 : FNM_PATHNAME;
-#endif
+    char buf[2048], *s, *string[2], *end[2];
+    const char *arg;
+    FILE *fp;
+    int opt, line, i, flag[2];
+    poptContext pc = poptGetContext("wildtest", argc, (const char**)argv,
+                                   long_options, 0);
+
+    while ((opt = poptGetNextOpt(pc)) != -1) {
+       switch (opt) {
+         case 'e':
+           arg = poptGetOptArg(pc);
+           empties_mod = atoi(arg);
+           if (strchr(arg, 's'))
+               empty_at_start = 1;
+           if (strchr(arg, 'e'))
+               empty_at_end = 1;
+           if (!explode_mod)
+               explode_mod = 1024;
+           break;
+         default:
+           fprintf(stderr, "%s: %s\n",
+                   poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+                   poptStrerror(opt));
+           exit(1);
+       }
+    }
 
-    if (strncmp(pattern, "**", 2) == 0) {
-       matched = wildmatch(pattern, text);
-#ifdef COMPARE_WITH_FNMATCH
-       fn_matched = !fnmatch(pattern, text, flags);
-#endif
+    if (explode_mod && !empties_mod)
+       empties_mod = 1024;
+
+    argv = (char**)poptGetArgs(pc);
+    if (!argv || argv[1]) {
+       fprintf(stderr, "Usage: wildtest [OPTIONS] TESTFILE\n");
+       exit(1);
     }
-    else {
-       const char *t = text;
-       while (1) {
-#ifdef COMPARE_WITH_FNMATCH
-           if (!fn_matched)
-               fn_matched = !fnmatch(pattern, t, flags);
-#endif
-           if (wildmatch(pattern, t)) {
-               matched = true;
-               break;
+
+    if ((fp = fopen(*argv, "r")) == NULL) {
+       fprintf(stderr, "Unable to open %s\n", *argv);
+       exit(1);
+    }
+
+    line = 0;
+    while (fgets(buf, sizeof buf, fp)) {
+       line++;
+       if (*buf == '#' || *buf == '\n')
+           continue;
+       for (s = buf, i = 0; i <= 1; i++) {
+           if (*s == '1')
+               flag[i] = 1;
+           else if (*s == '0')
+               flag[i] = 0;
+           else
+               flag[i] = -1;
+           if (*++s != ' ' && *s != '\t')
+               flag[i] = -1;
+           if (flag[i] < 0) {
+               fprintf(stderr, "Invalid flag syntax on line %d of %s:\n%s",
+                       line, *argv, buf);
+               exit(1);
            }
-#ifdef COMPARE_WITH_FNMATCH
-           if (fn_matched)
-               fn_matched = -1;
-#endif
-           if (!(t = strchr(t, '/')))
-               break;
-           t++;
+           while (*++s == ' ' || *s == '\t') {}
        }
+       for (i = 0; i <= 1; i++) {
+           if (*s == '\'' || *s == '"' || *s == '`') {
+               char quote = *s++;
+               string[i] = s;
+               while (*s && *s != quote) s++;
+               if (!*s) {
+                   fprintf(stderr, "Unmatched quote on line %d of %s:\n%s",
+                           line, *argv, buf);
+                   exit(1);
+               }
+               end[i] = s;
+           }
+           else {
+               if (!*s || *s == '\n') {
+                   fprintf(stderr, "Not enough strings on line %d of %s:\n%s",
+                           line, *argv, buf);
+                   exit(1);
+               }
+               string[i] = s;
+               while (*++s && *s != ' ' && *s != '\t' && *s != '\n') {}
+               end[i] = s;
+           }
+           while (*++s == ' ' || *s == '\t') {}
+       }
+       *end[0] = *end[1] = '\0';
+       run_test(line, flag[0], flag[1], string[0], string[1]);
     }
-    if (matched != matches) {
-       printf("wildmatch failure on #%d:\n  %s\n  %s\n  expected %d\n",
-              n, text, pattern, matches);
-    }
+
+    if (!wildmatch_errors)
+       fputs("No", stdout);
+    else
+       printf("%d", wildmatch_errors);
+    printf(" wildmatch error%s found.\n", wildmatch_errors == 1? "" : "s");
+
 #ifdef COMPARE_WITH_FNMATCH
-    if (fn_matched < 0 || fn_matched != (matches ^ !same_as_fnmatch)) {
-       printf("fnmatch disagreement on #%d:\n  %s\n  %s\n  expected %d\n",
-              n, text, pattern, matches ^ !same_as_fnmatch);
-    }
-#endif
-}
+    if (!fnmatch_errors)
+       fputs("No", stdout);
+    else
+       printf("%d", fnmatch_errors);
+    printf(" fnmatch error%s found.\n", fnmatch_errors == 1? "" : "s");
 
-int
-main(int argc, char **argv)
-{
-    /* Use our args to avoid a compiler warning. */
-    if (argc)
-       argv++;
-
-    /* Basic wildmat features. */
-    /* TEST, "text",           "pattern",              MATCH?, SAME-AS-FNMATCH? */
-    beg(100, "foo",            "foo",                  true,   true);
-    beg(101, "foo",            "bar",                  false,  true);
-    beg(102, "",               "",                     true,   true);
-    beg(103, "foo",            "???",                  true,   true);
-    beg(104, "foo",            "??",                   false,  true);
-    beg(105, "foo",            "*",                    true,   true);
-    beg(106, "foo",            "f*",                   true,   true);
-    beg(107, "foo",            "*f",                   false,  true);
-    beg(108, "foo",            "*foo*",                true,   true);
-    beg(109, "foobar",         "*ob*a*r*",             true,   true);
-    beg(110, "aaaaaaabababab", "*ab",                  true,   true);
-    beg(111, "foo*",           "foo\\*",               true,   true);
-    beg(112, "foobar",         "foo\\*bar",            false,  true);
-    beg(113, "f\\oo",          "f\\\\oo",              true,   true);
-    beg(114, "ball",           "*[al]?",               true,   true);
-    beg(115, "ten",            "[ten]",                false,  true);
-    beg(116, "ten",            "**[!te]",              true,   true);
-    beg(117, "ten",            "**[!ten]",             false,  true);
-    beg(118, "ten",            "t[a-g]n",              true,   true);
-    beg(119, "ten",            "t[!a-g]n",             false,  true);
-    beg(120, "ton",            "t[!a-g]n",             true,   true);
-    beg(121, "]",              "]",                    true,   true);
-    beg(122, "a]b",            "a[]]b",                true,   true);
-    beg(123, "a-b",            "a[]-]b",               true,   true);
-    beg(124, "a]b",            "a[]-]b",               true,   true);
-    beg(125, "aab",            "a[]-]b",               false,  true);
-    beg(126, "aab",            "a[]a-]b",              true,   true);
-
-    /* Extended slash-matching features */
-    /* TEST, "text",           "pattern",              MATCH?, SAME-AS-FNMATCH? */
-    beg(200, "foo/baz/bar",    "foo*bar",              false,  true);
-    beg(201, "foo/baz/bar",    "foo**bar",             true,   true);
-    beg(202, "foo/bar",                "foo?bar",              false,  true);
-    beg(203, "foo/bar",                "foo[/]bar",            true,   false);
-    beg(204, "foo",            "**/foo",               false,  true);
-    beg(205, "/foo",           "**/foo",               true,   true);
-    beg(206, "bar/baz/foo",    "**/foo",               true,   true);
-    beg(207, "bar/baz/foo",    "*/foo",                false,  true);
-    beg(208, "foo/bar/baz",    "**/bar*",              false,  false);
-    beg(209, "foo/bar/baz",    "**/bar**",             true,   true);
-
-    /* Various additional tests. */
-    /* TEST, "text",           "pattern",              MATCH?, SAME-AS-FNMATCH? */
-    beg(300, "acrt",           "a[c-c]st",             false,  true);
-    beg(301, "]",              "[!]-]",                false,  true);
-    beg(302, "a",              "[!]-]",                true,   true);
-    beg(303, "",               "\\",                   false,  true);
-    beg(304, "\\",             "\\",                   false,  true);
-    beg(305, "foo",            "foo",                  true,   true);
-    beg(306, "@foo",           "@foo",                 true,   true);
-    beg(307, "foo",            "@foo",                 false,  true);
-    beg(308, "[ab]",           "\\[ab]",               true,   true);
-    beg(309, "?a?b",           "\\??\\?b",             true,   true);
-    beg(310, "abc",            "\\a\\b\\c",            true,   true);
-    beg(311, "foo",            "",                     false,  true);
-
-    /* Tail-match tests */
-    /* TEST, "text",           "pattern",              MATCH?, SAME-AS-FNMATCH? */
-    end(400, "foo/bar/baz",    "baz",                  true,   true);
-    end(401, "foo/bar/baz",    "bar/baz",              true,   true);
-    end(402, "foo/bar/baz",    "ar/baz",               false,  true);
-    end(403, "foo/bar/baz",    "/bar/baz",             false,  true);
-    end(404, "foo/bar/baz",    "bar",                  false,  true);
-    end(405, "foo/bar/baz/to", "t[o]",                 true,   true);
-
-    /* Additional tests, including some malformed wildmats. */
-    /* TEST, "text",           "pattern",              MATCH?, SAME-AS-FNMATCH? */
-    beg(500, "]",              "[\\-_]",               true,   false);
-    beg(501, "[",              "[\\-_]",               false,  true);
-    beg(502, ".",              "[\\\\-_]",             false,  true);
-    beg(503, "^",              "[\\\\-_]",             true,   false);
-    beg(504, "Z",              "[\\\\-_]",             false,  true);
-    beg(505, "\\",             "[\\]]",                false,  true);
-    beg(506, "ab",             "a[]b",                 false,  true);
-    beg(507, "a[]b",           "a[]b",                 false,  true);
-    beg(508, "ab[",            "ab[",                  false,  true);
-    beg(509, "ab",             "[!",                   false,  true);
-    beg(510, "ab",             "[-",                   false,  true);
-    beg(511, "-",              "[-]",                  true,   true);
-    beg(512, "-",              "[a-",                  false,  true);
-    beg(513, "-",              "[!a-",                 false,  true);
-    beg(514, "-",              "[--A]",                true,   true);
-    beg(515, "5",              "[--A]",                true,   true);
-    beg(516, "\303\206",       "[--A]",                false,  true);
-    beg(517, " ",              "[ --]",                true,   true);
-    beg(518, "$",              "[ --]",                true,   true);
-    beg(519, "-",              "[ --]",                true,   true);
-    beg(520, "0",              "[ --]",                false,  true);
-    beg(521, "-",              "[---]",                true,   true);
-    beg(522, "-",              "[------]",             true,   true);
-    beg(523, "j",              "[a-e-n]",              false,  true);
-    beg(524, "-",              "[a-e-n]",              true,   true);
-    beg(525, "a",              "[!------]",            true,   true);
-    beg(526, "[",              "[]-a]",                false,  true);
-    beg(527, "^",              "[]-a]",                true,   true);
-    beg(528, "^",              "[!]-a]",               false,  true);
-    beg(529, "[",              "[!]-a]",               true,   true);
-    beg(530, "^",              "[a^bc]",               true,   true);
-    beg(531, "-b]",            "[a-]b]",               true,   true);
-    beg(532, "\\]",            "[\\]]",                true,   false);
-    beg(533, "\\",             "[\\]",                 true,   false);
-    beg(534, "\\",             "[!\\]",                false,  false); /*FN?*/
-    beg(535, "G",              "[A-\\]",               true,   false);
-    beg(536, "aaabbb",         "b*a",                  false,  true);
-    beg(537, "aabcaa",         "*ba*",                 false,  true);
-    beg(538, ",",              "[,]",                  true,   true);
-    beg(539, ",",              "[\\,]",                true,   true);
-    beg(540, "\\",             "[\\,]",                true,   false);
-    beg(541, "-",              "[,-.]",                true,   true);
-    beg(542, "+",              "[,-.]",                false,  true);
-    beg(543, "-.]",            "[,-.]",                false,  true);
+#endif
 
     return 0;
 }