gtk2/testsuite/gtk/fnmatch.c
Matthias Clasen 47400e4bd8 Add a helper to make case-insensitive globs
This will be used in GtkFileFilter in the future.

Tests included.
2021-06-04 21:10:01 -04:00

178 lines
4.7 KiB
C

#include <gtk/gtk.h>
#include "gtk/gtkprivate.h"
#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
#define DO_ESCAPE 0
#else
#define DO_ESCAPE 1
#endif
typedef struct {
const char *pat;
const char *str;
gboolean no_leading_period;
gboolean ci;
gboolean result;
} TestCase;
static TestCase tests[] = {
{ "[a-]", "-", TRUE, FALSE, TRUE },
{ "a", "a", TRUE, FALSE, TRUE },
{ "a", "b", TRUE, FALSE, FALSE },
/* Test what ? matches */
{ "?", "a", TRUE, FALSE, TRUE },
{ "?", ".", TRUE, FALSE, FALSE },
{ "a?", "a.", TRUE, FALSE, TRUE },
{ "a/?", "a/b", TRUE, FALSE, TRUE },
{ "a/?", "a/.", TRUE, FALSE, FALSE },
{ "?", "/", TRUE, FALSE, FALSE },
/* Test what * matches */
{ "*", "a", TRUE, FALSE, TRUE },
{ "*", ".", TRUE, FALSE, FALSE },
{ "a*", "a.", TRUE, FALSE, TRUE },
{ "a/*", "a/b", TRUE, FALSE, TRUE },
{ "a/*", "a/.", TRUE, FALSE, FALSE },
{ "*", "/", TRUE, FALSE, FALSE },
/* Range tests */
{ "[ab]", "a", TRUE, FALSE, TRUE },
{ "[ab]", "c", TRUE, FALSE, FALSE },
{ "[^ab]", "a", TRUE, FALSE, FALSE },
{ "[!ab]", "a", TRUE, FALSE, FALSE },
{ "[^ab]", "c", TRUE, FALSE, TRUE },
{ "[!ab]", "c", TRUE, FALSE, TRUE },
{ "[a-c]", "b", TRUE, FALSE, TRUE },
{ "[a-c]", "d", TRUE, FALSE, FALSE },
{ "[a-]", "-", TRUE, FALSE, TRUE },
{ "[]]", "]", TRUE, FALSE, TRUE },
{ "[^]]", "a", TRUE, FALSE, TRUE },
{ "[!]]", "a", TRUE, FALSE, TRUE },
/* Various unclosed ranges */
{ "[ab", "a", TRUE, FALSE, FALSE },
{ "[a-", "a", TRUE, FALSE, FALSE },
{ "[ab", "c", TRUE, FALSE, FALSE },
{ "[a-", "c", TRUE, FALSE, FALSE },
{ "[^]", "a", TRUE, FALSE, FALSE },
/* Ranges and special no-wildcard matches */
{ "[.]", ".", TRUE, FALSE, FALSE },
{ "a[.]", "a.", TRUE, FALSE, TRUE },
{ "a/[.]", "a/.", TRUE, FALSE, FALSE },
{ "[/]", "/", TRUE, FALSE, FALSE },
{ "[^/]", "a", TRUE, FALSE, TRUE },
/* Basic tests of * (and combinations of * and ?) */
{ "a*b", "ab", TRUE, FALSE, TRUE },
{ "a*b", "axb", TRUE, FALSE, TRUE },
{ "a*b", "axxb", TRUE, FALSE, TRUE },
{ "a**b", "ab", TRUE, FALSE, TRUE },
{ "a**b", "axb", TRUE, FALSE, TRUE },
{ "a**b", "axxb", TRUE, FALSE, TRUE },
{ "a*?*b", "ab", TRUE, FALSE, FALSE },
{ "a*?*b", "axb", TRUE, FALSE, TRUE },
{ "a*?*b", "axxb", TRUE, FALSE, TRUE },
/* Test of *[range] */
{ "a*[cd]", "ac", TRUE, FALSE, TRUE },
{ "a*[cd]", "axc", TRUE, FALSE, TRUE },
{ "a*[cd]", "axx", TRUE, FALSE, FALSE },
{ "a/[.]", "a/.", TRUE, FALSE, FALSE },
{ "a*[.]", "a/.", TRUE, FALSE, FALSE },
/* Test of UTF-8 */
{ "ä", "ä", TRUE, FALSE, TRUE },
{ "?", "ä", TRUE, FALSE, TRUE },
{ "", "äö", TRUE, FALSE, TRUE },
{ "", "ääö", TRUE, FALSE, TRUE },
{ "[ä]", "ä", TRUE, FALSE, TRUE },
{ "[ä-ö]", "é", TRUE, FALSE, TRUE },
{ "[ä-ö]", "a", TRUE, FALSE, FALSE },
/* ci patterns */
{ "*.txt", "a.TXT", TRUE, TRUE, TRUE },
{ "*.txt", "a.TxT", TRUE, TRUE, TRUE },
{ "*.txt", "a.txT", TRUE, TRUE, TRUE },
{ "", "äÖ", TRUE, TRUE, TRUE },
#ifdef DO_ESCAPE
/* Tests of escaping */
{ "\\\\", "\\", TRUE, FALSE, TRUE },
{ "\\?", "?", TRUE, FALSE, TRUE },
{ "\\?", "a", TRUE, FALSE, FALSE },
{ "\\*", "*", TRUE, FALSE, TRUE },
{ "\\*", "a", TRUE, FALSE, FALSE },
{ "\\[a-b]", "[a-b]", TRUE, FALSE, TRUE },
{ "[\\\\]", "\\", TRUE, FALSE, TRUE },
{ "[\\^a]", "a", TRUE, FALSE, TRUE },
{ "[a\\-c]", "b", TRUE, FALSE, FALSE },
{ "[a\\-c]", "-", TRUE, FALSE, TRUE },
{ "[a\\]", "a", TRUE, FALSE, FALSE },
#endif /* DO_ESCAPE */
};
static void
test_fnmatch (gconstpointer data)
{
const TestCase *test = data;
g_assert_true (_gtk_fnmatch (test->pat, test->str, test->no_leading_period, test->ci) == test->result);
}
typedef struct {
const char *glob;
const char *ci;
} CITest;
static CITest citests[] = {
{ "*.txt", "*.[tT][xX][tT]" },
{ "*.TXT", "*.[tT][xX][tT]" },
{ "*?[]-abc]t", "*?[]-abc][tT]" },
#ifdef DO_ESCAPE
/* Tests of escaping */
{ "\\\\", "\\\\" },
{ "\\??", "\\??" },
{ "\\**", "\\**" },
{ "\\[", "\\[" },
{ "\\[a-", "\\[[aA]-" },
{ "\\[]", "\\[]" },
#endif
};
static void
test_ci_glob (gconstpointer data)
{
const CITest *test = data;
char *ci;
ci = _gtk_make_ci_glob_pattern (test->glob);
g_assert_cmpstr (ci, ==, test->ci);
g_free (ci);
}
int
main (int argc, char *argv[])
{
(g_test_init) (&argc, &argv, NULL);
for (int i = 0; i < G_N_ELEMENTS (tests); i++)
{
char *path = g_strdup_printf ("/fnmatch/test%d", i);
g_test_add_data_func (path, &tests[i], test_fnmatch);
}
for (int i = 0; i < G_N_ELEMENTS (citests); i++)
{
char *path = g_strdup_printf ("/ci-glob/test%d", i);
g_test_add_data_func (path, &citests[i], test_ci_glob);
}
return g_test_run ();
}