~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_win32utils.py

  • Committer: Martin Pool
  • Date: 2010-04-01 04:41:18 UTC
  • mto: This revision was merged to the branch mainline in revision 5128.
  • Revision ID: mbp@sourcefrog.net-20100401044118-shyctqc02ob08ngz
ignore .testrepository

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007 Canonical Ltd
 
1
# Copyright (C) 2007-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
import os
18
18
import sys
19
19
 
20
 
from bzrlib import osutils
 
20
from bzrlib import (
 
21
    osutils,
 
22
    tests,
 
23
    win32utils,
 
24
    )
21
25
from bzrlib.tests import (
22
26
    Feature,
23
27
    TestCase,
26
30
    UnicodeFilenameFeature,
27
31
    )
28
32
from bzrlib.win32utils import glob_expand, get_app_path
29
 
from bzrlib import win32utils
30
 
 
31
 
 
32
 
# Features
33
 
# --------
34
 
 
35
 
class _NeedsGlobExpansionFeature(Feature):
 
33
 
 
34
 
 
35
class _BackslashDirSeparatorFeature(tests.Feature):
36
36
 
37
37
    def _probe(self):
38
 
        return sys.platform == 'win32'
 
38
        try:
 
39
            os.lstat(os.getcwd() + '\\')
 
40
        except OSError:
 
41
            return False
 
42
        else:
 
43
            return True
39
44
 
40
45
    def feature_name(self):
41
 
        return 'Internally performed glob expansion'
 
46
        return "Filesystem treats '\\' as a directory separator."
42
47
 
43
 
NeedsGlobExpansionFeature = _NeedsGlobExpansionFeature()
 
48
BackslashDirSeparatorFeature = _BackslashDirSeparatorFeature()
44
49
 
45
50
 
46
51
class _RequiredModuleFeature(Feature):
67
72
# Tests
68
73
# -----
69
74
 
70
 
class TestNeedsGlobExpansionFeature(TestCase):
71
 
 
72
 
    def test_available(self):
73
 
        self.assertEqual(sys.platform == 'win32',
74
 
                         NeedsGlobExpansionFeature.available())
75
 
 
76
 
    def test_str(self):
77
 
        self.assertTrue("performed" in str(NeedsGlobExpansionFeature))
78
 
 
79
 
 
80
75
class TestWin32UtilsGlobExpand(TestCaseInTempDir):
81
76
 
82
 
    _test_needs_features = [NeedsGlobExpansionFeature]
 
77
    _test_needs_features = []
83
78
 
84
79
    def test_empty_tree(self):
85
80
        self.build_tree([])
89
84
            [['*'], ['*']],
90
85
            [['a', 'a'], ['a', 'a']]])
91
86
 
92
 
    def test_tree_ascii(self):
93
 
        """Checks the glob expansion and path separation char
94
 
        normalization"""
 
87
    def build_ascii_tree(self):
95
88
        self.build_tree(['a', 'a1', 'a2', 'a11', 'a.1',
96
89
                         'b', 'b1', 'b2', 'b3',
97
90
                         'c/', 'c/c1', 'c/c2',
98
91
                         'd/', 'd/d1', 'd/d2', 'd/e/', 'd/e/e1'])
 
92
 
 
93
    def build_unicode_tree(self):
 
94
        self.requireFeature(UnicodeFilenameFeature)
 
95
        self.build_tree([u'\u1234', u'\u1234\u1234', u'\u1235/',
 
96
                         u'\u1235/\u1235'])
 
97
 
 
98
    def test_tree_ascii(self):
 
99
        """Checks the glob expansion and path separation char
 
100
        normalization"""
 
101
        self.build_ascii_tree()
