/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_win32utils.py

  • Committer: John Arbash Meinel
  • Date: 2009-12-22 16:28:47 UTC
  • mto: This revision was merged to the branch mainline in revision 4922.
  • Revision ID: john@arbash-meinel.com-20091222162847-tvnsc69to4l4uf5r
Implement a permute_for_extension helper.

Use it for all of the 'simple' extension permutations.
It basically permutes all tests in the current module, by setting TestCase.module.
Which works well for most of our extension tests. Some had more advanced
handling of permutations (extra permutations, custom vars, etc.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
import os
 
18
import sys
 
19
 
 
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
    )
 
32
from bzrlib.win32utils import glob_expand, get_app_path
 
33
 
 
34
 
 
35
class _BackslashDirSeparatorFeature(tests.Feature):
 
36
 
 
37
    def _probe(self):
 
38
        try:
 
39
            os.lstat(os.getcwd() + '\\')
 
40
        except OSError:
 
41
            return False
 
42
        else:
 
43
            return True
 
44
 
 
45
    def feature_name(self):
 
46
        return "Filesystem treats '\\' as a directory separator."
 
47
 
 
48
BackslashDirSeparatorFeature = _BackslashDirSeparatorFeature()
 
49
 
 
50
 
 
51
class _RequiredModuleFeature(Feature):
 
52
 
 
53
    def __init__(self, mod_name):
 
54
        self.mod_name = mod_name
 
55
        super(_RequiredModuleFeature, self).__init__()
 
56
 
 
57
    def _probe(self):
 
58
        try:
 
59
            __import__(self.mod_name)
 
60
            return True
 
61
        except ImportError:
 
62
            return False
 
63
 
 
64
    def feature_name(self):
 
65
        return self.mod_name
 
66
 
 
67
Win32RegistryFeature = _RequiredModuleFeature('_winreg')
 
68
CtypesFeature = _RequiredModuleFeature('ctypes')
 
69
Win32comShellFeature = _RequiredModuleFeature('win32com.shell')
 
70
 
 
71
 
 
72
# Tests
 
73
# -----
 
74
 
 
75
class TestWin32UtilsGlobExpand(TestCaseInTempDir):
 
76
 
 
77
    _test_needs_features = []
 
78
 
 
79
    def test_empty_tree(self):
 
80
        self.build_tree([])
 
81
        self._run_testset([
 
82
            [['a'], ['a']],
 
83
            [['?'], ['?']],
 
84
            [['*'], ['*']],
 
85
            [['a', 'a'], ['a', 'a']]])
 
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
 
 
98
    def test_tree_ascii(self):
 
99
        """Checks the glob expansion and path separation char
 
100
        normalization"""
 
101
        self.build_ascii_tree()
 
