~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_globbing.py

  • Committer: Martin Pool
  • Date: 2005-09-13 00:39:44 UTC
  • mto: (1185.8.2) (974.1.91)
  • mto: This revision was merged to the branch mainline in revision 1390.
  • Revision ID: mbp@sourcefrog.net-20050913003944-4890c9f8f04f37a5
- remove TestCase.run override which captures output

  this is *not* the way we want to do it now; it's a bug if the 
  library produces any output without permission

Show diffs side-by-side

added added

removed removed

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