1 package fnmatch_test
2
3 import (
4 "testing"
5
6 "github.com/danwakefield/fnmatch"
7 )
8
9
10
11 func TestMatch(t *testing.T) {
12 assert := func(p, s string) {
13 if !fnmatch.Match(p, s, 0) {
14 t.Errorf("Assertion failed: Match(%#v, %#v, 0)", p, s)
15 }
16 }
17 assert("", "")
18 assert("*", "")
19 assert("*", "foo")
20 assert("*", "bar")
21 assert("*", "*")
22 assert("**", "f")
23 assert("**", "foo.txt")
24 assert("*.*", "foo.txt")
25 assert("foo*.txt", "foobar.txt")
26 assert("foo.txt", "foo.txt")
27 assert("foo\\.txt", "foo.txt")
28 if fnmatch.Match("foo\\.txt", "foo.txt", fnmatch.FNM_NOESCAPE) {
29 t.Errorf("Assertion failed: Match(%#v, %#v, FNM_NOESCAPE) == false", "foo\\.txt", "foo.txt")
30 }
31 }
32
33 func TestWildcard(t *testing.T) {
34
35 cases := []struct {
36 pattern string
37 input string
38 flags int
39 want bool
40 }{
41 {"*", "", 0, true},
42 {"*", "foo", 0, true},
43 {"*", "*", 0, true},
44 {"*", " ", 0, true},
45 {"*", ".foo", 0, true},
46 {"*", "わたし", 0, true},
47 }
48
49 for tc, c := range cases {
50 got := fnmatch.Match(c.pattern, c.input, c.flags)
51 if got != c.want {
52 t.Errorf(
53 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
54 tc, c.pattern, c.input, c.flags, c.want, got,
55 )
56 }
57 }
58 }
59
60 func TestWildcardSlash(t *testing.T) {
61 cases := []struct {
62 pattern string
63 input string
64 flags int
65 want bool
66 }{
67
68 {"*", "foo/bar", 0, true},
69 {"*", "/", 0, true},
70 {"*", "/foo", 0, true},
71 {"*", "foo/", 0, true},
72
73 {"*", "foo/bar", fnmatch.FNM_PATHNAME, false},
74 {"*", "/", fnmatch.FNM_PATHNAME, false},
75 {"*", "/foo", fnmatch.FNM_PATHNAME, false},
76 {"*", "foo/", fnmatch.FNM_PATHNAME, false},
77 }
78
79 for tc, c := range cases {
80 got := fnmatch.Match(c.pattern, c.input, c.flags)
81 if got != c.want {
82 t.Errorf(
83 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
84 tc, c.pattern, c.input, c.flags, c.want, got,
85 )
86 }
87 }
88 for _, c := range cases {
89 got := fnmatch.Match(c.pattern, c.input, c.flags)
90 if got != c.want {
91 t.Errorf(
92 "fnmatch.Match('%s', '%s', %d) should be %v not %v",
93 c.pattern, c.input, c.flags, c.want, got,
94 )
95 }
96 }
97 }
98
99 func TestWildcardFNMPeriod(t *testing.T) {
100
101 cases := []struct {
102 pattern string
103 input string
104 flags int
105 want bool
106 }{
107 {"*", ".foo", fnmatch.FNM_PERIOD, false},
108 {"/*", "/.foo", fnmatch.FNM_PERIOD, true},
109 {"/*", "/.foo", fnmatch.FNM_PERIOD | fnmatch.FNM_PATHNAME, false},
110 }
111
112 for tc, c := range cases {
113 got := fnmatch.Match(c.pattern, c.input, c.flags)
114 if got != c.want {
115 t.Errorf(
116 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
117 tc, c.pattern, c.input, c.flags, c.want, got,
118 )
119 }
120 }
121 }
122
123 func TestQuestionMark(t *testing.T) {
124
125 cases := []struct {
126 pattern string
127 input string
128 flags int
129 want bool
130 }{
131 {"?", "", 0, false},
132 {"?", "f", 0, true},
133 {"?", ".", 0, true},
134 {"?", "?", 0, true},
135 {"?", "foo", 0, false},
136 {"?", "わ", 0, true},
137 {"?", "わた", 0, false},
138
139 {"?", "/", 0, true},
140
141 {"?", "/", fnmatch.FNM_PATHNAME, false},
142 }
143
144 for tc, c := range cases {
145 got := fnmatch.Match(c.pattern, c.input, c.flags)
146 if got != c.want {
147 t.Errorf(
148 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
149 tc, c.pattern, c.input, c.flags, c.want, got,
150 )
151 }
152 }
153 }
154
155 func TestQuestionMarkExceptions(t *testing.T) {
156
157 cases := []struct {
158 pattern string
159 input string
160 flags int
161 want bool
162 }{
163 {"?", ".", fnmatch.FNM_PERIOD, false},
164 {"foo?", "foo.", fnmatch.FNM_PERIOD, true},
165 {"/?", "/.", fnmatch.FNM_PERIOD, true},
166 {"/?", "/.", fnmatch.FNM_PERIOD | fnmatch.FNM_PATHNAME, false},
167 }
168
169 for tc, c := range cases {
170 got := fnmatch.Match(c.pattern, c.input, c.flags)
171 if got != c.want {
172 t.Errorf(
173 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
174 tc, c.pattern, c.input, c.flags, c.want, got,
175 )
176 }
177 }
178 }
179
180 func TestRange(t *testing.T) {
181 azPat := "[a-z]"
182 cases := []struct {
183 pattern string
184 input string
185 flags int
186 want bool
187 }{
188
189 {azPat, "a", 0, true},
190 {azPat, "q", 0, true},
191 {azPat, "z", 0, true},
192 {"[わ]", "わ", 0, true},
193
194
195 {azPat, "-", 0, false},
196 {azPat, " ", 0, false},
197 {azPat, "D", 0, false},
198 {azPat, "é", 0, false},
199
200
201 {azPat, "ab", 0, false},
202 {azPat, "", 0, false},
203
204
205 {azPat + "foo", "afoo", 0, true},
206
207
208
209 {"[-az]", "-", 0, true},
210 {"[-az]", "a", 0, true},
211 {"[-az]", "b", 0, false},
212 {"[az-]", "-", 0, true},
213 {"[a\\-z]", "-", 0, true},
214 {"[a\\-z]", "b", 0, false},
215
216
217 {"[a\\-z]", "\\", fnmatch.FNM_NOESCAPE, true},
218 {"[a\\-z]", "-", fnmatch.FNM_NOESCAPE, false},
219
220
221 {"[^a-z]", "a", 0, false},
222 {"[!a-z]", "b", 0, false},
223 {"[!a-z]", "é", 0, true},
224 {"[!a-z]", "わ", 0, true},
225
226
227 {"[^-az]", "-", 0, false},
228 {"[^-az]", "b", 0, true},
229
230
231 {"[abc]", "a", 0, true},
232 {"[abc]", "c", 0, true},
233 {"[abc]", "d", 0, false},
234 {"[a-cg-z]", "c", 0, true},
235 {"[a-cg-z]", "h", 0, true},
236 {"[a-cg-z]", "d", 0, false},
237
238
239 {"[abc/def]", "/", 0, true},
240 {"[abc/def]", "/", fnmatch.FNM_PATHNAME, false},
241 {"[.-0]", "/", 0, true},
242 {"[.-0]", "/", fnmatch.FNM_PATHNAME, false},
243
244
245 {"[a-z]", "A", 0, false},
246 {"[A-Z]", "a", 0, false},
247
248 {"[a-z]", "A", fnmatch.FNM_CASEFOLD, true},
249 {"[A-Z]", "a", fnmatch.FNM_CASEFOLD, true},
250 }
251
252 for tc, c := range cases {
253 got := fnmatch.Match(c.pattern, c.input, c.flags)
254 if got != c.want {
255 t.Errorf(
256 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
257 tc, c.pattern, c.input, c.flags, c.want, got,
258 )
259 }
260 }
261 }
262
263 func TestBackSlash(t *testing.T) {
264 cases := []struct {
265 pattern string
266 input string
267 flags int
268 want bool
269 }{
270
271 {"\\\\", "\\", 0, true},
272 {"\\*", "*", 0, true},
273 {"\\*", "foo", 0, false},
274 {"\\?", "?", 0, true},
275 {"\\?", "f", 0, false},
276 {"\\[a-z]", "[a-z]", 0, true},
277 {"\\[a-z]", "a", 0, false},
278 {"\\foo", "foo", 0, true},
279 {"\\わ", "わ", 0, true},
280
281
282 {"\\\\", "\\", fnmatch.FNM_NOESCAPE, false},
283 {"\\\\", "\\\\", fnmatch.FNM_NOESCAPE, true},
284 {"\\*", "foo", fnmatch.FNM_NOESCAPE, false},
285 {"\\*", "\\*", fnmatch.FNM_NOESCAPE, true},
286 }
287
288 for tc, c := range cases {
289 got := fnmatch.Match(c.pattern, c.input, c.flags)
290 if got != c.want {
291 t.Errorf(
292 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
293 tc, c.pattern, c.input, c.flags, c.want, got,
294 )
295 }
296 }
297 }
298
299 func TestLiteral(t *testing.T) {
300 cases := []struct {
301 pattern string
302 input string
303 flags int
304 want bool
305 }{
306
307 {"foo", "foo", 0, true},
308 {"foo", "foobar", 0, false},
309 {"foobar", "foo", 0, false},
310 {"foo", "Foo", 0, false},
311 {"わたし", "わたし", 0, true},
312
313 {"foo", "FOO", fnmatch.FNM_CASEFOLD, true},
314 {"FoO", "fOo", fnmatch.FNM_CASEFOLD, true},
315 }
316
317 for tc, c := range cases {
318 got := fnmatch.Match(c.pattern, c.input, c.flags)
319 if got != c.want {
320 t.Errorf(
321 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
322 tc, c.pattern, c.input, c.flags, c.want, got,
323 )
324 }
325 }
326 }
327
328 func TestFNMLeadingDir(t *testing.T) {
329 cases := []struct {
330 pattern string
331 input string
332 flags int
333 want bool
334 }{
335
336 {"foo", "foo/bar", 0, false},
337 {"foo", "foo/bar", fnmatch.FNM_LEADING_DIR, true},
338 {"*", "foo/bar", fnmatch.FNM_PATHNAME, false},
339 {"*", "foo/bar", fnmatch.FNM_PATHNAME | fnmatch.FNM_LEADING_DIR, true},
340 }
341
342 for tc, c := range cases {
343 got := fnmatch.Match(c.pattern, c.input, c.flags)
344 if got != c.want {
345 t.Errorf(
346 "Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
347 tc, c.pattern, c.input, c.flags, c.want, got,
348 )
349 }
350 }
351 }
352
View as plain text