~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-05-05 07:00:55 UTC
  • Revision ID: mbp@sourcefrog.net-20050505070055-e1ef8f7dd14b48b1
- Fix up bzr log command

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/\\\\/'))