102
        self._run_testset([
 
103
            # no wildcards
 
104
            [[u'a'], [u'a']],
 
105
            [[u'a', u'a' ], [u'a', u'a']],
 
106
 
 
107
            [[u'd'], [u'd']],
 
108
            [[u'd/'], [u'd/']],
 
109
 
 
110
            # wildcards
 
111
            [[u'a*'], [u'a', u'a1', u'a2', u'a11', u'a.1']],
 
112
            [[u'?'], [u'a', u'b', u'c', u'd']],
 
113
            [[u'a?'], [u'a1', u'a2']],
 
114
            [[u'a??'], [u'a11', u'a.1']],
 
115
            [[u'b[1-2]'], [u'b1', u'b2']],
 
116
 
 
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/']],
 
128
            [[u'd\\*'], [u'd/d1', u'd/d2', u'd/e']],
 
129
            [[u'?\\*'], [u'c/c1', u'c/c2', u'd/d1', u'd/d2', u'd/e']],
 
130
            [[u'*\\*'], [u'c/c1', u'c/c2', u'd/d1', u'd/d2', u'd/e']],
 
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
 
 
142
    def test_tree_unicode(self):
 
143
        """Checks behaviour with non-ascii filenames"""
 
144
        self.build_unicode_tree()
 
145
        self._run_testset([
 
146
            # no wildcards
 
147
            [[u'\u1234'], [u'\u1234']],
 
148
            [[u'\u1235'], [u'\u1235']],
 
149
 
 
150
            [[u'\u1235/'], [u'\u1235/']],
 
151
            [[u'\u1235/\u1235'], [u'\u1235/\u1235']],
 
152
 
 
153
            # wildcards
 
154
            [[u'?'], [u'\u1234', u'\u1235']],
 
155
            [[u'*'], [u'\u1234', u'\u1234\u1234', u'\u1235']],
 
156
            [[u'\u1234*'], [u'\u1234', u'\u1234\u1234']],
 
157
 
 
158
            [[u'\u1235/?'], [u'\u1235/\u1235']],
 
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']],
 
173
            [[u'\u1235\\?'], [u'\u1235/\u1235']],
 
174
            [[u'\u1235\\*'], [u'\u1235/\u1235']],
 
175
            [[u'?\\'], [u'\u1235/']],
 
176
            [[u'*\\'], [u'\u1235/']],
 
177
            [[u'?\\?'], [u'\u1235/\u1235']],
 
178
            [[u'*\\*'], [u'\u1235/\u1235']],
 
179
            ])
 
180
 
 
181
    def _run_testset(self, testset):
 
182
        for pattern, expected in testset:
 
183
            result = glob_expand(pattern)
 
184
            expected.sort()
 
185
            result.sort()
 
186
            self.assertEqual(expected, result, 'pattern %s' % pattern)
 
187
 
 
188
 
 
189
class TestAppPaths(TestCase):
 
190
 
 
191
    _test_needs_features = [Win32RegistryFeature]
 
192
 
 
193
    def test_iexplore(self):
 
194
        # typical windows users should have IE installed
 
195
        for a in ('iexplore', 'iexplore.exe'):
 
196
            p = get_app_path(a)
 
197
            d, b = os.path.split(p)
 
198
            self.assertEquals('iexplore.exe', b.lower())
 
199
            self.assertNotEquals('', d)
 
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
 
 
211
    def test_not_existing(self):
 
212
        p = get_app_path('not-existing')
 
213
        self.assertEquals('not-existing', p)
 
214
 
 
215
 
 
216
class TestLocationsCtypes(TestCase):
 
217
 
 
218
    _test_needs_features = [CtypesFeature]
 
219
 
 
220
    def assertPathsEqual(self, p1, p2):
 
221
        # TODO: The env var values in particular might return the "short"
 
222
        # version (ie, "C:\DOCUME~1\...").  Its even possible the returned
 
223
        # values will differ only by case - handle these situations as we
 
224
        # come across them.
 
225
        self.assertEquals(p1, p2)
 
226
 
 
227
    def test_appdata_not_using_environment(self):
 
228
        # Test that we aren't falling back to the environment
 
229
        first = win32utils.get_appdata_location()
 
230
        self._captureVar("APPDATA", None)
 
231
        self.assertPathsEqual(first, win32utils.get_appdata_location())
 
232
 
 
233
    def test_appdata_matches_environment(self):
 
234
        # Typically the APPDATA environment variable will match
 
235
        # get_appdata_location
 
236
        # XXX - See bug 262874, which asserts the correct encoding is 'mbcs',
 
237
        encoding = osutils.get_user_encoding()
 
238
        env_val = os.environ.get("APPDATA", None)
 
239
        if not env_val:
 
240
            raise TestSkipped("No APPDATA environment variable exists")
 
241
        self.assertPathsEqual(win32utils.get_appdata_location(),
 
242
                              env_val.decode(encoding))
 
243
 
 
244
    def test_local_appdata_not_using_environment(self):
 
245
        # Test that we aren't falling back to the environment
 
246
        first = win32utils.get_local_appdata_location()
 
247
        self._captureVar("LOCALAPPDATA", None)
 
248
        self.assertPathsEqual(first, win32utils.get_local_appdata_location())
 
249
 
 
250
    def test_local_appdata_matches_environment(self):
 
251
        # LOCALAPPDATA typically only exists on Vista, so we only attempt to
 
252
        # compare when it exists.
 
253
        lad = win32utils.get_local_appdata_location()
 
254
        env = os.environ.get("LOCALAPPDATA")
 
255
        if env:
 
256
            # XXX - See bug 262874, which asserts the correct encoding is 'mbcs'
 
257
            encoding = osutils.get_user_encoding()
 
258
            self.assertPathsEqual(lad, env.decode(encoding))
 
259
 
 
260
 
 
261
class TestLocationsPywin32(TestLocationsCtypes):
 
262
 
 
263
    _test_needs_features = [Win32comShellFeature]
 
264
 
 
265
    def setUp(self):
 
266
        super(TestLocationsPywin32, self).setUp()
 
267
        # We perform the exact same tests after disabling the use of ctypes.
 
268
        # This causes the implementation to fall back to pywin32.
 
269
        self.old_ctypes = win32utils.has_ctypes
 
270
        win32utils.has_ctypes = False
 
271
        self.addCleanup(self.restoreCtypes)
 
272
 
 
273
    def restoreCtypes(self):
 
274
        win32utils.has_ctypes = self.old_ctypes
 
275
 
 
276
 
 
277
class TestSetHidden(TestCaseInTempDir):
 
278
 
 
279
    def test_unicode_dir(self):
 
280
        # we should handle unicode paths without errors
 
281
        self.requireFeature(UnicodeFilenameFeature)
 
282
        os.mkdir(u'\u1234')
 
283
        win32utils.set_file_attr_hidden(u'\u1234')
 
284
 
 
285
    def test_dot_bzr_in_unicode_dir(self):
 
286
        # we should not raise traceback if we try to set hidden attribute
 
287
        # on .bzr directory below unicode path
 
288
        self.requireFeature(UnicodeFilenameFeature)
 
289
        os.makedirs(u'\u1234\\.bzr')
 
290
        path = osutils.abspath(u'\u1234\\.bzr')
 
291
        win32utils.set_file_attr_hidden(path)
 
292
 
 
293
 
 
294
 
 
295
class TestUnicodeShlex(tests.TestCase):
 
296
 
 
297
    def assertAsTokens(self, expected, line):
 
298
        s = win32utils.UnicodeShlex(line)
 
299
        self.assertEqual(expected, list(s))
 
300
 
 
301
    def test_simple(self):
 
302
        self.assertAsTokens([(False, u'foo'), (False, u'bar'), (False, u'baz')],
 
303
                            u'foo bar baz')
 
304
 
 
305
    def test_ignore_multiple_spaces(self):
 
306
        self.assertAsTokens([(False, u'foo'), (False, u'bar')], u'foo  bar')
 
307
 
 
308
    def test_ignore_leading_space(self):
 
309
        self.assertAsTokens([(False, u'foo'), (False, u'bar')], u'  foo bar')
 
310
 
 
311
    def test_ignore_trailing_space(self):
 
312
        self.assertAsTokens([(False, u'foo'), (False, u'bar')], u'foo bar  ')
 
313
 
 
314
    def test_posix_quotations(self):
 
315
        self.assertAsTokens([(True, u'foo bar')], u'"foo bar"')
 
316
        self.assertAsTokens([(False, u"'fo''o"), (False, u"b''ar'")],
 
317
            u"'fo''o b''ar'")
 
318
        self.assertAsTokens([(True, u'foo bar')], u'"fo""o b""ar"')
 
319
        self.assertAsTokens([(True, u"fo'o"), (True, u"b'ar")],
 
320
            u'"fo"\'o b\'"ar"')
 
321
 
 
322
    def test_nested_quotations(self):
 
323
        self.assertAsTokens([(True, u'foo"" bar')], u"\"foo\\\"\\\" bar\"")
 
324
        self.assertAsTokens([(True, u'foo\'\' bar')], u"\"foo'' bar\"")
 
325
 
 
326
    def test_empty_result(self):
 
327
        self.assertAsTokens([], u'')
 
328
        self.assertAsTokens([], u'    ')
 
329
 
 
330
    def test_quoted_empty(self):
 
331
        self.assertAsTokens([(True, '')], u'""')
 
332
        self.assertAsTokens([(False, u"''")], u"''")
 
333
 
 
334
    def test_unicode_chars(self):
 
335
        self.assertAsTokens([(False, u'f\xb5\xee'), (False, u'\u1234\u3456')],
 
336
                             u'f\xb5\xee \u1234\u3456')
 
337
 
 
338
    def test_newline_in_quoted_section(self):
 
339
        self.assertAsTokens([(True, u'foo\nbar\nbaz\n')], u'"foo\nbar\nbaz\n"')
 
340
 
 
341
    def test_escape_chars(self):
 
342
        self.assertAsTokens([(False, u'foo\\bar')], u'foo\\bar')
 
343
 
 
344
    def test_escape_quote(self):
 
345
        self.assertAsTokens([(True, u'foo"bar')], u'"foo\\"bar"')
 
346
 
 
347
    def test_double_escape(self):
 
348
        self.assertAsTokens([(True, u'foo\\bar')], u'"foo\\\\bar"')
 
349
        self.assertAsTokens([(False, u'foo\\\\bar')], u"foo\\\\bar")
 
350
 
 
351
 
 
352
class Test_CommandLineToArgv(tests.TestCaseInTempDir):
 
353
 
 
354
    def assertCommandLine(self, expected, line):
 
355
        # Strictly speaking we should respect parameter order versus glob
 
356
        # expansions, but it's not really worth the effort here
 
357
        self.assertEqual(expected,
 
358
                         sorted(win32utils._command_line_to_argv(line)))
 
359
 
 
360
    def test_glob_paths(self):
 
361
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
362
        self.assertCommandLine([u'a/b.c', u'a/c.c'], 'a/*.c')
 
363
        self.build_tree(['b/', 'b/b.c', 'b/d.c', 'b/d.h'])
 
364
        self.assertCommandLine([u'a/b.c', u'b/b.c'], '*/b.c')
 
365
        self.assertCommandLine([u'a/b.c', u'a/c.c', u'b/b.c', u'b/d.c'],
 
366
                               '*/*.c')
 
367
        # Bash style, just pass through the argument if nothing matches
 
368
        self.assertCommandLine([u'*/*.qqq'], '*/*.qqq')
 
369
 
 
370
    def test_quoted_globs(self):
 
371
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
372
        self.assertCommandLine([u'a/*.c'], '"a/*.c"')
 
373
        self.assertCommandLine([u"'a/*.c'"], "'a/*.c'")
 
374
 
 
375
    def test_slashes_changed(self):
 
376
        # Quoting doesn't change the supplied args
 
377
        self.assertCommandLine([u'a\\*.c'], '"a\\*.c"')
 
378
        # Expands the glob, but nothing matches, swaps slashes
 
379
        self.assertCommandLine([u'a/*.c'], 'a\\*.c')
 
380
        self.assertCommandLine([u'a/?.c'], 'a\\?.c')
 
381
        # No glob, doesn't touch slashes
 
382
        self.assertCommandLine([u'a\\foo.c'], 'a\\foo.c')
 
383
 
 
384
    def test_no_single_quote_supported(self):
 
385
        self.assertCommandLine(["add", "let's-do-it.txt"],
 
386
            "add let's-do-it.txt")
 
387
 
 
388
    def test_case_insensitive_globs(self):
 
389
        self.requireFeature(tests.CaseInsCasePresFilenameFeature)
 
390
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
391
        self.assertCommandLine([u'A/b.c'], 'A/B*')
 
392
 
 
393
    def test_backslashes(self):
 
394
        self.requireFeature(BackslashDirSeparatorFeature)
 
395
        self.build_tree(['a/', 'a/b.c', 'a/c.c', 'a/c.h'])
 
396
        self.assertCommandLine([u'a/b.c'], 'a\\b*')