~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_win32utils.py

  • Committer: Vincent Ladeuil
  • Date: 2010-02-10 15:46:03 UTC
  • mfrom: (4985.3.21 update)
  • mto: This revision was merged to the branch mainline in revision 5021.
  • Revision ID: v.ladeuil+lp@free.fr-20100210154603-k4no1gvfuqpzrw7p
Update performs two merges in a more logical order but stop on conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
18
import sys
19
19
 
20
 
from bzrlib import osutils
21
 
from bzrlib.tests import TestCase, TestCaseInTempDir, TestSkipped, Feature
 
20
from bzrlib import (
 
21
    osutils,
 
22
    tests,
 
23
    win32utils,
 
24
    )
 
25
from bzrlib.tests import (
 
26
    Feature,
 
27
    TestCase,
 
28
    TestCaseInTempDir,
 
29
    TestSkipped,
 
30
    UnicodeFilenameFeature,
 
31
    )
22
32
from bzrlib.win32utils import glob_expand, get_app_path
23
 
from bzrlib import win32utils
24
 
 
25
 
 
26
 
# Features
27
 
# --------
28
 
 
29
 
class _NeedsGlobExpansionFeature(Feature):
 
33
 
 
34
 
 
35
class _BackslashDirSeparatorFeature(tests.Feature):
30
36
 
31
37
    def _probe(self):
32
 
        return sys.platform == 'win32'
 
38
        try:
 
39
            os.lstat(os.getcwd() + '\\')
 
40
        except OSError:
 
41
            return False
 
42
        else:
 
43
            return True
33
44
 
34
45
    def feature_name(self):
35
 
        return 'Internally performed glob expansion'
 
46
        return "Filesystem treats '\\' as a directory separator."
36
47
 
37
 
NeedsGlobExpansionFeature = _NeedsGlobExpansionFeature()
 
48
BackslashDirSeparatorFeature = _BackslashDirSeparatorFeature()
38
49
 
39
50
 
40
51
class _RequiredModuleFeature(Feature):
61
72
# Tests
62
73
# -----
63
74
 
64
 
class TestNeedsGlobExpansionFeature(TestCase):
65
 
    
66
 
    def test_available(self):
67
 
        self.assertEqual(sys.platform == 'win32', 
68
 
                         NeedsGlobExpansionFeature.available())
69
 
        
70
 
    def test_str(self):
71
 
        self.assertTrue("performed" in str(NeedsGlobExpansionFeature))
72
 
 
73
 
 
74
75
class TestWin32UtilsGlobExpand(TestCaseInTempDir):
75
76
 
76
 
    _test_needs_features = [NeedsGlobExpansionFeature]
77
 
   
 
77
    _test_needs_features = []
 
78
 
78
79
    def test_empty_tree(self):
79
80
        self.build_tree([])
80
81
        self._run_testset([
82
83
            [['?'], ['?']],
83
84
            [['*'], ['*']],
84
85
            [['a', 'a'], ['a', 'a']]])
85
 
        
 
86
 
 
87
    def build_ascii_tree(self):
 
