~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_globbing.py

  • Committer: Robert Collins
  • Date: 2007-07-04 08:08:13 UTC
  • mfrom: (2572 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2587.
  • Revision ID: robertc@robertcollins.net-20070704080813-wzebx0r88fvwj5rq
Merge bzr.dev.

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