/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_globbing.py

  • Committer: Robert Collins
  • Date: 2005-10-19 10:11:57 UTC
  • mfrom: (1185.16.78)
  • mto: This revision was merged to the branch mainline in revision 1470.
  • Revision ID: robertc@robertcollins.net-20051019101157-17438d311e746b4f
mergeĀ fromĀ upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
2
 
# -*- coding: utf-8 -*-
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License as published by
6
 
# the Free Software Foundation; either version 2 of the License, or
7
 
# (at your option) any later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License
15
 
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
 
 
18
 
import re
19
 
 
20
 
from .. import errors, lazy_regex
21
 
from ..globbing import (
22
 
    Globster,
23
 
    ExceptionGlobster,
24
 
    _OrderedGlobster,
25
 
    normalize_pattern
26
 
    )
27
 
from . import (
28
 
    TestCase,
29
 
    )
30
 
 
31
 
 
32
 
class TestGlobster(TestCase):
33
 
 
34
 
    def assertMatch(self, matchset, glob_prefix=None):
35
 
        for glob, positive, negative in matchset:
36
 
            if glob_prefix:
37
 
                glob = glob_prefix + glob
38
 
            globster = Globster([glob])
39
 
            for name in positive:
40
 
                self.assertTrue(globster.match(name), repr(
41
 
                    u'name "%s" does not match glob "%s" (re=%s)' %
42
 
                    (name, glob, globster._regex_patterns[0][0].pattern)))
43
 
            for name in negative:
44
 
                self.assertFalse(globster.match(name), repr(
45
 
                    u'name "%s" does match glob "%s" (re=%s)' %
46
 
                    (name, glob, globster._regex_patterns[0][0].pattern)))
47
 
 
48
 
    def assertMatchBasenameAndFullpath(self, matchset):
49
 
        # test basename matcher
50
 
        self.assertMatch(matchset)
51
 
        # test fullpath matcher
52
 
        self.assertMatch(matchset, glob_prefix='./')
53
 
 
54
 
    def test_char_group_digit(self):
55
 
        self.assertMatchBasenameAndFullpath([
56
 
            # The definition of digit this uses includes arabic digits from
57
 
            # non-latin scripts (arabic, indic, etc.) but neither roman
58
 
            # numerals nor vulgar fractions. Some characters such as
59
 
            # subscript/superscript digits may or may not match depending on
60
 
            # the Python version used, see: <http://bugs.python.org/issue6561>
61
 
            (u'[[:digit:]]',
62
 
             [u'0', u'5', u'\u0663', u'\u06f9', u'\u0f21'],
63
 
             [u'T', u'q', u' ', u'\u8336', u'.']),
64
 
            (u'[^[:digit:]]',
65
 
             [u'T', u'q', u' ', u'\u8336', u'.'],
66
 
             [u'0', u'5', u'\u0663', u'\u06f9', u'\u0f21']),
67
 
            ])
68
 
 
69
 
    def test_char_group_space(self):
70
 
        self.assertMatchBasenameAndFullpath([
71
 
            (u'[[:space:]]',
72
 
             [u' ', u'\t', u'\n', u'\xa0', u'\u2000', u'\u2002'],
73
 
             [u'a', u'-', u'\u8336', u'.']),
74
 
            (u'[^[:space:]]',
75
 
             [u'a', u'-', u'\u8336', u'.'],
76
 
             [u' ', u'\t', u'\n', u'\xa0', u'\u2000', u'\u2002']),
77
 
            ])
78
 
 
79
 
    def test_char_group_alnum(self):
80
 
        self.assertMatchBasenameAndFullpath([
81
 
            (u'[[:alnum:]]',
82
 
             [u'a', u'Z', u'\u017e', u'\u8336'],
83
 
             [u':', u'-', u'\u25cf', u'.']),
84
 
            (u'[^[:alnum:]]',
85
 
             [u':', u'-', u'\u25cf', u'.'],
86
 
             [u'a']),
87
 
            ])
88
 
 
89
 
    def test_char_group_ascii(self):