88
        self.build_tree(['a', 'a1', 'a2', 'a11', 'a.1',
 
89
                         'b', 'b1', 'b2', 'b3',
 
90
                         'c/', 'c/c1', 'c/c2',
 
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
 
86
98
    def test_tree_ascii(self):
87
99
        """Checks the glob expansion and path separation char
88
100
        normalization"""
89
 
        self.build_tree(['a', 'a1', 'a2', 'a11', 'a.1',
90
 
                         'b', 'b1', 'b2', 'b3',
91
 
                         'c/', 'c/c1', 'c/c2', 
92
 
                         'd/', 'd/d1', 'd/d2', 'd/e/', 'd/e/e1'])
 
101
        self.build_ascii_tree()
93
102
        self._run_testset([
94
103
            # no wildcards
95
104
            [[u'a'], [u'a']],
96
105
            [[u'a', u'a' ], [u'a', u'a']],
97
 
            [[u'A'], [u'A']],
98
 
                
 
106
 
99
107
            [[u'd'], [u'd']],
100
108
            [[u'd/'], [u'd/']],
101
 
            [[u'd\\'], [u'd/']],
102
 
            
 
109
 
103
110
            # wildcards
104
111
            [[u'a*'], [u'a', u'a1', u'a2', u'a11', u'a.1']],
105
112
            [[u'?'], [u'a', u'b', u'c', u'd']],
106
113
            [[u'a?'], [u'a1', u'a2']],
107
114
            [[u'a??'], [u'a11', u'a.1']],
108
115
            [[u'b[1-2]'], [u'b1', u'b2']],
109
 
            [[u'A?'], [u'a1', u'a2']],
110
 
               
 
116
 
111
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/']],
112
128
            [[u'd\\*'], [u'd/d1', u'd/d2', u'd/e']],
113
129
            [[u'?\\*'], [u'c/c1', u'c/c2', u'd/d1', u'd/d2', u'd/e']],
114
130
            [[u'*\\*'], [u'c/c1', u'c/c2', u'd/d1', u'd/d2', u'd/e']],
115
 
            [[u'*/'], [u'c/', u'd/']],
116
 
            [[u'*\\'], [u'c/', u'd/']]])
117
 
        
 
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
            ])
 
141
 
118
142
    def test_tree_unicode(self):
119
143
        """Checks behaviour with non-ascii filenames"""
120
 
        self.build_tree([u'\u1234', u'\u1234\u1234', u'\u1235/', u'\u1235/\u1235'])
 
144
        self.build_unicode_tree()
121
145
        self._run_testset([
122
146
            # no wildcards
123
147
            [[u'\u1234'], [u'\u1234']],
124
148
            [[u'\u1235'], [u'\u1235']],
125
 
         
 
149
 
126
150
            [[u'\u1235/'], [u'\u1235/']],
127
151
            [[u'\u1235/\u1235'], [u'\u1235/\u1235']],
128
 
            
 
152
 
129
153
            # wildcards
130
154
            [[u'?'], [u'\u1234', u'\u1235']],
131
155
            [[u'*'], [u'\u1234', u'\u1234\u1234', u'\u1235']],
132
156
            [[u'\u1234*'], [u'\u1234', u'\u1234\u1234']],
133
 
            
 
157
 
134
158
            [[u'\u1235/?'], [u'\u1235/\u1235']],
135
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']],
136
173
            [[u'\u1235\\?'], [u'\u1235/\u1235']],
137
174
            [[u'\u1235\\*'], [u'\u1235/\u1235']],
138
 
            [[u'?/'], [u'\u1235/']],
139
 
            [[u'*/'], [u'\u1235/']],
140
175
            [[u'?\\'], [u'\u1235/']],
141
176
            [[u'*\\'], [u'\u1235/']],
142
 
            [[u'?/?'], [u'\u1235/\u1235']],
143
 
            [[u'*/*'], [u'\u1235/\u1235']],
144
177
            [[u'?\\?'], [u'\u1235/\u1235']],
145
 
            [[u'*\\*'], [u'\u1235/\u1235']]])
 
178
            [[u'*\\*'], [u'\u1235/\u1235']],
 
179
            ])
146
180
 
147
181
    def _run_testset(self, testset):
148
182
        for pattern, expected in testset:
164
198
            self.assertEquals('iexplore.exe', b.lower())
165
199
            self.assertNotEquals('', d)
166
200
 
 
201
    def test_wordpad(self):
 
202
        # typical windows users should have wordpad in the system
 
203
        # but there is problem: its path has the format REG_EXPAND_SZ
 
204
        # so naive attempt to get the path is not working
 
205
        for a in ('wordpad', 'wordpad.exe'):
 
206
            p = get_app_path(a)
 
207
            d, b = os.path.split(p)
 
208
            self.assertEquals('wordpad.exe', b.lower())
 
