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 |
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 |
149 | test_ci_glob (gconstpointer data) |
150 | { |
151 | const CITest *test = data; |
152 | char *ci; |
153 | |
154 | ci = _gtk_make_ci_glob_pattern (pattern: test->glob); |
155 | g_assert_cmpstr (ci, ==, test->ci); |
156 | g_free (mem: ci); |
157 | } |
158 | |
159 | int |
160 | main (int argc, char *argv[]) |
161 | { |
162 | (g_test_init) (argc: &argc, argv: &argv, NULL); |
163 | |
164 | for (int i = 0; i < G_N_ELEMENTS (tests); i++) |
165 | { |
166 | char *path = g_strdup_printf (format: "/fnmatch/test%d" , i); |
167 | g_test_add_data_func (testpath: path, test_data: &tests[i], test_func: test_fnmatch); |
168 | g_free (mem: path); |
169 | } |
170 | |
171 | for (int i = 0; i < G_N_ELEMENTS (citests); i++) |
172 | { |
173 | char *path = g_strdup_printf (format: "/ci-glob/test%d" , i); |
174 | g_test_add_data_func (testpath: path, test_data: &citests[i], test_func: test_ci_glob); |
175 | g_free (mem: path); |
176 | } |
177 | |
178 | return g_test_run (); |
179 | } |
180 | |