90
 
        self.assertMatchBasenameAndFullpath([
91
 
            (u'[[:ascii:]]',
92
 
             [u'a', u'Q', u'^', u'.'],
93
 
             [u'\xcc', u'\u8336']),
94
 
            (u'[^[:ascii:]]',
95
 
             [u'\xcc', u'\u8336'],
96
 
             [u'a', u'Q', u'^', u'.']),
97
 
            ])
98
 
 
99
 
    def test_char_group_blank(self):
100
 
        self.assertMatchBasenameAndFullpath([
101
 
            (u'[[:blank:]]',
102
 
             [u'\t'],
103
 
             [u'x', u'y', u'z', u'.']),
104
 
            (u'[^[:blank:]]',
105
 
             [u'x', u'y', u'z', u'.'],
106
 
             [u'\t']),
107
 
            ])
108
 
 
109
 
    def test_char_group_cntrl(self):
110
 
        self.assertMatchBasenameAndFullpath([
111
 
            (u'[[:cntrl:]]',
112
 
             [u'\b', u'\t', '\x7f'],
113
 
             [u'a', u'Q', u'\u8336', u'.']),
114
 
            (u'[^[:cntrl:]]',
115
 
             [u'a', u'Q', u'\u8336', u'.'],
116
 
             [u'\b', u'\t', '\x7f']),
117
 
            ])
118
 
 
119
 
    def test_char_group_range(self):
120
 
        self.assertMatchBasenameAndFullpath([
121
 
            (u'[a-z]',
122
 
             [u'a', u'q', u'f'],
123
 
             [u'A', u'Q', u'F']),
124
 
            (u'[^a-z]',
125
 
             [u'A', u'Q', u'F'],
126
 
             [u'a', u'q', u'f']),
127
 
            (u'[!a-z]foo',
128
 
             [u'Afoo', u'.foo'],
129
 
             [u'afoo', u'ABfoo']),
130
 
            (u'foo[!a-z]bar',
131
 
             [u'fooAbar', u'foo.bar'],
132
 
             [u'foojbar']),
133
 
            (u'[\x20-\x30\u8336]',
134
 
             [u'\040', u'\044', u'\u8336'],
135
 
             [u'\x1f']),
136
 
            (u'[^\x20-\x30\u8336]',
137
 
             [u'\x1f'],
138
 
             [u'\040', u'\044', u'\u8336']),
139
 
            ])
140
 
 
141
 
    def test_regex(self):
142
 
        self.assertMatch([
143
 
            (u'RE:(a|b|c+)',
144
 
             [u'a', u'b', u'ccc'],
145
 
             [u'd', u'aa', u'c+', u'-a']),
146
 
            (u'RE:(?:a|b|c+)',
147
 
             [u'a', u'b', u'ccc'],
148
 
             [u'd', u'aa', u'c+', u'-a']),
149
 
            (u'RE:(?P<a>.)(?P=a)',
150
 
             [u'a'],
151
 
             [u'ab', u'aa', u'aaa']),
152
 
            # test we can handle odd numbers of trailing backslashes
153
 
            (u'RE:a\\\\\\',
154
 
             [u'a\\'],
155
 
             [u'a', u'ab', u'aa', u'aaa']),
156
 
            ])
157
 
 
158
 
    def test_question_mark(self):
159
 
        self.assertMatch([
160
 
            (u'?foo',
161
 
             [u'xfoo', u'bar/xfoo', u'bar/\u8336foo', u'.foo', u'bar/.foo'],
162
 
             [u'bar/foo', u'foo']),
163
 
            (u'foo?bar',
164
 
             [u'fooxbar', u'foo.bar', u'foo\u8336bar', u'qyzzy/foo.bar'],
165
 
             [u'foo/bar']),
166
 
            (u'foo/?bar',
167
 
             [u'foo/xbar', u'foo/\u8336bar', u'foo/.bar'],
168
 
             [u'foo/bar', u'bar/foo/xbar']),
169
 
            ])
170
 
 
171
 
    def test_asterisk(self):
