~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_globbing.py

  • Committer: John Arbash Meinel
  • Date: 2010-01-05 04:08:35 UTC
  • mfrom: (4634.108.10 2.0)
  • mto: This revision was merged to the branch mainline in revision 4933.
  • Revision ID: john@arbash-meinel.com-20100105040835-sq0zrv5dte8sqqib
Merge stable, including bug #495023

Show diffs side-by-side

added added

removed removed

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