1 #include <gtk/gtk.h>
2 #include "gtk/gtkprivate.h"
3 
4 #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
5 #define DO_ESCAPE 0
6 #else
7 #define DO_ESCAPE 1
8 #endif
9 
10 typedef struct {
11   const char *pat;
12   const char *str;
13   gboolean no_leading_period;
14   gboolean ci;
15   gboolean result;
16 } TestCase;
17 
18 static TestCase tests[] = {
19   { "[a-]", "-", TRUE, FALSE, TRUE },
20 
21   { "a", "a", TRUE, FALSE, TRUE },
22   { "a", "b", TRUE, FALSE, FALSE },
23 
24   /* Test what ? matches */
25   { "?", "a", TRUE, FALSE, TRUE },
26   { "?", ".", TRUE, FALSE, FALSE },
27   { "a?", "a.", TRUE, FALSE, TRUE },
28   { "a/?", "a/b", TRUE, FALSE, TRUE },
29   { "a/?", "a/.", TRUE, FALSE, FALSE },
30   { "?", "/", TRUE, FALSE, FALSE },
31 
32   /* Test what * matches */
33   { "*", "a", TRUE, FALSE, TRUE },
34   { "*", ".", TRUE, FALSE, FALSE },
35   { "a*", "a.", TRUE, FALSE, TRUE },
36   { "a/*", "a/b", TRUE, FALSE, TRUE },
37   { "a/*", "a/.", TRUE, FALSE, FALSE },
38   { "*", "/", TRUE, FALSE, FALSE },
39 
40   /* Range tests */
41   { "[ab]", "a", TRUE, FALSE, TRUE },
42   { "[ab]", "c", TRUE, FALSE, FALSE },
43   { "[^ab]", "a", TRUE, FALSE, FALSE },
44   { "[!ab]", "a", TRUE, FALSE, FALSE },
45   { "[^ab]", "c", TRUE, FALSE, TRUE },
46   { "[!ab]", "c", TRUE, FALSE, TRUE },
47   { "[a-c]", "b", TRUE, FALSE, TRUE },
48   { "[a-c]", "d", TRUE, FALSE, FALSE },
49   { "[a-]", "-", TRUE, FALSE, TRUE },
50   { "[]]", "]", TRUE, FALSE, TRUE },
51   { "[^]]", "a", TRUE, FALSE, TRUE },
52   { "[!]]", "a", TRUE, FALSE, TRUE },
53 
54   /* Various unclosed ranges */
55   { "[ab", "a", TRUE, FALSE, FALSE },
56   { "[a-", "a", TRUE, FALSE, FALSE },
57   { "[ab", "c", TRUE, FALSE, FALSE },
58   { "[a-", "c", TRUE, FALSE, FALSE },
59   { "[^]", "a", TRUE, FALSE, FALSE },
60 
61   /* Ranges and special no-wildcard matches */
62   { "[.]", ".", TRUE, FALSE, FALSE },
63   { "a[.]", "a.", TRUE, FALSE, TRUE },
64   { "a/[.]", "a/.", TRUE, FALSE, FALSE },
65   { "[/]", "/", TRUE, FALSE, FALSE },
66   { "[^/]", "a", TRUE, FALSE, TRUE },
67 
68   /* Basic tests of * (and combinations of * and ?) */
69   { "a*b", "ab", TRUE, FALSE, TRUE },
70   { "a*b", "axb", TRUE, FALSE, TRUE },
71   { "a*b", "axxb", TRUE, FALSE, TRUE },
72   { "a**b", "ab", TRUE, FALSE, TRUE },
73   { "a**b", "axb", TRUE, FALSE, TRUE },
74   { "a**b", "axxb", TRUE, FALSE, TRUE },
75   { "a*?*b", "ab", TRUE, FALSE, FALSE },
76   { "a*?*b", "axb", TRUE, FALSE, TRUE },
77   { "a*?*b", "axxb", TRUE, FALSE, TRUE },
78 
79   /* Test of  *[range] */
80   { "a*[cd]", "ac", TRUE, FALSE, TRUE },
81   { "a*[cd]", "axc", TRUE, FALSE, TRUE },
82   { "a*[cd]", "axx", TRUE, FALSE, FALSE },
83 
84   { "a/[.]", "a/.", TRUE, FALSE, FALSE },
85   { "a*[.]", "a/.", TRUE, FALSE, FALSE },
86 
87 
88   /* Test of UTF-8 */
89 
90   { "ä", "ä", TRUE, FALSE, TRUE },
91   { "?", "ä", TRUE, FALSE, TRUE },
92   { "*ö", "äö", TRUE, FALSE, TRUE },
93   { "*ö", "ääö", TRUE, FALSE, TRUE },
94   { "[ä]", "ä", TRUE, FALSE, TRUE },
95   { "[ä-ö]", "é", TRUE, FALSE, TRUE },
96   { "[ä-ö]", "a", TRUE, FALSE, FALSE },
97 
98   /* ci patterns */
99   { "*.txt", "a.TXT", TRUE, TRUE, TRUE },
100   { "*.txt", "a.TxT", TRUE, TRUE, TRUE },
101   { "*.txt", "a.txT", TRUE, TRUE, TRUE },
102   { "*ö", "äÖ", TRUE, TRUE, TRUE },
103 
104 #ifdef DO_ESCAPE
105   /* Tests of escaping */
106   { "\\\\", "\\", TRUE, FALSE, TRUE },
107   { "\\?", "?", TRUE, FALSE, TRUE },
108   { "\\?", "a", TRUE, FALSE, FALSE },
109   { "\\*", "*", TRUE, FALSE, TRUE },
110   { "\\*", "a", TRUE, FALSE, FALSE },
111   { "\\[a-b]", "[a-b]", TRUE, FALSE, TRUE },
112   { "[\\\\]", "\\", TRUE, FALSE, TRUE },
113   { "[\\^a]", "a", TRUE, FALSE, TRUE },
114   { "[a\\-c]", "b", TRUE, FALSE, FALSE },
115   { "[a\\-c]", "-", TRUE, FALSE, TRUE },
116   { "[a\\]", "a", TRUE, FALSE, FALSE },
117 #endif /* DO_ESCAPE */
118 };
119 
120 static void
test_fnmatch(gconstpointer data)121 test_fnmatch (gconstpointer data)
122 {
123   const TestCase *test = data;
124 
125   g_assert_true (_gtk_fnmatch (test->pat, test->str, test->no_leading_period, test->ci) == test->result);
126 }
127 
128 typedef struct {
129   const char *glob;
130   const char *ci;
131 } CITest;
132 
133 static CITest citests[] = {
134   { "*.txt", "*.[tT][xX][tT]" },
135   { "*.TXT", "*.[tT][xX][tT]" },
136   { "*?[]-abc]t", "*?[]-abc][tT]" },
137 #ifdef DO_ESCAPE
138   /* Tests of escaping */
139   { "\\\\", "\\\\" },
140   { "\\??", "\\??" },
141   { "\\**", "\\**" },
142   { "\\[", "\\[" },
143   { "\\[a-", "\\[[aA]-" },
144   { "\\[]", "\\[]" },
145 #endif
146 };
147 
148 static void
test_ci_glob(gconstpointer data)149 test_ci_glob (gconstpointer data)
150 {
151   const CITest *test = data;
152   char *ci;
153 
154   ci = _gtk_make_ci_glob_pattern (test->glob);
155   g_assert_cmpstr (ci, ==, test->ci);
156   g_free (ci);
157 }
158 
159 int
main(int argc,char * argv[])160 main (int argc, char *argv[])
161 {
162   (g_test_init) (&argc, &argv, NULL);
163 
164   for (int i = 0; i < G_N_ELEMENTS (tests); i++)
165     {
166       char *path = g_strdup_printf ("/fnmatch/test%d", i);
167       g_test_add_data_func (path, &tests[i], test_fnmatch);
168       g_free (path);
169     }
170 
171   for (int i = 0; i < G_N_ELEMENTS (citests); i++)
172     {
173       char *path = g_strdup_printf ("/ci-glob/test%d", i);
174       g_test_add_data_func (path, &citests[i], test_ci_glob);
175       g_free (path);
176     }
177 
178   return g_test_run ();
179 }
180