172
 
        self.assertMatch([
173
 
            (u'x*x',
174
 
             [u'xx', u'x.x', u'x\u8336..x', u'\u8336/x.x', u'x.y.x'],
175
 
             [u'x/x', u'bar/x/bar/x', u'bax/abaxab']),
176
 
            (u'foo/*x',
177
 
             [u'foo/x', u'foo/bax', u'foo/a.x', u'foo/.x', u'foo/.q.x'],
178
 
             [u'foo/bar/bax']),
179
 
            (u'*/*x',
180
 
             [u'\u8336/x', u'foo/x', u'foo/bax', u'x/a.x', u'.foo/x',
181
 
              u'\u8336/.x', u'foo/.q.x'],
182
 
             [u'foo/bar/bax']),
183
 
            (u'f*',
184
 
             [u'foo', u'foo.bar'],
185
 
             [u'.foo', u'foo/bar', u'foo/.bar']),
186
 
            (u'*bar',
187
 
             [u'bar', u'foobar', u'foo\\nbar', u'foo.bar', u'foo/bar',
188
 
              u'foo/foobar', u'foo/f.bar', u'.bar', u'foo/.bar'],
189
 
             []),
190
 
            ])
191
 
 
192
 
    def test_double_asterisk(self):
193
 
        self.assertMatch([
194
 
            # expected uses of double asterisk
195
 
            (u'foo/**/x',
196
 
             [u'foo/x', u'foo/bar/x'],
197
 
             [u'foox', u'foo/bax', u'foo/.x', u'foo/bar/bax']),
198
 
            (u'**/bar',
199
 
             [u'bar', u'foo/bar'],
200
 
             [u'foobar', u'foo.bar', u'foo/foobar', u'foo/f.bar',
201
 
              u'.bar', u'foo/.bar']),
202
 
            # check that we ignore extra *s, so *** is treated like ** not *.
203
 
            (u'foo/***/x',
204
 
             [u'foo/x', u'foo/bar/x'],
205
 
             [u'foox', u'foo/bax', u'foo/.x', u'foo/bar/bax']),
206
 
            (u'***/bar',
207
 
             [u'bar', u'foo/bar'],
208
 
             [u'foobar', u'foo.bar', u'foo/foobar', u'foo/f.bar',
209
 
              u'.bar', u'foo/.bar']),
210
 
            # the remaining tests check that ** is interpreted as *
211
 
            # unless it is a whole path component
212
 
            (u'x**/x',
213
 
             [u'x\u8336/x', u'x/x'],
214
 
             [u'xx', u'x.x', u'bar/x/bar/x', u'x.y.x', u'x/y/x']),
215
 
            (u'x**x',
216
 
             [u'xx', u'x.x', u'x\u8336..x', u'foo/x.x', u'x.y.x'],
217
 
             [u'bar/x/bar/x', u'xfoo/bar/x', u'x/x', u'bax/abaxab']),
218
 
            (u'foo/**x',
219
 
             [u'foo/x', u'foo/bax', u'foo/a.x', u'foo/.x', u'foo/.q.x'],
220
 
             [u'foo/bar/bax']),
221
 
            (u'f**',
222
 
             [u'foo', u'foo.bar'],
223
 
             [u'.foo', u'foo/bar', u'foo/.bar']),
224
 
            (u'**bar',
225
 
             [u'bar', u'foobar', u'foo\\nbar', u'foo.bar', u'foo/bar',
226
 
              u'foo/foobar', u'foo/f.bar', u'.bar', u'foo/.bar'],
227
 
             []),
228
 
            ])
229
 
 
230
 
    def test_leading_dot_slash(self):
231
 
        self.assertMatch([
232
 
            (u'./foo',
233
 
             [u'foo'],
234
 
             [u'\u8336/foo', u'barfoo', u'x/y/foo']),
235
 
            (u'./f*',
236
 
             [u'foo'],
237
 
             [u'foo/bar', u'foo/.bar', u'x/foo/y']),
238
 
            ])
239
 
 
240
 
    def test_backslash(self):
