1 """Test cases for the fnmatch module."""
2
3 import unittest
4 import os
5 import string
6 import warnings
7
8 from fnmatch import fnmatch, fnmatchcase, translate, filter
9
10 class ESC[4;38;5;81mFnmatchTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
11
12 def check_match(self, filename, pattern, should_match=True, fn=fnmatch):
13 if should_match:
14 self.assertTrue(fn(filename, pattern),
15 "expected %r to match pattern %r"
16 % (filename, pattern))
17 else:
18 self.assertFalse(fn(filename, pattern),
19 "expected %r not to match pattern %r"
20 % (filename, pattern))
21
22 def test_fnmatch(self):
23 check = self.check_match
24 check('abc', 'abc')
25 check('abc', '?*?')
26 check('abc', '???*')
27 check('abc', '*???')
28 check('abc', '???')
29 check('abc', '*')
30 check('abc', 'ab[cd]')
31 check('abc', 'ab[!de]')
32 check('abc', 'ab[de]', False)
33 check('a', '??', False)
34 check('a', 'b', False)
35
36 # these test that '\' is handled correctly in character sets;
37 # see SF bug #409651
38 check('\\', r'[\]')
39 check('a', r'[!\]')
40 check('\\', r'[!\]', False)
41
42 # test that filenames with newlines in them are handled correctly.
43 # http://bugs.python.org/issue6665
44 check('foo\nbar', 'foo*')
45 check('foo\nbar\n', 'foo*')
46 check('\nfoo', 'foo*', False)
47 check('\n', '*')
48
49 def test_slow_fnmatch(self):
50 check = self.check_match
51 check('a' * 50, '*a*a*a*a*a*a*a*a*a*a')
52 # The next "takes forever" if the regexp translation is
53 # straightforward. See bpo-40480.
54 check('a' * 50 + 'b', '*a*a*a*a*a*a*a*a*a*a', False)
55
56 def test_mix_bytes_str(self):
57 self.assertRaises(TypeError, fnmatch, 'test', b'*')
58 self.assertRaises(TypeError, fnmatch, b'test', '*')
59 self.assertRaises(TypeError, fnmatchcase, 'test', b'*')
60 self.assertRaises(TypeError, fnmatchcase, b'test', '*')
61
62 def test_fnmatchcase(self):
63 check = self.check_match
64 check('abc', 'abc', True, fnmatchcase)
65 check('AbC', 'abc', False, fnmatchcase)
66 check('abc', 'AbC', False, fnmatchcase)
67 check('AbC', 'AbC', True, fnmatchcase)
68
69 check('usr/bin', 'usr/bin', True, fnmatchcase)
70 check('usr\\bin', 'usr/bin', False, fnmatchcase)
71 check('usr/bin', 'usr\\bin', False, fnmatchcase)
72 check('usr\\bin', 'usr\\bin', True, fnmatchcase)
73
74 def test_bytes(self):
75 self.check_match(b'test', b'te*')
76 self.check_match(b'test\xff', b'te*\xff')
77 self.check_match(b'foo\nbar', b'foo*')
78
79 def test_case(self):
80 ignorecase = os.path.normcase('ABC') == os.path.normcase('abc')
81 check = self.check_match
82 check('abc', 'abc')
83 check('AbC', 'abc', ignorecase)
84 check('abc', 'AbC', ignorecase)
85 check('AbC', 'AbC')
86
87 def test_sep(self):
88 normsep = os.path.normcase('\\') == os.path.normcase('/')
89 check = self.check_match
90 check('usr/bin', 'usr/bin')
91 check('usr\\bin', 'usr/bin', normsep)
92 check('usr/bin', 'usr\\bin', normsep)
93 check('usr\\bin', 'usr\\bin')
94
95 def test_char_set(self):
96 ignorecase = os.path.normcase('ABC') == os.path.normcase('abc')
97 check = self.check_match
98 tescases = string.ascii_lowercase + string.digits + string.punctuation
99 for c in tescases:
100 check(c, '[az]', c in 'az')
101 check(c, '[!az]', c not in 'az')
102 # Case insensitive.
103 for c in tescases:
104 check(c, '[AZ]', (c in 'az') and ignorecase)
105 check(c, '[!AZ]', (c not in 'az') or not ignorecase)
106 for c in string.ascii_uppercase:
107 check(c, '[az]', (c in 'AZ') and ignorecase)
108 check(c, '[!az]', (c not in 'AZ') or not ignorecase)
109 # Repeated same character.
110 for c in tescases:
111 check(c, '[aa]', c == 'a')
112 # Special cases.
113 for c in tescases:
114 check(c, '[^az]', c in '^az')
115 check(c, '[[az]', c in '[az')
116 check(c, r'[!]]', c != ']')
117 check('[', '[')
118 check('[]', '[]')
119 check('[!', '[!')
120 check('[!]', '[!]')
121
122 def test_range(self):
123 ignorecase = os.path.normcase('ABC') == os.path.normcase('abc')
124 normsep = os.path.normcase('\\') == os.path.normcase('/')
125 check = self.check_match
126 tescases = string.ascii_lowercase + string.digits + string.punctuation
127 for c in tescases:
128 check(c, '[b-d]', c in 'bcd')
129 check(c, '[!b-d]', c not in 'bcd')
130 check(c, '[b-dx-z]', c in 'bcdxyz')
131 check(c, '[!b-dx-z]', c not in 'bcdxyz')
132 # Case insensitive.
133 for c in tescases:
134 check(c, '[B-D]', (c in 'bcd') and ignorecase)
135 check(c, '[!B-D]', (c not in 'bcd') or not ignorecase)
136 for c in string.ascii_uppercase:
137 check(c, '[b-d]', (c in 'BCD') and ignorecase)
138 check(c, '[!b-d]', (c not in 'BCD') or not ignorecase)
139 # Upper bound == lower bound.
140 for c in tescases:
141 check(c, '[b-b]', c == 'b')
142 # Special cases.
143 for c in tescases:
144 check(c, '[!-#]', c not in '-#')
145 check(c, '[!--.]', c not in '-.')
146 check(c, '[^-`]', c in '^_`')
147 if not (normsep and c == '/'):
148 check(c, '[[-^]', c in r'[\]^')
149 check(c, r'[\-^]', c in r'\]^')
150 check(c, '[b-]', c in '-b')
151 check(c, '[!b-]', c not in '-b')
152 check(c, '[-b]', c in '-b')
153 check(c, '[!-b]', c not in '-b')
154 check(c, '[-]', c in '-')
155 check(c, '[!-]', c not in '-')
156 # Upper bound is less that lower bound: error in RE.
157 for c in tescases:
158 check(c, '[d-b]', False)
159 check(c, '[!d-b]', True)
160 check(c, '[d-bx-z]', c in 'xyz')
161 check(c, '[!d-bx-z]', c not in 'xyz')
162 check(c, '[d-b^-`]', c in '^_`')
163 if not (normsep and c == '/'):
164 check(c, '[d-b[-^]', c in r'[\]^')
165
166 def test_sep_in_char_set(self):
167 normsep = os.path.normcase('\\') == os.path.normcase('/')
168 check = self.check_match
169 check('/', r'[/]')
170 check('\\', r'[\]')
171 check('/', r'[\]', normsep)
172 check('\\', r'[/]', normsep)
173 check('[/]', r'[/]', False)
174 check(r'[\\]', r'[/]', False)
175 check('\\', r'[\t]')
176 check('/', r'[\t]', normsep)
177 check('t', r'[\t]')
178 check('\t', r'[\t]', False)
179
180 def test_sep_in_range(self):
181 normsep = os.path.normcase('\\') == os.path.normcase('/')
182 check = self.check_match
183 check('a/b', 'a[.-0]b', not normsep)
184 check('a\\b', 'a[.-0]b', False)
185 check('a\\b', 'a[Z-^]b', not normsep)
186 check('a/b', 'a[Z-^]b', False)
187
188 check('a/b', 'a[/-0]b', not normsep)
189 check(r'a\b', 'a[/-0]b', False)
190 check('a[/-0]b', 'a[/-0]b', False)
191 check(r'a[\-0]b', 'a[/-0]b', False)
192
193 check('a/b', 'a[.-/]b')
194 check(r'a\b', 'a[.-/]b', normsep)
195 check('a[.-/]b', 'a[.-/]b', False)
196 check(r'a[.-\]b', 'a[.-/]b', False)
197
198 check(r'a\b', r'a[\-^]b')
199 check('a/b', r'a[\-^]b', normsep)
200 check(r'a[\-^]b', r'a[\-^]b', False)
201 check('a[/-^]b', r'a[\-^]b', False)
202
203 check(r'a\b', r'a[Z-\]b', not normsep)
204 check('a/b', r'a[Z-\]b', False)
205 check(r'a[Z-\]b', r'a[Z-\]b', False)
206 check('a[Z-/]b', r'a[Z-\]b', False)
207
208 def test_warnings(self):
209 with warnings.catch_warnings():
210 warnings.simplefilter('error', Warning)
211 check = self.check_match
212 check('[', '[[]')
213 check('&', '[a&&b]')
214 check('|', '[a||b]')
215 check('~', '[a~~b]')
216 check(',', '[a-z+--A-Z]')
217 check('.', '[a-z--/A-Z]')
218
219
220 class ESC[4;38;5;81mTranslateTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
221
222 def test_translate(self):
223 import re
224 self.assertEqual(translate('*'), r'(?s:.*)\Z')
225 self.assertEqual(translate('?'), r'(?s:.)\Z')
226 self.assertEqual(translate('a?b*'), r'(?s:a.b.*)\Z')
227 self.assertEqual(translate('[abc]'), r'(?s:[abc])\Z')
228 self.assertEqual(translate('[]]'), r'(?s:[]])\Z')
229 self.assertEqual(translate('[!x]'), r'(?s:[^x])\Z')
230 self.assertEqual(translate('[^x]'), r'(?s:[\^x])\Z')
231 self.assertEqual(translate('[x'), r'(?s:\[x)\Z')
232 # from the docs
233 self.assertEqual(translate('*.txt'), r'(?s:.*\.txt)\Z')
234 # squash consecutive stars
235 self.assertEqual(translate('*********'), r'(?s:.*)\Z')
236 self.assertEqual(translate('A*********'), r'(?s:A.*)\Z')
237 self.assertEqual(translate('*********A'), r'(?s:.*A)\Z')
238 self.assertEqual(translate('A*********?[?]?'), r'(?s:A.*.[?].)\Z')
239 # fancy translation to prevent exponential-time match failure
240 t = translate('**a*a****a')
241 self.assertEqual(t, r'(?s:(?>.*?a)(?>.*?a).*a)\Z')
242 # and try pasting multiple translate results - it's an undocumented
243 # feature that this works
244 r1 = translate('**a**a**a*')
245 r2 = translate('**b**b**b*')
246 r3 = translate('*c*c*c*')
247 fatre = "|".join([r1, r2, r3])
248 self.assertTrue(re.match(fatre, 'abaccad'))
249 self.assertTrue(re.match(fatre, 'abxbcab'))
250 self.assertTrue(re.match(fatre, 'cbabcaxc'))
251 self.assertFalse(re.match(fatre, 'dabccbad'))
252
253 class ESC[4;38;5;81mFilterTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
254
255 def test_filter(self):
256 self.assertEqual(filter(['Python', 'Ruby', 'Perl', 'Tcl'], 'P*'),
257 ['Python', 'Perl'])
258 self.assertEqual(filter([b'Python', b'Ruby', b'Perl', b'Tcl'], b'P*'),
259 [b'Python', b'Perl'])
260
261 def test_mix_bytes_str(self):
262 self.assertRaises(TypeError, filter, ['test'], b'*')
263 self.assertRaises(TypeError, filter, [b'test'], '*')
264
265 def test_case(self):
266 ignorecase = os.path.normcase('P') == os.path.normcase('p')
267 self.assertEqual(filter(['Test.py', 'Test.rb', 'Test.PL'], '*.p*'),
268 ['Test.py', 'Test.PL'] if ignorecase else ['Test.py'])
269 self.assertEqual(filter(['Test.py', 'Test.rb', 'Test.PL'], '*.P*'),
270 ['Test.py', 'Test.PL'] if ignorecase else ['Test.PL'])
271
272 def test_sep(self):
273 normsep = os.path.normcase('\\') == os.path.normcase('/')
274 self.assertEqual(filter(['usr/bin', 'usr', 'usr\\lib'], 'usr/*'),
275 ['usr/bin', 'usr\\lib'] if normsep else ['usr/bin'])
276 self.assertEqual(filter(['usr/bin', 'usr', 'usr\\lib'], 'usr\\*'),
277 ['usr/bin', 'usr\\lib'] if normsep else ['usr\\lib'])
278
279
280 if __name__ == "__main__":
281 unittest.main()