~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_win32utils.py

  • Committer: John Arbash Meinel
  • Date: 2010-02-17 17:11:16 UTC
  • mfrom: (4797.2.17 2.1)
  • mto: (4797.2.18 2.1)
  • mto: This revision was merged to the branch mainline in revision 5055.
  • Revision ID: john@arbash-meinel.com-20100217171116-h7t9223ystbnx5h8
merge bzr.2.1 in preparation for NEWS entry.

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:
261
289
        os.makedirs(u'\u1234\\.bzr')
262
290
        path = osutils.abspath(u'\u1234\\.bzr')
263
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*')