241
 
        self.assertMatch([
242
 
            (u'.\\foo',
243
 
             [u'foo'],
244
 
             [u'\u8336/foo', u'barfoo', u'x/y/foo']),
245
 
            (u'.\\f*',
246
 
             [u'foo'],
247
 
             [u'foo/bar', u'foo/.bar', u'x/foo/y']),
248
 
            (u'foo\\**\\x',
249
 
             [u'foo/x', u'foo/bar/x'],
250
 
             [u'foox', u'foo/bax', u'foo/.x', u'foo/bar/bax']),
251
 
            ])
252
 
 
253
 
    def test_trailing_slash(self):
254
 
        self.assertMatch([
255
 
            (u'./foo/',
256
 
             [u'foo'],
257
 
             [u'\u8336/foo', u'barfoo', u'x/y/foo']),
258
 
            (u'.\\foo\\',
259
 
             [u'foo'],
260
 
             [u'foo/', u'\u8336/foo', u'barfoo', u'x/y/foo']),
261
 
            ])
262
 
 
263
 
    def test_leading_asterisk_dot(self):
264
 
        self.assertMatch([
265
 
            (u'*.x',
266
 
             [u'foo/bar/baz.x', u'\u8336/Q.x', u'foo.y.x', u'.foo.x',
267
 
              u'bar/.foo.x', u'.x', ],
268
 
             [u'foo.x.y']),
269
 
            (u'foo/*.bar',
270
 
             [u'foo/b.bar', u'foo/a.b.bar', u'foo/.bar'],
271
 
             [u'foo/bar']),
272
 
            (u'*.~*',
273
 
             [u'foo.py.~1~', u'.foo.py.~1~'],
274
 
             []),
275
 
            ])
276
 
 
277
 
    def test_end_anchor(self):
278
 
        self.assertMatch([
279
 
            (u'*.333',
280
 
             [u'foo.333'],
281
 
             [u'foo.3']),
282
 
            (u'*.3',
283
 
             [u'foo.3'],
284
 
             [u'foo.333']),
285
 
            ])
286
 
 
287
 
    def test_mixed_globs(self):
288
 
        """tests handling of combinations of path type matches.
289
 
 
290
 
        The types being extension, basename and full path.
291
 
        """
292
 
        patterns = [u'*.foo', u'.*.swp', u'./*.png']
293
 
        globster = Globster(patterns)
294
 
        self.assertEqual(u'*.foo', globster.match('bar.foo'))
295
 
        self.assertEqual(u'./*.png', globster.match('foo.png'))
296
 
        self.assertEqual(None, globster.match('foo/bar.png'))
297
 
        self.assertEqual(u'.*.swp', globster.match('foo/.bar.py.swp'))
298
 
 
299
 
    def test_large_globset(self):
300
 
        """tests that the globster can handle a large set of patterns.
301
 
 
302
 
        Large is defined as more than supported by python regex groups,
303
 
        i.e. 99.
304
 
        This test assumes the globs are broken into regexs containing 99
305
 
        groups.
306
 
        """
307
 
        patterns = [u'*.%03d' % i for i in range(300)]
308
 
        globster = Globster(patterns)
309
 
        # test the fence posts
310
 
        for x in (0, 98, 99, 197, 198, 296, 297, 299):
311
 
            filename = u'foo.%03d' % x
312
 
            self.assertEqual(patterns[x], globster.match(filename))
313
 
        self.assertEqual(None, globster.match('foobar.300'))
314
 
 
315
 
    def test_bad_pattern(self):
316
 
        """Ensure that globster handles bad patterns cleanly."""
317
 
        patterns = [u'RE:[', u'/home/foo', u'RE:*.cpp']
318
 
        g = Globster(patterns)
319
 
        e = self.assertRaises(lazy_regex.InvalidPattern, g.match, 'filename')
320
 
        self.assertContainsRe(e.msg,
321
 
                              r"File.*ignore.*contains error.*RE:\[.*RE:\*\.cpp", flags=re.DOTALL)
322
 
 
323
 
 
324
 
class TestExceptionGlobster(TestCase):
325
 
 
326
 
    def test_exclusion_patterns(self):
327
 
        """test that exception patterns are not matched"""