99
102
        self._run_testset([
100
103
            # no wildcards
101
104
            [[u'a'], [u'a']],
102
105
            [[u'a', u'a' ], [u'a', u'a']],
103
 
            [[u'A'], [u'A']],
104
106
 
105
107
            [[u'd'], [u'd']],
106
108
            [[u'd/'], [u'd/']],
107
 
            [[u'd\\'], [u'd/']],
108
109
 
109
110
            # wildcards
110
111
            [[u'a*'], [u'a', u'a1', u'a2', u'a11', u'a.1']],
112
113
            [[u'a?'], [u'a1', u'a2']],
113
114
            [[u'a??'], [u'a11', u'a.1']],
114
115
            [[u'b[1-2]'], [u'b1', u'b2']],
115
 
            [[u'A?'], [u'a1', u'a2']],
116
116
 
117
117
            [[u'd/*'], [u'd/d1', u'd/d2', u'd/e']],
 
118
            [[u'?/*'], [u'c/c1', u'c/c2', u'd/d1', u'd/d2', u'd/e']],
 
119
            [[u'*/*'], [u'c/c1', u'c/c2', u'd/d1', u'd/d2', u'd/e']],
 
120
            [[u'*/'], [u'c/', u'd/']],
 
121
            ])
 
122
 
 
123
    def test_backslash_globbing(self):
 
124
        self.requireFeature(BackslashDirSeparatorFeature)
 
125
        self.build_ascii_tree()
 
126
        self._run_testset([
 
127
            [[u'd\\'], [u'd/']],
118
128
            [[u'd\\*'], [u'd/d1', u'd/d2', u'd/e']],
119
129
            [[u'?\\*'], [u'c/c1', u'c/c2', u'd/d1', u'd/d2', u'd/e']],
120
130
            [[u'*\\*'], [u'c/c1', u'c/c2', u'd/d1', u'd/d2', u'd/e']],
121
 
            [[u'*/'], [u'c/', u'd/']],
122
 
            [[u'*\\'], [u'c/', u'd/']]])
 
131
            [[u'*\\'], [u'c/', u'd/']],
 
132
            ])
 
133
 
 
134
    def test_case_insensitive_globbing(self):
 
135
        self.requireFeature(tests.CaseInsCasePresFilenameFeature)
 
136
        self.build_ascii_tree()
 
137
        self._run_testset([
 
138
            [[u'A'], [u'A']],
 
139
            [[u'A?'], [u'a1', u'a2']],
 
140
            ])
123
141
 
124
142
    def test_tree_unicode(self):
125
143
        """Checks behaviour with non-ascii filenames"""
126
 
        self.build_tree([u'\u1234', u'\u1234\u1234', u'\u1235/', u'\u1235/\u1235'])
 
144
        self.build_unicode_tree()
127
145
        self._run_testset([
128
146
            # no wildcards
129
147
            [[u'\u1234'], [u'\u1234']],
139
157
 
140
158
            [[u'\u1235/?'], [u'\u1235/\u1235']],
141
159
            [[u'\u1235/*'], [u'\u1235/\u1235']],
 
160
            [[u'?/'], [u'\u1235/']],
 
161
            [[u'*/'], [u'\u1235/']],
 
162
            [[u'?/?'], [u'\u1235/\u1235']],
 
163
            [[u'*/*'], [u'\u1235/\u1235']],
 
164
            ])
 
165
 
 
166
    def test_unicode_backslashes(self):
 
167
        self.requireFeature(BackslashDirSeparatorFeature)
 
168
        self.build_unicode_tree()
 
169
        self._run_testset([
 
170
            # no wildcards
 
171
            [[u'\u1235\\'], [u'\u1235/']],
 
172
            [[u'\u1235\\\u1235'], [u'\u1235/\u1235']],
142
173
            [[u'\u1235\\?'], [u'\u1235/\u1235']],
143
174
            [[u'\u1235\\*'], [u'\u1235/\u1235']],
144
 
            [[u'?/'], [u'\u1235/']],
145
 
            [[u'*/'], [u'\u1235/']],
146
175
            [[u'?\\'], [u'\u1235/']],
147
176
            [[u'*\\'], [u'\u1235/']],
148
 
            [[u'?/?'], [u'\u1235/\u1235']],
149
 
            [[u'*/*'], [u'\u1235/\u1235']],
150
177
            [[u'?\\?'], [u'\u1235/\u1235']],
151
 
            [[u'*\\*'], [u'\u1235/\u1235']]])
 
178
            [[u'*\\*'], [u'\u1235/\u1235']],
 
179
            ])
152
180
 