209
            self.assertNotEquals('', d)
 
210
 
167
211
    def test_not_existing(self):
168
212
        p = get_app_path('not-existing')
169
213
        self.assertEquals('not-existing', p)
185
229
        first = win32utils.get_appdata_location()
186
230
        self._captureVar("APPDATA", None)
187
231
        self.assertPathsEqual(first, win32utils.get_appdata_location())
188
 
 
 
232
 
189
233
    def test_appdata_matches_environment(self):
190
234
        # Typically the APPDATA environment variable will match
191
235
        # get_appdata_location
222
266
        super(TestLocationsPywin32, self).setUp()
223
267
        # We perform the exact same tests after disabling the use of ctypes.
224
268
        # This causes the implementation to fall back to pywin32.
225
 
        self.old_ctypes = win32utils.has_ctypes
226
 
        win32utils.has_ctypes = False
227
 
        self.addCleanup(self.restoreCtypes)
228
 
 
229
 
    def restoreCtypes(self):
230
 
        win32utils.has_ctypes = self.old_ctypes
 
269
        self.overrideAttr(win32utils, 'has_ctypes', False)
 
270
        # FIXME: this should be done by parametrization -- vila 100123
 
271
 
 
272
 
 
273
class TestSetHidden(TestCaseInTempDir):
 
274
 
 
275
    def test_unicode_dir(self):
 
276
        # we should handle unicode paths without errors
 
277
        self.requireFeature(UnicodeFilenameFeature)
 
278
        os.mkdir(u'\u1234')
 
279
        win32utils.set_file_attr_hidden(u'\u1234')
 
280
 
 
281
    def test_dot_bzr_in_unicode_dir(self):
 
282
        # we should not raise traceback if we try to set hidden attribute
 
283
        # on .bzr directory below unicode path
 
284
        self.requireFeature(UnicodeFilenameFeature)
 
285
        os.makedirs(u'\u1234\\.bzr')
 
286
        path = osutils.abspath(u'\u1234\\.bzr')
 
287
        win32utils.set_file_attr_hidden(path)
 
288
 
 
289
 
 
290
 
 
291
class TestUnicodeShlex(tests.TestCase):
 
292
 
 
293
    def assertAsTokens(self, expected, line):
 
294
        s = win32utils.UnicodeShlex(line)
 
295
        self.assertEqual(expected, list(s))
 
296
 
 
297
    def test_simple(self):
 
298
        self.assertAsTokens([(False, u'foo'), (False, u'bar'), (False, u'baz')],
 
299
                            u'foo bar baz')
 
300
 
 
301
    def test_ignore_multiple_spaces(self):
 
302
        self.assertAsTokens([(False, u'foo'), (False, u'bar')], u'foo  bar')
 
303
 
 
304
    def test_ignore_leading_space(self):
 
305
        self.assertAsTokens([(False, u'foo'), (False, u'bar')], u'  foo bar')
 
306
 
 
307
    def test_ignore_trailing_space(self):
 
308
        self.assertAsTokens([(False, u'foo'), (False, u'bar')], u'foo bar  ')
 
309
 
 
310
    def test_posix_quotations(self):
 
311
        self.assertAsTokens([(True, u'foo bar')], u'"foo bar"')
 
312
        self.assertAsTokens([(False, u"'fo''o"), (False, u"b''ar'")],
 
313
            u"'fo''o b''ar'")
 
314
        self.assertAsTokens([(True, u'foo bar')], u'"fo""o b""ar"')
 
315
        self.assertAsTokens([(True, u"fo'o"), (True, u"b'ar")],
 
316
            u'"fo"\'o b\'"ar"')
 
317
 
 
318
    def test_nested_quotations(self):
 
319
        self.assertAsTokens([(True, u'foo"" bar')], u"\"foo\\\"\\\" bar\"")
 
320
        self.assertAsTokens([(True, u'foo\'\' bar')], u"\"foo'' bar\"")
 