328
 
        patterns = [u'*', u'!./local', u'!./local/**/*',
329
 
                    u'!RE:\\.z.*', u'!!./.zcompdump']
330
 
        globster = ExceptionGlobster(patterns)
331
 
        self.assertEqual(u'*', globster.match('tmp/foo.txt'))
332
 
        self.assertEqual(None, globster.match('local'))
333
 
        self.assertEqual(None, globster.match('local/bin/wombat'))
334
 
        self.assertEqual(None, globster.match('.zshrc'))
335
 
        self.assertEqual(None, globster.match('.zfunctions/fiddle/flam'))
336
 
        self.assertEqual(u'!!./.zcompdump', globster.match('.zcompdump'))
337
 
 
338
 
    def test_exclusion_order(self):
339
 
        """test that ordering of exclusion patterns does not matter"""
340
 
        patterns = [u'static/**/*.html', u'!static/**/versionable.html']
341
 
        globster = ExceptionGlobster(patterns)
342
 
        self.assertEqual(u'static/**/*.html',
343
 
                         globster.match('static/foo.html'))
344
 
        self.assertEqual(None, globster.match('static/versionable.html'))
345
 
        self.assertEqual(None, globster.match('static/bar/versionable.html'))
346
 
        globster = ExceptionGlobster(reversed(patterns))
347
 
        self.assertEqual(u'static/**/*.html',
348
 
                         globster.match('static/foo.html'))
349
 
        self.assertEqual(None, globster.match('static/versionable.html'))
350
 
        self.assertEqual(None, globster.match('static/bar/versionable.html'))
351
 
 
352
 
 
353
 
class TestOrderedGlobster(TestCase):
354
 
 
355
 
    def test_ordered_globs(self):
356
 
        """test that the first match in a list is the one found"""
357
 
        patterns = [u'*.foo', u'bar.*']
358
 
        globster = _OrderedGlobster(patterns)
359
 
        self.assertEqual(u'*.foo', globster.match('bar.foo'))
360
 
        self.assertEqual(None, globster.match('foo.bar'))
361
 
        globster = _OrderedGlobster(reversed(patterns))
362
 
        self.assertEqual(u'bar.*', globster.match('bar.foo'))
363
 
        self.assertEqual(None, globster.match('foo.bar'))
364
 
 
365
 
 
366
 
class TestNormalizePattern(TestCase):
367
 
 
368
 
    def test_backslashes(self):
369
 
        """tests that backslashes are converted to forward slashes, multiple
370
 
        backslashes are collapsed to single forward slashes and trailing
371
 
        backslashes are removed"""
372
 
        self.assertEqual(u'/', normalize_pattern(u'\\'))
373
 
        self.assertEqual(u'/', normalize_pattern(u'\\\\'))
374
 
        self.assertEqual(u'/foo/bar', normalize_pattern(u'\\foo\\bar'))
375
 
        self.assertEqual(u'foo/bar', normalize_pattern(u'foo\\bar\\'))
376
 
        self.assertEqual(u'/foo/bar', normalize_pattern(u'\\\\foo\\\\bar\\\\'))
377
 
 
378
 
    def test_forward_slashes(self):
379
 
        """tests that multiple foward slashes are collapsed to single forward
380
 
        slashes and trailing forward slashes are removed"""
381
 
        self.assertEqual(u'/', normalize_pattern(u'/'))
382
 
        self.assertEqual(u'/', normalize_pattern(u'//'))
383
 
        self.assertEqual(u'/foo/bar', normalize_pattern(u'/foo/bar'))
384
 
        self.assertEqual(u'foo/bar', normalize_pattern(u'foo/bar/'))
385
 
        self.assertEqual(u'/foo/bar', normalize_pattern(u'//foo//bar//'))
386
 
 
387
 
    def test_mixed_slashes(self):
388
 
        """tests that multiple mixed slashes are collapsed to single forward
389
 
        slashes and trailing mixed slashes are removed"""
390
 
        self.assertEqual(
391
 
            u'/foo/bar', normalize_pattern(u'\\/\\foo//\\///bar/\\\\/'))