X-Git-Url: https://git.gag.com/?p=debian%2Famanda;a=blobdiff_plain;f=common-src%2Fmatch-test.c;h=63717385b68aef34bb19ec6b0931c6f9c5b3d325;hp=44c8d1e83011d6353cbf467905fa935e7d50dab7;hb=b116e9366c7b2ea2c2eb53b0a13df4090e176235;hpb=fd48f3e498442f0cbff5f3606c7c403d0566150e diff --git a/common-src/match-test.c b/common-src/match-test.c index 44c8d1e..6371738 100644 --- a/common-src/match-test.c +++ b/common-src/match-test.c @@ -22,36 +22,522 @@ #include "testutils.h" #include "match.h" -/* NOTE: this is an incomplete set of tests for match.c */ - /* * Tests */ -/**** - * Test some host expressions - */ static int -test_host_match(void) +test_validate_regexp(void) +{ + gboolean ok = TRUE; + struct { + char *regexp; + gboolean should_validate; + } tests[] = { + { ".*", TRUE }, + { "*", FALSE }, + { "[abc", FALSE }, + { "(abc", FALSE }, + { "{1,}", FALSE }, + { NULL, FALSE }, + }, *t; + + for (t = tests; t->regexp; t++) { + char *validated_err = validate_regexp(t->regexp); + if (!validated_err != !!t->should_validate) { + ok = FALSE; + if (t->should_validate) { + g_fprintf(stderr, "should have validated regular expr %s: %s\n", + t->regexp, validated_err); + } else { + g_fprintf(stderr, "unexpectedly validated regular expr %s\n", + t->regexp); + } + } + } + + return ok; +} + +static int +test_match(void) +{ + gboolean ok = TRUE; + struct { + char *expr, *str; + gboolean should_match, should_match_no_newline; + } tests[] = { + /* literal, unanchored matching */ + { "a", "a", TRUE, TRUE }, + { "a", "A", FALSE, FALSE }, + { "a", "ab", TRUE, TRUE }, + { "a", "ba", TRUE, TRUE }, + { "a", "bab", TRUE, TRUE }, + + /* dot */ + { ".", "", FALSE, FALSE }, + { ".", "a", TRUE, TRUE }, + { "..", "a", FALSE, FALSE }, + { "..", "bc", TRUE, TRUE }, + + /* brackets */ + { "[abc]", "xbx", TRUE, TRUE }, + { "[abc]", "xyz", FALSE, FALSE }, + { "[^abc]", "cba", FALSE, FALSE }, + { "[^abc]", "xyz", TRUE, TRUE }, + { "[a-c]", "b", TRUE, TRUE }, + { "[^a-c]", "-", TRUE, TRUE }, + { "[1-9-]", "-", TRUE, TRUE }, + { "[ab\\-cd]", "-", FALSE, FALSE }, /* NOTE! */ + + /* anchors */ + { "^xy", "xyz", TRUE, TRUE }, + { "^xy", "wxyz", FALSE, FALSE }, + { "yz$", "xyz", TRUE, TRUE }, + { "yz$", "yza", FALSE, FALSE }, + { "^123$", "123", TRUE, TRUE }, + { "^123$", "0123", FALSE, FALSE }, + { "^123$", "1234", FALSE, FALSE }, + + /* capture groups */ + { "([a-c])([x-y])", "pqaxyr", TRUE, TRUE }, + { "([a-c])([x-y])", "paqrxy", FALSE, FALSE }, + { "([a-c])/\\1", "a/b", FALSE, FALSE }, + { "([a-c])/\\1", "c/c", TRUE, TRUE }, + + /* * */ + { ">[0-9]*<", "><", TRUE, TRUE }, + { ">[0-9]*<", ">3<", TRUE, TRUE }, + { ">[0-9]*<", ">34<", TRUE, TRUE }, + { ">[0-9]*<", ">345<", TRUE, TRUE }, + { ">[0-9]*<", ">x<", FALSE, FALSE }, + + /* | */ + { ":(abc|ABC);", ":abc;", TRUE, TRUE }, + { ":(abc|ABC);", ":ABC;", TRUE, TRUE }, + { ":(abc|ABC);", ":abcBC;", FALSE, FALSE }, + + /* + */ + { ">[0-9]+<", "><", FALSE, FALSE }, + { ">[0-9]+<", ">3<", TRUE, TRUE }, + { ">[0-9]+<", ">34<", TRUE, TRUE }, + { ">[0-9]+<", ">345<", TRUE, TRUE }, + { ">[0-9]+<", ">x<", FALSE, FALSE }, + + /* { .. } */ + { ">[0-9]{0,1}<", "><", TRUE, TRUE }, + { ">[0-9]{0,1}<", ">9<", TRUE, TRUE }, + { ">[0-9]{0,1}<", ">98<", FALSE, FALSE }, + { ">[0-9]{2,3}<", "><", FALSE, FALSE }, + { ">[0-9]{2,3}<", ">5<", FALSE, FALSE }, + { ">[0-9]{2,3}<", ">55<", TRUE, TRUE }, + { ">[0-9]{2,3}<", ">555<", TRUE, TRUE }, + { ">[0-9]{2,3}<", ">5555<", FALSE, FALSE }, + + /* quoting metacharacters */ + { "\\\\", "\\", TRUE, TRUE }, + { "\\,", ",", TRUE, TRUE }, + { "\\[", "[", TRUE, TRUE }, + { "\\*", "*", TRUE, TRUE }, + { "\\?", "?", TRUE, TRUE }, + { "\\+", "+", TRUE, TRUE }, + { "\\.", ".", TRUE, TRUE }, + { "\\|", "|", TRUE, TRUE }, + { "\\^", "^", TRUE, TRUE }, + { "\\$", "$", TRUE, TRUE }, + + /* differences between match and match_no_newline */ + { "x.y", "x\ny", FALSE, TRUE }, + { "x[^yz]y", "x\ny", FALSE, TRUE }, + { "^y", "x\ny", TRUE, FALSE }, + { "x$", "x\ny", TRUE, FALSE }, + + { NULL, NULL, FALSE, FALSE }, + }, *t; + + for (t = tests; t->expr; t++) { + gboolean matched = match(t->expr, t->str); + if (!!matched != !!t->should_match) { + ok = FALSE; + if (t->should_match) { + g_fprintf(stderr, "%s should have matched regular expr %s\n", + t->str, t->expr); + } else { + g_fprintf(stderr, "%s unexpectedly matched regular expr %s\n", + t->str, t->expr); + } + } + + matched = match_no_newline(t->expr, t->str); + if (!!matched != !!t->should_match_no_newline) { + ok = FALSE; + if (t->should_match) { + g_fprintf(stderr, "%s should have matched (no_newline) regular expr %s\n", + t->str, t->expr); + } else { + g_fprintf(stderr, "%s unexpectedly matched (no_newline) regular expr %s\n", + t->str, t->expr); + } + } + } + + return ok; +} + +static int +test_validate_glob(void) +{ + gboolean ok = TRUE; + struct { + char *glob; + gboolean should_validate; + } tests[] = { + { "foo.*", TRUE }, + { "*.txt", TRUE }, + { "x[abc]y", TRUE }, + { "x[!abc]y", TRUE }, + { "[abc", FALSE }, + { "[!abc", FALSE }, + { "??*", TRUE }, + { "**?", TRUE }, /* legal, but weird */ + { "foo\\", FALSE }, /* un-escaped \ is illegal */ + { "foo\\\\", TRUE }, /* but escaped is OK */ + { "(){}+.^$|", TRUE }, /* funny characters OK */ + { "/usr/bin/*", TRUE }, /* filename seps are OK */ + { NULL, FALSE }, + }, *t; + + for (t = tests; t->glob; t++) { + char *validated_err = validate_glob(t->glob); + if (!validated_err != !!t->should_validate) { + ok = FALSE; + if (t->should_validate) { + g_fprintf(stderr, "should have validated glob %s: %s\n", + t->glob, validated_err); + } else { + g_fprintf(stderr, "unexpectedly validated glob %s\n", + t->glob); + } + } + } + + return ok; +} + +static int +test_glob_to_regex(void) +{ + gboolean ok = TRUE; + struct { char *glob, *regex; } tests[] = { + { "abc", "^abc$" }, + { "*.txt", "^[^/]*\\.txt$" }, + { "?.txt", "^[^/]\\.txt$" }, + { "?*.txt", "^[^/][^/]*\\.txt$" }, + { "foo.[tT][xX][tT]", "^foo\\.[tT][xX][tT]$" }, + { "foo.[tT][!yY][tT]", "^foo\\.[tT][^yY][tT]$" }, + { "foo\\\\", "^foo\\\\$" }, + { "(){}+.^$|", "^\\(\\)\\{\\}\\+\\.\\^\\$\\|$" }, + { "/usr/bin/*", "^/usr/bin/[^/]*$" }, + { NULL, NULL }, + }, *t; + + for (t = tests; t->glob; t++) { + char *regex = glob_to_regex(t->glob); + if (0 != strcmp(regex, t->regex)) { + ok = FALSE; + g_fprintf(stderr, "glob_to_regex(\"%s\") returned \"%s\"; expected \"%s\"\n", + t->glob, regex, t->regex); + } + } + + return ok; +} + +static int +test_match_glob(void) +{ + gboolean ok = TRUE; + struct { + char *expr, *str; + gboolean should_match; + } tests[] = { + /* literal, unanchored matching */ + { "a", "a", TRUE }, + + { "abc", "abc", TRUE }, + { "abc", "abcd", FALSE }, + { "abc", "dabc", FALSE }, + { "abc", "/usr/bin/abc", FALSE }, + + { "*.txt", "foo.txt", TRUE }, + { "*.txt", ".txt", TRUE }, + { "*.txt", "txt", FALSE }, + + { "?.txt", "X.txt", TRUE }, + { "?.txt", ".txt", FALSE }, + { "?.txt", "XY.txt", FALSE }, + + { "?*.txt", ".txt", FALSE }, + { "?*.txt", "a.txt", TRUE }, + { "?*.txt", "aa.txt", TRUE }, + { "?*.txt", "aaa.txt", TRUE }, + + { "foo.[tT][xX][tT]", "foo.txt", TRUE }, + { "foo.[tT][xX][tT]", "foo.TXt", TRUE }, + { "foo.[tT][xX][tT]", "foo.TXT", TRUE }, + { "foo.[tT][xX][tT]", "foo.TaT", FALSE }, + + { "foo.[tT][!yY][tT]", "foo.TXt", TRUE }, + { "foo.[tT][!yY][tT]", "foo.TXT", TRUE }, + { "foo.[tT][!yY][tT]", "foo.TyT", FALSE }, + + { "foo\\\\", "foo", FALSE }, + { "foo\\\\", "foo\\", TRUE }, + { "foo\\\\", "foo\\\\", FALSE }, + + { "(){}+.^$|", "(){}+.^$|", TRUE }, + + { "/usr/bin/*", "/usr/bin/tar", TRUE }, + { "/usr/bin/*", "/usr/bin/local/tar", FALSE }, + { "/usr/bin/*", "/usr/sbin/tar", FALSE }, + { "/usr/bin/*", "/opt/usr/bin/tar", FALSE }, + + { "/usr?bin", "/usr/bin", FALSE }, + { "/usr*bin", "/usr/bin", FALSE }, + + { NULL, NULL, FALSE }, + }, *t; + + for (t = tests; t->expr; t++) { + gboolean matched = match_glob(t->expr, t->str); + if (!!matched != !!t->should_match) { + ok = FALSE; + if (t->should_match) { + g_fprintf(stderr, "%s should have matched glob %s\n", + t->str, t->expr); + } else { + g_fprintf(stderr, "%s unexpectedly matched glob %s\n", + t->str, t->expr); + } + } + } + + return ok; +} + +static int +test_match_tar(void) +{ + gboolean ok = TRUE; + struct { + char *expr, *str; + gboolean should_match; + } tests[] = { + /* literal, unanchored matching */ + { "a", "a", TRUE }, + + { "abc", "abc", TRUE }, + { "abc", "abcd", FALSE }, + { "abc", "dabc", FALSE }, + { "abc", "/usr/bin/abc", TRUE }, + + { "*.txt", "foo.txt", TRUE }, + { "*.txt", ".txt", TRUE }, + { "*.txt", "txt", FALSE }, + + { "?.txt", "X.txt", TRUE }, + { "?.txt", ".txt", FALSE }, + { "?.txt", "XY.txt", FALSE }, + + { "?*.txt", ".txt", FALSE }, + { "?*.txt", "a.txt", TRUE }, + { "?*.txt", "aa.txt", TRUE }, + { "?*.txt", "aaa.txt", TRUE }, + + { "foo.[tT][xX][tT]", "foo.txt", TRUE }, + { "foo.[tT][xX][tT]", "foo.TXt", TRUE }, + { "foo.[tT][xX][tT]", "foo.TXT", TRUE }, + { "foo.[tT][xX][tT]", "foo.TaT", FALSE }, + + { "foo.[tT][!yY][tT]", "foo.TXt", TRUE }, + { "foo.[tT][!yY][tT]", "foo.TXT", TRUE }, + { "foo.[tT][!yY][tT]", "foo.TyT", FALSE }, + + { "foo\\\\", "foo", FALSE }, + { "foo\\\\", "foo\\", TRUE }, + { "foo\\\\", "foo\\\\", FALSE }, + + { "(){}+.^$|", "(){}+.^$|", TRUE }, + + { "/usr/bin/*", "/usr/bin/tar", TRUE }, + { "/usr/bin/*", "/usr/bin/local/tar", TRUE }, /* different from match_glob */ + { "/usr/bin/*", "/usr/sbin/tar", FALSE }, + { "/usr/bin/*", "/opt/usr/bin/tar", FALSE }, + + { "/usr?bin", "/usr/bin", FALSE }, + { "/usr*bin", "/usr/bin", TRUE }, /* different from match_glob */ + + /* examples from the amgtar manpage */ + { "./temp-files", "./temp-files", TRUE }, + { "./temp-files", "./temp-files/foo", TRUE }, + { "./temp-files", "./temp-files/foo/bar", TRUE }, + { "./temp-files", "./temp-files.bak", FALSE }, + { "./temp-files", "./backup/temp-files", FALSE }, + + { "./temp-files/", "./temp-files", FALSE }, + { "./temp-files/", "./temp-files/", TRUE }, + { "./temp-files/", "./temp-files/foo", FALSE }, + { "./temp-files/", "./temp-files/foo/bar", FALSE }, + { "./temp-files/", "./temp-files.bak", FALSE }, + + { "/temp-files/", "./temp-files", FALSE }, + { "/temp-files/", "./temp-files/", FALSE }, + { "/temp-files/", "./temp-files/foo", FALSE }, + { "/temp-files/", "./temp-files/foo/bar", FALSE }, + { "/temp-files/", "./temp-files.bak", FALSE }, + + { "./temp-files/*", "./temp-files", FALSE }, + { "./temp-files/*", "./temp-files/", TRUE }, + { "./temp-files/*", "./temp-files/foo", TRUE }, + { "./temp-files/*", "./temp-files/foo/bar", TRUE }, + + { "temp-files", "./my/temp-files", TRUE }, + { "temp-files", "./my/temp-files/bar", TRUE }, + { "temp-files", "./temp-files", TRUE }, + { "temp-files", "./her-temp-files", FALSE }, + { "temp-files", "./her/old-temp-files", FALSE }, + { "temp-files", "./her/old-temp-files/bar", FALSE }, + + { "generated-*", "./my/generated-xyz", TRUE }, + { "generated-*", "./my/generated-xyz/bar", TRUE }, + { "generated-*", "./generated-xyz", TRUE }, + { "generated-*", "./her-generated-xyz", FALSE }, + { "generated-*", "./her/old-generated-xyz", FALSE }, + { "generated-*", "./her/old-generated-xyz/bar", FALSE }, + + { "*.iso", "./my/amanda.iso", TRUE }, + { "*.iso", "./amanda.iso", TRUE }, + + { "proxy/local/cache", "./usr/proxy/local/cache", TRUE }, + { "proxy/local/cache", "./proxy/local/cache", TRUE }, + { "proxy/local/cache", "./proxy/local/cache/7a", TRUE }, + + { NULL, NULL, FALSE }, + }, *t; + + for (t = tests; t->expr; t++) { + gboolean matched = match_tar(t->expr, t->str); + if (!!matched != !!t->should_match) { + ok = FALSE; + if (t->should_match) { + g_fprintf(stderr, "%s should have matched tar %s\n", + t->str, t->expr); + } else { + g_fprintf(stderr, "%s unexpectedly matched tar %s\n", + t->str, t->expr); + } + } + } + + return ok; +} + +static int +test_make_exact_host_expression(void) { gboolean ok = TRUE; - struct { char *expr, *str; gboolean should_match; } tests[] = { - /* examples from amanda(8) */ + guint i, j; + const char *test_strs[] = { + "host", + "host.org", + "host.host.org", + /* note that these will inter-match: */ + /* + ".host", + ".host.org", + ".host.host.org", + "host.", + "host.org.", + "host.host.org.", + */ + "org", + "^host", + "host$", + "^host$", + "ho[s]t", + "ho[!s]t", + "ho\\st", + "ho/st", + "ho?t", + "h*t", + "h**t", + }; + + for (i = 0; i < G_N_ELEMENTS(test_strs); i++) { + for (j = 0; j < G_N_ELEMENTS(test_strs); j++) { + char *expr = make_exact_host_expression(test_strs[i]); + gboolean matched = match_host(expr, test_strs[j]); + if (!!matched != !!(i == j)) { + ok = FALSE; + if (matched) { + g_fprintf(stderr, "expr %s for str %s unexpectedly matched %s\n", + expr, test_strs[i], test_strs[j]); + } else { + g_fprintf(stderr, "expr %s for str %s should have matched %s\n", + expr, test_strs[i], test_strs[j]); + } + } + } + } + + return ok; +} + +static int +test_match_host(void) +{ + gboolean ok = TRUE; + struct { + char *expr, *str; + gboolean should_match; + } tests[] = { + /* from the amanda(8) manpage */ { "hosta", "hosta", TRUE }, { "hosta", "foo.hosta.org", TRUE }, - { "hosta", "hOsTA.domain.org", TRUE }, + { "hosta", "hoSTA.dOMAIna.ORG", TRUE }, { "hosta", "hostb", FALSE }, + { "hOsta", "hosta", TRUE }, + { "hOsta", "foo.hosta.org", TRUE }, + { "hOsta", "hoSTA.dOMAIna.ORG", TRUE }, + { "hOsta", "hostb", FALSE }, + { "host", "host", TRUE }, { "host", "hosta", FALSE }, + { "host?", "hosta", TRUE }, + { "host?", "hostb", TRUE }, { "host?", "host", FALSE }, + { "host?", "hostabc", FALSE }, + + { "ho*na", "hona", TRUE }, { "ho*na", "hoina", TRUE }, + { "ho*na", "hoina.org", TRUE }, + { "ho*na", "ns.hoina.org", TRUE }, { "ho*na", "ho.aina.org", FALSE }, + + { "ho**na", "hona", TRUE }, { "ho**na", "hoina", TRUE }, + { "ho**na", "hoina.org", TRUE }, + { "ho**na", "ns.hoina.org", TRUE }, { "ho**na", "ho.aina.org", TRUE }, + { "^hosta", "hosta", TRUE }, - { "^hosta", "hosta.foo.org", TRUE }, - { "^hosta", "foo.hosta.org", FALSE }, + { "^hosta", "hosta.org", TRUE }, + { "^hosta", "hostabc", FALSE }, + { "^hosta", "www.hosta", FALSE }, + { "^hosta", "www.hosta.org", FALSE }, + + { "/opt", "opt", FALSE }, { ".hosta.", "hosta", TRUE }, { ".hosta.", "foo.hosta", TRUE }, @@ -62,7 +548,12 @@ test_host_match(void) { "/hosta", "hosta.org", FALSE }, { "/hosta", "foo.hosta.org", FALSE }, - /* additional checks */ + { ".opt.", "opt", TRUE }, + { ".opt.", "www.opt", TRUE }, + { ".opt.", "www.opt.com", TRUE }, + { ".opt.", "opt.com", TRUE }, + + /* other examples */ { "^hosta$", "hosta", TRUE }, { "^hosta$", "foo.hosta", FALSE }, { "^hosta$", "hosta.org", FALSE }, @@ -82,6 +573,18 @@ test_host_match(void) { "mo[!st]a", "moma", TRUE }, { "mo[!st]a", "momma", FALSE }, + { "host[acd]", "hosta", TRUE }, + { "host[acd]", "hostb", FALSE }, + { "host[acd]", "hostc", TRUE }, + { "host[!acd]", "hosta", FALSE }, + { "host[!acd]", "hostb", TRUE }, + { "host[!acd]", "hostc", FALSE }, + + { "toast", "www.toast.com", TRUE }, + { ".toast", "www.toast.com", TRUE }, + { "toast.", "www.toast.com", TRUE }, + { ".toast.", "www.toast.com", TRUE }, + { NULL, NULL, FALSE }, }, *t; @@ -102,47 +605,120 @@ test_host_match(void) return ok; } -/**** - * Test some disk expressions - */ static int -test_disk_match(void) +test_make_exact_disk_expression(void) +{ + gboolean ok = TRUE; + guint i, j; + const char *test_strs[] = { + "/disk", + "/disk/disk", + "d[i]sk", + "d**k", + "d*k", + "d?sk", + "d.sk", + "d[!pqr]sk", + "^disk", + "disk$", + "^disk$", + /* these intermatch due to some special-casing */ + /* + "//windows/share", + "\\\\windows\\share", + */ + }; + + for (i = 0; i < G_N_ELEMENTS(test_strs); i++) { + for (j = 0; j < G_N_ELEMENTS(test_strs); j++) { + char *expr = make_exact_disk_expression(test_strs[i]); + gboolean matched = match_disk(expr, test_strs[j]); + if (!!matched != !!(i == j)) { + ok = FALSE; + if (matched) { + g_fprintf(stderr, "expr %s for str %s unexpectedly matched %s\n", + expr, test_strs[i], test_strs[j]); + } else { + g_fprintf(stderr, "expr %s for str %s should have matched %s\n", + expr, test_strs[i], test_strs[j]); + } + } + } + } + + return ok; +} + +static int +test_match_disk(void) { gboolean ok = TRUE; - struct { char *expr, *str; gboolean should_match; } tests[] = { - /* examples from amanda(8) */ + struct { + char *expr, *str; + gboolean should_match; + } tests[] = { + /* from the amanda(8) manpage */ { "sda*", "/dev/sda1", TRUE }, - { "sda*", "/dev/sda12", TRUE }, + { "sda*", "/dev/sda2", TRUE }, + { "sda*", "/dev/sdb2", FALSE }, + { "opt", "opt", TRUE }, { "opt", "/opt", TRUE }, { "opt", "/opt/foo", TRUE }, { "opt", "opt/foo", TRUE }, + + { "/opt", "opt", TRUE }, + { "/opt", "opt/", TRUE }, + { "/opt", "/opt", TRUE }, + { "/opt", "/opt/", TRUE }, + { "/opt", "/local/opt/", TRUE }, + { "/opt", "/opt/local/", TRUE }, + + { "opt/", "opt", TRUE }, + { "opt/", "opt/", TRUE }, + { "opt/", "/opt", TRUE }, + { "opt/", "/opt/", TRUE }, + { "opt/", "/local/opt/", TRUE }, + { "opt/", "/opt/local/", TRUE }, + { "/", "/", TRUE }, - { "/", "/opt", FALSE }, - { "/", "/opt/var", FALSE }, - { "/usr", "/", FALSE }, - { "/usr", "/usr", TRUE }, - { "/usr", "/usr/local", TRUE }, + { "/", "/opt/local/", FALSE }, + { "/usr$", "/", FALSE }, { "/usr$", "/usr", TRUE }, { "/usr$", "/usr/local", FALSE }, - { "share", "//windows1/share", TRUE }, - { "share", "//windows2/share", TRUE }, + { "share", "\\\\windows1\\share", TRUE }, { "share", "\\\\windows2\\share", TRUE }, - { "share*", "//windows/share1", TRUE }, - { "share*", "//windows/share2", TRUE }, + { "share", "//windows1/share", TRUE }, + { "share", "//windows2/share", TRUE }, + { "share*", "\\\\windows\\share1", TRUE }, { "share*", "\\\\windows\\share2", TRUE }, + { "share*", "//windows/share3", TRUE }, + { "share*", "//windows/share4", TRUE }, + { "//windows/share", "//windows/share", TRUE }, { "//windows/share", "\\\\windows\\share", TRUE }, - - /* and now things get murky */ { "\\\\windows\\share", "//windows/share", FALSE }, { "\\\\windows\\share", "\\\\windows\\share", FALSE }, { "\\\\\\\\windows\\\\share", "//windows/share", FALSE }, { "\\\\\\\\windows\\\\share", "\\\\windows\\share", TRUE }, + /* other expressions */ + { "^local", "/local", TRUE }, + { "^local", "/local/vore", TRUE }, + { "^local", "/usr/local", FALSE }, + + { "local/bin", "/local/bin", TRUE }, + { "local/bin", "/opt/local/bin", TRUE }, + { "local/bin", "/local/bin/git", TRUE }, + + { "//windows/share", "//windows/share/files", TRUE }, + { "//windows/share", "\\\\windows\\share\\files", TRUE }, + { "\\\\windows\\share", "//windows/share/files", FALSE }, + { "\\\\windows\\share", "\\\\windows\\share\\files", FALSE }, + /* longer expressions */ { "local/var", "/local/var", TRUE }, { "local/var", "/opt/local/var", TRUE }, @@ -186,53 +762,83 @@ test_disk_match(void) return ok; } -/**** - * Test make_exact_host_expression - */ static int -test_make_exact_host_expression(void) +test_match_datestamp(void) { gboolean ok = TRUE; - guint i, j; - const char *test_strs[] = { - "host", - "host.org", - "host.host.org", - /* note that these will inter-match: */ - /* - ".host", - ".host.org", - ".host.host.org", - "host.", - "host.org.", - "host.host.org.", - */ - "org", - "^host", - "host$", - "^host$", - "ho[s]t", - "ho[!s]t", - "ho\\st", - "ho/st", - "ho?t", - "h*t", - "h**t", - }; + struct { + char *expr, *str; + gboolean should_match; + } tests[] = { + /* from the amanda(8) manpage */ + { "20001212-14", "20001212", TRUE }, + { "20001212-14", "20001212010203", TRUE }, + { "20001212-14", "20001213", TRUE }, + { "20001212-14", "20001213010203", TRUE }, + { "20001212-14", "20001214", TRUE }, + { "20001212-14", "20001215", FALSE }, - for (i = 0; i < G_N_ELEMENTS(test_strs); i++) { - for (j = 0; j < G_N_ELEMENTS(test_strs); j++) { - char *expr = make_exact_host_expression(test_strs[i]); - gboolean matched = match_host(expr, test_strs[j]); - if (!!matched != !!(i == j)) { - ok = FALSE; - if (matched) { - g_fprintf(stderr, "expr %s for str %s unexpectedly matched %s\n", - expr, test_strs[i], test_strs[j]); - } else { - g_fprintf(stderr, "expr %s for str %s should have matched %s\n", - expr, test_strs[i], test_strs[j]); - } + { "20001212-4", "20001212", TRUE }, + { "20001212-4", "20001212010203", TRUE }, + { "20001212-4", "20001213", TRUE }, + { "20001212-4", "20001213010203", TRUE }, + { "20001212-4", "20001214", TRUE }, + { "20001212-4", "20001215", FALSE }, + + { "20001212-214", "20001212", TRUE }, + { "20001212-214", "20001212010203", TRUE }, + { "20001212-214", "20001213", TRUE }, + { "20001212-214", "20001213010203", TRUE }, + { "20001212-214", "20001214", TRUE }, + { "20001212-214", "20001215", FALSE }, + + { "20001212-24", "20001211", FALSE }, + { "20001212-24", "20001214010203", TRUE }, + { "20001212-24", "20001221010203", TRUE }, + { "20001212-24", "20001224", TRUE }, + { "20001212-24", "20001225", FALSE }, + + { "2000121", "20001209", FALSE }, + { "2000121", "20001210", TRUE }, + { "2000121", "20001210012345", TRUE }, + { "2000121", "20001219", TRUE }, + { "2000121", "20001219012345", TRUE }, + { "2000121", "20001220", FALSE }, + + { "2", "19991231", FALSE }, + { "2", "20000101", TRUE }, + { "2", "20100419", TRUE }, + + { "^2", "19991231", FALSE }, + { "^2", "20000101", TRUE }, + { "^2", "20100419", TRUE }, + + { "2000-2010", "19991231235959", FALSE }, + { "2000-2010", "20001010", TRUE }, + { "2000-2010", "20101231", TRUE }, + { "2000-2010", "20111010", FALSE }, + + { "200010$", "200010", TRUE }, /* but it's not a real datestamp */ + { "200010$", "20001001", FALSE }, + { "200010$", "20001001061500", FALSE }, + + { "20000615$", "20000615", TRUE }, + { "20000615$", "20000615000000", FALSE }, + { "20000615$", "20000615010306", FALSE }, + + { NULL, NULL, FALSE }, + }, *t; + + for (t = tests; t->expr; t++) { + gboolean matched = match_datestamp(t->expr, t->str); + if (!!matched != !!t->should_match) { + ok = FALSE; + if (t->should_match) { + g_fprintf(stderr, "%s should have matched datestamp expr %s\n", + t->str, t->expr); + } else { + g_fprintf(stderr, "%s unexpectedly matched datestamp expr %s\n", + t->str, t->expr); } } } @@ -240,46 +846,80 @@ test_make_exact_host_expression(void) return ok; } -/**** - * Test make_exact_disk_expression - */ static int -test_make_exact_disk_expression(void) +test_match_level(void) { gboolean ok = TRUE; - guint i, j; - const char *test_strs[] = { - "/disk", - "/disk/disk", - "d[i]sk", - "d**k", - "d*k", - "d?sk", - "d.sk", - "d[!pqr]sk", - "^disk", - "disk$", - "^disk$", - /* these intermatch due to some special-casing */ - /* - "//windows/share", - "\\\\windows\\share", - */ - }; + struct { + char *expr, *str; + gboolean should_match; + } tests[] = { + /* exact matches, optionally ignoring "^" */ + { "3$", "2", FALSE }, + { "3$", "3", TRUE }, + { "3$", "4", FALSE }, + { "3$", "32", FALSE }, - for (i = 0; i < G_N_ELEMENTS(test_strs); i++) { - for (j = 0; j < G_N_ELEMENTS(test_strs); j++) { - char *expr = make_exact_disk_expression(test_strs[i]); - gboolean matched = match_disk(expr, test_strs[j]); - if (!!matched != !!(i == j)) { - ok = FALSE; - if (matched) { - g_fprintf(stderr, "expr %s for str %s unexpectedly matched %s\n", - expr, test_strs[i], test_strs[j]); - } else { - g_fprintf(stderr, "expr %s for str %s should have matched %s\n", - expr, test_strs[i], test_strs[j]); - } + { "^3$", "2", FALSE }, + { "^3$", "3", TRUE }, + { "^3$", "4", FALSE }, + { "^3$", "32", FALSE }, + + /* prefix matches */ + { "3", "2", FALSE }, + { "3", "3", TRUE }, + { "3", "4", FALSE }, + { "3", "32", TRUE }, + + /* ranges */ + { "2-5", "1", FALSE }, + { "2-5", "13", FALSE }, + { "2-5", "23", FALSE }, + { "2-5", "2", TRUE }, + { "2-5", "4", TRUE }, + { "2-5", "5", TRUE }, + { "2-5", "53", FALSE }, + { "2-5", "63", FALSE }, + { "2-5", "6", FALSE }, + + { "9-15", "8", FALSE }, + { "9-15", "19", FALSE }, + { "9-15", "91", FALSE }, + { "9-15", "9", TRUE }, + { "9-15", "14", TRUE }, + { "9-15", "15", TRUE }, + { "9-15", "152", FALSE }, + { "9-15", "16", FALSE }, + + { "19-21", "18", FALSE }, + { "19-21", "19", TRUE }, + { "19-21", "21", TRUE }, + { "19-21", "22", FALSE }, + + /* single range is the same as an exact match */ + { "99-99", "98", FALSE }, + { "99-99", "99", TRUE }, + { "99-99", "100", FALSE }, + + /* reversed range never matches */ + { "21-19", "18", FALSE }, + { "21-19", "19", FALSE }, + { "21-19", "21", FALSE }, + { "21-19", "22", FALSE }, + + { NULL, NULL, FALSE }, + }, *t; + + for (t = tests; t->expr; t++) { + gboolean matched = match_level(t->expr, t->str); + if (!!matched != !!t->should_match) { + ok = FALSE; + if (t->should_match) { + g_fprintf(stderr, "%s should have matched level expr %s\n", + t->str, t->expr); + } else { + g_fprintf(stderr, "%s unexpectedly matched level expr %s\n", + t->str, t->expr); } } } @@ -287,6 +927,7 @@ test_make_exact_disk_expression(void) return ok; } + /* * Main driver */ @@ -295,10 +936,18 @@ int main(int argc, char **argv) { static TestUtilsTest tests[] = { - TU_TEST(test_host_match, 90), - TU_TEST(test_disk_match, 90), + TU_TEST(test_validate_regexp, 90), + TU_TEST(test_match, 90), + TU_TEST(test_validate_glob, 90), + TU_TEST(test_glob_to_regex, 90), + TU_TEST(test_match_glob, 90), + TU_TEST(test_match_tar, 90), TU_TEST(test_make_exact_host_expression, 90), + TU_TEST(test_match_host, 90), TU_TEST(test_make_exact_disk_expression, 90), + TU_TEST(test_match_disk, 90), + TU_TEST(test_match_datestamp, 90), + TU_TEST(test_match_level, 90), TU_END() };