321
 
 
322
    def test_empty_result(self):
 
323
        self.assertAsTokens([], u'')
 
324
        self.assertAsTokens([], u'    ')
 
325
 
 
326
    def test_quoted_empty(self):
 
327
        self.assertAsTokens([(True, '')], u'""')
 
328
        self.assertAsTokens([(False, u"''")], u"''")
 
329
 
 
330
    def test_unicode_chars(self):
 
331
        self.assertAsTokens([(False, u'f\xb5\xee'), (False, u'\u1234\u3456')],
 
332
                             u'f\xb5\xee \u1234\u3456')
 
333
 
 
334
    def test_newline_in_quoted_section(self):
 
335
        self.assertAsTokens([(True, u'foo\nbar\nbaz\n')], u'"foo\nbar\nbaz\n"')
 
336
 
 
337
    def test_escape_chars(self):
 
338
        self.assertAsTokens([(False, u'foo\\bar')], u'foo\\bar')
 
339
 
 
340
    def test_escape_quote(self):
 
341
        self.assertAsTokens([(True, u'foo"bar')], u'"foo\\"bar"')
 
342
 
 
343
    def test_double_escape(self):
 
344
        self.assertAsTokens([(True, u'foo\\bar')], u'"foo\\\\bar"')
 
345
        self.assertAsTokens([(False, u'foo\\\\bar')], u"foo\\\\bar")
 
346
 
 
347
 
 
348
class Test_CommandLineToArgv(tests.TestCaseInTempDir):
 
349
 
 
350
    def assertCommandLine(self, expected, line):
 
351
        # Strictly speaking we should respect parameter order versus glob
 
352
        # expansions, but it's not really worth the effort here
 
353
        self.assertEqual(expected,
 
354
                         sorted(win32utils._command_line_to_argv(line)))
 
355
 
 
356
    def test_glob_paths(self):
 
357
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
358
        self.assertCommandLine([u'a/b.c', u'a/c.c'], 'a/*.c')
 
359
        self.build_tree(['b/', 'b/b.c', 'b/d.c', 'b/d.h'])
 
360
        self.assertCommandLine([u'a/b.c', u'b/b.c'], '*/b.c')
 
361
        self.assertCommandLine([u'a/b.c', u'a/c.c', u'b/b.c', u'b/d.c'],
 
362
                               '*/*.c')
 
363
        # Bash style, just pass through the argument if nothing matches
 
364
        self.assertCommandLine([u'*/*.qqq'], '*/*.qqq')
 
365
 
 
366
    def test_quoted_globs(self):
 
367
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
368
        self.assertCommandLine([u'a/*.c'], '"a/*.c"')
 
369
        self.assertCommandLine([u"'a/*.c'"], "'a/*.c'")
 
370
 
 
371
    def test_slashes_changed(self):
 
372
        # Quoting doesn't change the supplied args
 
373
        self.assertCommandLine([u'a\\*.c'], '"a\\*.c"')
 
374
        # Expands the glob, but nothing matches, swaps slashes
 
375
        self.assertCommandLine([u'a/*.c'], 'a\\*.c')
 
376
        self.assertCommandLine([u'a/?.c'], 'a\\?.c')
 
377
        # No glob, doesn't touch slashes
 
378
        self.assertCommandLine([u'a\\foo.c'], 'a\\foo.c')
 
379
 
 
380
    def test_no_single_quote_supported(self):
 
381
        self.assertCommandLine(["add", "let's-do-it.txt"],
 
382
            "add let's-do-it.txt")
 
383
 
 
384
    def test_case_insensitive_globs(self):
 
385
        self.requireFeature(tests.CaseInsCasePresFilenameFeature)
 
386
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
387
        self.assertCommandLine([u'A/b.c'], 'A/B*')
 
388
 
 
389
    def test_backslashes(self):
 
390
        self.requireFeature(BackslashDirSeparatorFeature)
 
391
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
392
        self.assertCommandLine([u'a/b.c'], 'a\\b*')