153
181
    def _run_testset(self, testset):
154
182
        for pattern, expected in testset:
238
266
        super(TestLocationsPywin32, self).setUp()
239
267
        # We perform the exact same tests after disabling the use of ctypes.
240
268
        # This causes the implementation to fall back to pywin32.
241
 
        self.old_ctypes = win32utils.has_ctypes
242
 
        win32utils.has_ctypes = False
243
 
        self.addCleanup(self.restoreCtypes)
244
 
 
245
 
    def restoreCtypes(self):
246
 
        win32utils.has_ctypes = self.old_ctypes
 
269
        self.overrideAttr(win32utils, 'has_ctypes', False)
 
270
        # FIXME: this should be done by parametrization -- vila 100123
247
271
 
248
272
 
249
273
class TestSetHidden(TestCaseInTempDir):
261
285
        os.makedirs(u'\u1234\\.bzr')
262
286
        path = osutils.abspath(u'\u1234\\.bzr')
263
287
        win32utils.set_file_attr_hidden(path)
 
288
 
 
289
 
 
290
 
 
291
 
 
292
class Test_CommandLineToArgv(tests.TestCaseInTempDir):
 
293
 
 
294
    def assertCommandLine(self, expected, line, single_quotes_allowed=False):
 
295
        # Strictly speaking we should respect parameter order versus glob
 
296
        # expansions, but it's not really worth the effort here
 
297
        argv = win32utils._command_line_to_argv(line,
 
298
                single_quotes_allowed=single_quotes_allowed)
 
299
        self.assertEqual(expected, sorted(argv))
 
300
 
 
301
    def test_glob_paths(self):
 
302
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
303
        self.assertCommandLine([u'a/b.c', u'a/c.c'], 'a/*.c')
 
304
        self.build_tree(['b/', 'b/b.c', 'b/d.c', 'b/d.h'])
 
305
        self.assertCommandLine([u'a/b.c', u'b/b.c'], '*/b.c')
 
306
        self.assertCommandLine([u'a/b.c', u'a/c.c', u'b/b.c', u'b/d.c'],
 
307
                               '*/*.c')
 
308
        # Bash style, just pass through the argument if nothing matches
 
309
        self.assertCommandLine([u'*/*.qqq'], '*/*.qqq')
 
310
 
 
311
    def test_quoted_globs(self):
 
312
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
313
        self.assertCommandLine([u'a/*.c'], '"a/*.c"')
 
314
        self.assertCommandLine([u"'a/*.c'"], "'a/*.c'")
 
315
        self.assertCommandLine([u'a/*.c'], "'a/*.c'",
 
316
            single_quotes_allowed=True)
 
317
 
 
318
    def test_slashes_changed(self):
 
319
        # Quoting doesn't change the supplied args
 
320
        self.assertCommandLine([u'a\\*.c'], '"a\\*.c"')
 
321
        self.assertCommandLine([u'a\\*.c'], "'a\\*.c'",
 
322
            single_quotes_allowed=True)
 
323
        # Expands the glob, but nothing matches, swaps slashes
 
324
        self.assertCommandLine([u'a/*.c'], 'a\\*.c')
 
325
        self.assertCommandLine([u'a/?.c'], 'a\\?.c')
 
326
        # No glob, doesn't touch slashes
 
327
        self.assertCommandLine([u'a\\foo.c'], 'a\\foo.c')
 
328
 
 
329
    def test_single_quote_support(self):
 
330
        self.assertCommandLine(["add", "let's-do-it.txt"],
 
331
            "add let's-do-it.txt")
 
332
        self.assertCommandLine(["add", "lets do it.txt"],
 
333
            "add 'lets do it.txt'", single_quotes_allowed=True)
 
334
 
 
335
    def test_case_insensitive_globs(self):
 
336
        self.requireFeature(tests.CaseInsCasePresFilenameFeature)
 
337
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
338
        self.assertCommandLine([u'A/b.c'], 'A/B*')
 
339
 
 
340
    def test_backslashes(self):
 
341
        self.requireFeature(BackslashDirSeparatorFeature)
 
342
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
343
        self.assertCommandLine([u'a/b.c'], 'a\\b*')