/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
1
# Copyright (C) 2005 by 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
17
"""Tests for the osutils wrapper."""
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
18
1732.1.28 by John Arbash Meinel
Add tests for fancy file types.
19
import errno
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
20
import os
1732.1.28 by John Arbash Meinel
Add tests for fancy file types.
21
import socket
22
import stat
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
23
import sys
24
25
import bzrlib
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
26
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
1532 by Robert Collins
Merge in John Meinels integration branch.
27
import bzrlib.osutils as osutils
1711.4.10 by John Arbash Meinel
Pull out sys.stdout.encoding handling into a separate function so it can be tested, and used elsewhere.
28
from bzrlib.tests import (
29
        StringIOWrapper,
30
        TestCase, 
31
        TestCaseInTempDir, 
32
        TestSkipped,
33
        )
1532 by Robert Collins
Merge in John Meinels integration branch.
34
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
35
36
class TestOSUtils(TestCaseInTempDir):
37
38
    def test_fancy_rename(self):
39
        # This should work everywhere
40
        def rename(a, b):
41
            osutils.fancy_rename(a, b,
42
                    rename_func=os.rename,
43
                    unlink_func=os.unlink)
44
45
        open('a', 'wb').write('something in a\n')
46
        rename('a', 'b')
47
        self.failIfExists('a')
48
        self.failUnlessExists('b')
49
        self.check_file_contents('b', 'something in a\n')
50
51
        open('a', 'wb').write('new something in a\n')
52
        rename('b', 'a')
53
54
        self.check_file_contents('a', 'something in a\n')
55
56
    def test_rename(self):
57
        # Rename should be semi-atomic on all platforms
58
        open('a', 'wb').write('something in a\n')
59
        osutils.rename('a', 'b')
60
        self.failIfExists('a')
61
        self.failUnlessExists('b')
62
        self.check_file_contents('b', 'something in a\n')
63
64
        open('a', 'wb').write('new something in a\n')
65
        osutils.rename('b', 'a')
66
67
        self.check_file_contents('a', 'something in a\n')
68
69
    # TODO: test fancy_rename using a MemoryTransport
70
1553.5.5 by Martin Pool
New utility routine rand_chars
71
    def test_01_rand_chars_empty(self):
72
        result = osutils.rand_chars(0)
73
        self.assertEqual(result, '')
74
75
    def test_02_rand_chars_100(self):
76
        result = osutils.rand_chars(100)
77
        self.assertEqual(len(result), 100)
78
        self.assertEqual(type(result), str)
79
        self.assertContainsRe(result, r'^[a-z0-9]{100}$')
80
1534.3.1 by Robert Collins
* bzrlib.osutils.safe_unicode now exists to provide parameter coercion
81
1692.7.6 by Martin Pool
[patch] force deletion of trees containing readonly files (alexander)
82
    def test_rmtree(self):
83
        # Check to remove tree with read-only files/dirs
84
        os.mkdir('dir')
85
        f = file('dir/file', 'w')
86
        f.write('spam')
87
        f.close()
88
        # would like to also try making the directory readonly, but at the
89
        # moment python shutil.rmtree doesn't handle that properly - it would
90
        # need to chmod the directory before removing things inside it - deferred
91
        # for now -- mbp 20060505
92
        # osutils.make_readonly('dir')
93
        osutils.make_readonly('dir/file')
94
95
        osutils.rmtree('dir')
96
97
        self.failIfExists('dir/file')
98
        self.failIfExists('dir')
99
1732.1.10 by John Arbash Meinel
Updated version of file_kind. Rather than multiple function calls, one mask + dictionary lookup
100
    def test_file_kind(self):
101
        self.build_tree(['file', 'dir/'])
102
        self.assertEquals('file', osutils.file_kind('file'))
103
        self.assertEquals('directory', osutils.file_kind('dir/'))
104
        if osutils.has_symlinks():
105
            os.symlink('symlink', 'symlink')
106
            self.assertEquals('symlink', osutils.file_kind('symlink'))
1732.1.28 by John Arbash Meinel
Add tests for fancy file types.
107
        
108
        # TODO: jam 20060529 Test a block device
109
        try:
110
            os.lstat('/dev/null')
111
        except OSError, e:
112
            if e.errno not in (errno.ENOENT,):
113
                raise
114
        else:
115
            self.assertEquals('chardev', osutils.file_kind('/dev/null'))
116
117
        mkfifo = getattr(os, 'mkfifo', None)
118
        if mkfifo:
119
            mkfifo('fifo')
120
            try:
121
                self.assertEquals('fifo', osutils.file_kind('fifo'))
122
            finally:
123
                os.remove('fifo')
124
125
        AF_UNIX = getattr(socket, 'AF_UNIX', None)
126
        if AF_UNIX:
127
            s = socket.socket(AF_UNIX)
128
            s.bind('socket')
129
            try:
130
                self.assertEquals('socket', osutils.file_kind('socket'))
131
            finally:
132
                os.remove('socket')
1732.1.10 by John Arbash Meinel
Updated version of file_kind. Rather than multiple function calls, one mask + dictionary lookup
133
1755.3.7 by John Arbash Meinel
Clean up and write tests for permissions. Now we use fstat which should be cheap, and lets us check the permissions and the file size
134
    def test_get_umask(self):
135
        if sys.platform == 'win32':
136
            # umask always returns '0', no way to set it
137
            self.assertEqual(0, osutils.get_umask())
138
            return
139
140
        orig_umask = osutils.get_umask()
141
        try:
142
            os.umask(0222)
143
            self.assertEqual(0222, osutils.get_umask())
144
            os.umask(0022)
145
            self.assertEqual(0022, osutils.get_umask())
146
            os.umask(0002)
147
            self.assertEqual(0002, osutils.get_umask())
148
            os.umask(0027)
149
            self.assertEqual(0027, osutils.get_umask())
150
        finally:
151
            os.umask(orig_umask)
152
1957.1.15 by John Arbash Meinel
Review feedback from Robert
153
    def assertFormatedDelta(self, expected, seconds):
154
        """Assert osutils.format_delta formats as expected"""
155
        actual = osutils.format_delta(seconds)
156
        self.assertEqual(expected, actual)
157
1957.1.4 by John Arbash Meinel
create a helper for formatting a time delta
158
    def test_format_delta(self):
1957.1.15 by John Arbash Meinel
Review feedback from Robert
159
        self.assertFormatedDelta('0 seconds ago', 0)
160
        self.assertFormatedDelta('1 second ago', 1)
161
        self.assertFormatedDelta('10 seconds ago', 10)
162
        self.assertFormatedDelta('59 seconds ago', 59)
163
        self.assertFormatedDelta('89 seconds ago', 89)
164
        self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
165
        self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
166
        self.assertFormatedDelta('3 minutes, 1 second ago', 181)
167
        self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
168
        self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
169
        self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
170
        self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
171
        self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
172
        self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
173
        self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
174
        self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
175
        self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
176
        self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
177
        self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
178
        self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
179
        self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
180
        self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
181
        self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
1957.1.4 by John Arbash Meinel
create a helper for formatting a time delta
182
183
        # We handle when time steps the wrong direction because computers
184
        # don't have synchronized clocks.
1957.1.15 by John Arbash Meinel
Review feedback from Robert
185
        self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
186
        self.assertFormatedDelta('1 second in the future', -1)
187
        self.assertFormatedDelta('2 seconds in the future', -2)
1957.1.4 by John Arbash Meinel
create a helper for formatting a time delta
188
1692.7.6 by Martin Pool
[patch] force deletion of trees containing readonly files (alexander)
189
1534.3.1 by Robert Collins
* bzrlib.osutils.safe_unicode now exists to provide parameter coercion
190
class TestSafeUnicode(TestCase):
191
192
    def test_from_ascii_string(self):
193
        self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
194
1534.3.2 by Robert Collins
An extra test for John.
195
    def test_from_unicode_string_ascii_contents(self):
1534.3.1 by Robert Collins
* bzrlib.osutils.safe_unicode now exists to provide parameter coercion
196
        self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
197
1534.3.2 by Robert Collins
An extra test for John.
198
    def test_from_unicode_string_unicode_contents(self):
199
        self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
200
1534.3.1 by Robert Collins
* bzrlib.osutils.safe_unicode now exists to provide parameter coercion
201
    def test_from_utf8_string(self):
202
        self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
203
204
    def test_bad_utf8_string(self):
1185.65.29 by Robert Collins
Implement final review suggestions.
205
        self.assertRaises(BzrBadParameterNotUnicode,
206
                          osutils.safe_unicode,
207
                          '\xbb\xbb')
1666.1.6 by Robert Collins
Make knit the default format.
208
209
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
210
class TestWin32Funcs(TestCase):
211
    """Test that the _win32 versions of os utilities return appropriate paths."""
212
213
    def test_abspath(self):
214
        self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
215
        self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
216
217
    def test_realpath(self):
218
        self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
219
        self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
220
221
    def test_pathjoin(self):
222
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
223
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
224
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
225
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
226
        self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
227
        self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
228
229
    def test_normpath(self):
230
        self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
231
        self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
232
233
    def test_getcwd(self):
1711.5.2 by John Arbash Meinel
win32 likes to return lowercase drive letters sometimes, and uppercase at other times. normalize this
234
        cwd = osutils._win32_getcwd()
235
        os_cwd = os.getcwdu()
236
        self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
237
        # win32 is inconsistent whether it returns lower or upper case
238
        # and even if it was consistent the user might type the other
239
        # so we force it to uppercase
240
        # running python.exe under cmd.exe return capital C:\\
241
        # running win32 python inside a cygwin shell returns lowercase
242
        self.assertEqual(os_cwd[0].upper(), cwd[0])
243
244
    def test_fixdrive(self):
245
        self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
246
        self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
247
        self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
248
249
250
class TestWin32FuncsDirs(TestCaseInTempDir):
251
    """Test win32 functions that create files."""
252
    
253
    def test_getcwd(self):
254
        # Make sure getcwd can handle unicode filenames
255
        try:
1830.3.9 by John Arbash Meinel
Use a directory name that doesn't get messed up on Mac for getcwd() test.
256
            os.mkdir(u'mu-\xb5')
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
257
        except UnicodeError:
258
            raise TestSkipped("Unable to create Unicode filename")
259
1830.3.9 by John Arbash Meinel
Use a directory name that doesn't get messed up on Mac for getcwd() test.
260
        os.chdir(u'mu-\xb5')
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
261
        # TODO: jam 20060427 This will probably fail on Mac OSX because
262
        #       it will change the normalization of B\xe5gfors
263
        #       Consider using a different unicode character, or make
264
        #       osutils.getcwd() renormalize the path.
1830.3.9 by John Arbash Meinel
Use a directory name that doesn't get messed up on Mac for getcwd() test.
265
        self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
266
267
    def test_mkdtemp(self):
268
        tmpdir = osutils._win32_mkdtemp(dir='.')
269
        self.assertFalse('\\' in tmpdir)
270
271
    def test_rename(self):
272
        a = open('a', 'wb')
273
        a.write('foo\n')
274
        a.close()
275
        b = open('b', 'wb')
276
        b.write('baz\n')
277
        b.close()
278
279
        osutils._win32_rename('b', 'a')
280
        self.failUnlessExists('a')
281
        self.failIfExists('b')
282
        self.assertFileEqual('baz\n', 'a')
283
1711.7.6 by John Arbash Meinel
Change _win32_rename() so that it raises ENOENT *before* it tries any renaming.
284
    def test_rename_missing_file(self):
285
        a = open('a', 'wb')
286
        a.write('foo\n')
287
        a.close()
288
289
        try:
290
            osutils._win32_rename('b', 'a')
291
        except (IOError, OSError), e:
292
            self.assertEqual(errno.ENOENT, e.errno)
293
        self.assertFileEqual('foo\n', 'a')
294
295
    def test_rename_missing_dir(self):
296
        os.mkdir('a')
297
        try:
298
            osutils._win32_rename('b', 'a')
299
        except (IOError, OSError), e:
300
            self.assertEqual(errno.ENOENT, e.errno)
301
302
    def test_rename_current_dir(self):
303
        os.mkdir('a')
304
        os.chdir('a')
305
        # You can't rename the working directory
306
        # doing rename non-existant . usually
307
        # just raises ENOENT, since non-existant
308
        # doesn't exist.
309
        try:
310
            osutils._win32_rename('b', '.')
311
        except (IOError, OSError), e:
312
            self.assertEqual(errno.ENOENT, e.errno)
313
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
314
1830.3.11 by John Arbash Meinel
Create a mac version of 'getcwd()' which normalizes the path.
315
class TestMacFuncsDirs(TestCaseInTempDir):
316
    """Test mac special functions that require directories."""
317
318
    def test_getcwd(self):
319
        # On Mac, this will actually create Ba\u030agfors
320
        # but chdir will still work, because it accepts both paths
321
        try:
322
            os.mkdir(u'B\xe5gfors')
323
        except UnicodeError:
324
            raise TestSkipped("Unable to create Unicode filename")
325
326
        os.chdir(u'B\xe5gfors')
327
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
328
329
    def test_getcwd_nonnorm(self):
330
        # Test that _mac_getcwd() will normalize this path
331
        try:
332
            os.mkdir(u'Ba\u030agfors')
333
        except UnicodeError:
334
            raise TestSkipped("Unable to create Unicode filename")
335
336
        os.chdir(u'Ba\u030agfors')
337
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
338
1666.1.6 by Robert Collins
Make knit the default format.
339
class TestSplitLines(TestCase):
340
341
    def test_split_unicode(self):
342
        self.assertEqual([u'foo\n', u'bar\xae'],
343
                         osutils.split_lines(u'foo\nbar\xae'))
344
        self.assertEqual([u'foo\n', u'bar\xae\n'],
345
                         osutils.split_lines(u'foo\nbar\xae\n'))
346
347
    def test_split_with_carriage_returns(self):
348
        self.assertEqual(['foo\rbar\n'],
349
                         osutils.split_lines('foo\rbar\n'))
1753.1.1 by Robert Collins
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.
350
351
352
class TestWalkDirs(TestCaseInTempDir):
353
354
    def test_walkdirs(self):
355
        tree = [
356
            '.bzr',
357
            '0file',
358
            '1dir/',
359
            '1dir/0file',
360
            '1dir/1dir/',
361
            '2file'
362
            ]
363
        self.build_tree(tree)
364
        expected_dirblocks = [
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
365
                (('', '.'),
366
                 [('0file', '0file', 'file'),
367
                  ('1dir', '1dir', 'directory'),
368
                  ('2file', '2file', 'file'),
369
                 ]
370
                ),
371
                (('1dir', './1dir'),
372
                 [('1dir/0file', '0file', 'file'),
373
                  ('1dir/1dir', '1dir', 'directory'),
374
                 ]
375
                ),
376
                (('1dir/1dir', './1dir/1dir'),
377
                 [
378
                 ]
379
                ),
1753.1.1 by Robert Collins
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.
380
            ]
381
        result = []
382
        found_bzrdir = False
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
383
        for dirdetail, dirblock in osutils.walkdirs('.'):
1753.1.1 by Robert Collins
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.
384
            if len(dirblock) and dirblock[0][1] == '.bzr':
385
                # this tests the filtering of selected paths
386
                found_bzrdir = True
387
                del dirblock[0]
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
388
            result.append((dirdetail, dirblock))
1753.1.1 by Robert Collins
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.
389
390
        self.assertTrue(found_bzrdir)
391
        self.assertEqual(expected_dirblocks,
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
392
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
1757.2.8 by Robert Collins
Teach walkdirs to walk a subdir of a tree.
393
        # you can search a subdir only, with a supplied prefix.
394
        result = []
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
395
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
1757.2.8 by Robert Collins
Teach walkdirs to walk a subdir of a tree.
396
            result.append(dirblock)
397
        self.assertEqual(expected_dirblocks[1:],
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
398
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
1757.2.8 by Robert Collins
Teach walkdirs to walk a subdir of a tree.
399
1773.3.1 by Robert Collins
Add path_prefix_key and compare_paths_prefix_order utility functions.
400
    def assertPathCompare(self, path_less, path_greater):
401
        """check that path_less and path_greater compare correctly."""
402
        self.assertEqual(0, osutils.compare_paths_prefix_order(
403
            path_less, path_less))
404
        self.assertEqual(0, osutils.compare_paths_prefix_order(
405
            path_greater, path_greater))
406
        self.assertEqual(-1, osutils.compare_paths_prefix_order(
407
            path_less, path_greater))
408
        self.assertEqual(1, osutils.compare_paths_prefix_order(
409
            path_greater, path_less))
410
411
    def test_compare_paths_prefix_order(self):
412
        # root before all else
413
        self.assertPathCompare("/", "/a")
414
        # alpha within a dir
415
        self.assertPathCompare("/a", "/b")
416
        self.assertPathCompare("/b", "/z")
417
        # high dirs before lower.
418
        self.assertPathCompare("/z", "/a/a")
1773.3.2 by Robert Collins
New corner case from John Meinel, showing up the need to check the directory lexographically outside of a single tree's root. Fixed.
419
        # except if the deeper dir should be output first
420
        self.assertPathCompare("/a/b/c", "/d/g")
1773.3.1 by Robert Collins
Add path_prefix_key and compare_paths_prefix_order utility functions.
421
        # lexical betwen dirs of the same height
422
        self.assertPathCompare("/a/z", "/z/z")
423
        self.assertPathCompare("/a/c/z", "/a/d/e")
424
425
        # this should also be consistent for no leading / paths
426
        # root before all else
427
        self.assertPathCompare("", "a")
428
        # alpha within a dir
429
        self.assertPathCompare("a", "b")
430
        self.assertPathCompare("b", "z")
431
        # high dirs before lower.
432
        self.assertPathCompare("z", "a/a")
1773.3.2 by Robert Collins
New corner case from John Meinel, showing up the need to check the directory lexographically outside of a single tree's root. Fixed.
433
        # except if the deeper dir should be output first
434
        self.assertPathCompare("a/b/c", "d/g")
1773.3.1 by Robert Collins
Add path_prefix_key and compare_paths_prefix_order utility functions.
435
        # lexical betwen dirs of the same height
436
        self.assertPathCompare("a/z", "z/z")
437
        self.assertPathCompare("a/c/z", "a/d/e")
438
1773.3.3 by Robert Collins
Add new tests John Meinel asked for.
439
    def test_path_prefix_sorting(self):
440
        """Doing a sort on path prefix should match our sample data."""
441
        original_paths = [
442
            'a',
443
            'a/b',
444
            'a/b/c',
445
            'b',
446
            'b/c',
447
            'd',
448
            'd/e',
449
            'd/e/f',
450
            'd/f',
451
            'd/g',
452
            'g',
453
            ]
454
455
        dir_sorted_paths = [
456
            'a',
457
            'b',
458
            'd',
459
            'g',
460
            'a/b',
461
            'a/b/c',
462
            'b/c',
463
            'd/e',
464
            'd/f',
465
            'd/g',
466
            'd/e/f',
467
            ]
468
469
        self.assertEqual(
470
            dir_sorted_paths,
471
            sorted(original_paths, key=osutils.path_prefix_key))
472
        # using the comparison routine shoudl work too:
473
        self.assertEqual(
474
            dir_sorted_paths,
475
            sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
1711.4.10 by John Arbash Meinel
Pull out sys.stdout.encoding handling into a separate function so it can be tested, and used elsewhere.
476
477
1907.3.1 by John Arbash Meinel
create a copy_tree wrapper around walkdirs()
478
class TestCopyTree(TestCaseInTempDir):
479
    
480
    def test_copy_basic_tree(self):
481
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
482
        osutils.copy_tree('source', 'target')
483
        self.assertEqual(['a', 'b'], os.listdir('target'))
484
        self.assertEqual(['c'], os.listdir('target/b'))
485
486
    def test_copy_tree_target_exists(self):
487
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
488
                         'target/'])
489
        osutils.copy_tree('source', 'target')
490
        self.assertEqual(['a', 'b'], os.listdir('target'))
491
        self.assertEqual(['c'], os.listdir('target/b'))
492
1907.3.2 by John Arbash Meinel
Updated the copy_tree function to allow overriding functionality.
493
    def test_copy_tree_symlinks(self):
494
        if not osutils.has_symlinks():
495
            return
496
        self.build_tree(['source/'])
497
        os.symlink('a/generic/path', 'source/lnk')
498
        osutils.copy_tree('source', 'target')
499
        self.assertEqual(['lnk'], os.listdir('target'))
500
        self.assertEqual('a/generic/path', os.readlink('target/lnk'))
501
502
    def test_copy_tree_handlers(self):
503
        processed_files = []
504
        processed_links = []
505
        def file_handler(from_path, to_path):
506
            processed_files.append(('f', from_path, to_path))
507
        def dir_handler(from_path, to_path):
508
            processed_files.append(('d', from_path, to_path))
509
        def link_handler(from_path, to_path):
510
            processed_links.append((from_path, to_path))
511
        handlers = {'file':file_handler,
512
                    'directory':dir_handler,
513
                    'symlink':link_handler,
514
                   }
515
516
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
517
        if osutils.has_symlinks():
518
            os.symlink('a/generic/path', 'source/lnk')
519
        osutils.copy_tree('source', 'target', handlers=handlers)
520
521
        self.assertEqual([('d', 'source', 'target'),
522
                          ('f', 'source/a', 'target/a'),
523
                          ('d', 'source/b', 'target/b'),
524
                          ('f', 'source/b/c', 'target/b/c'),
525
                         ], processed_files)
526
        self.failIfExists('target')
527
        if osutils.has_symlinks():
528
            self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
529
1907.3.1 by John Arbash Meinel
create a copy_tree wrapper around walkdirs()
530
1711.4.10 by John Arbash Meinel
Pull out sys.stdout.encoding handling into a separate function so it can be tested, and used elsewhere.
531
class TestTerminalEncoding(TestCase):
532
    """Test the auto-detection of proper terminal encoding."""
533
534
    def setUp(self):
535
        self._stdout = sys.stdout
536
        self._stderr = sys.stderr
537
        self._stdin = sys.stdin
538
        self._user_encoding = bzrlib.user_encoding
539
540
        self.addCleanup(self._reset)
541
542
        sys.stdout = StringIOWrapper()
543
        sys.stdout.encoding = 'stdout_encoding'
544
        sys.stderr = StringIOWrapper()
545
        sys.stderr.encoding = 'stderr_encoding'
546
        sys.stdin = StringIOWrapper()
547
        sys.stdin.encoding = 'stdin_encoding'
548
        bzrlib.user_encoding = 'user_encoding'
549
550
    def _reset(self):
551
        sys.stdout = self._stdout
552
        sys.stderr = self._stderr
553
        sys.stdin = self._stdin
554
        bzrlib.user_encoding = self._user_encoding
555
556
    def test_get_terminal_encoding(self):
557
        # first preference is stdout encoding
558
        self.assertEqual('stdout_encoding', osutils.get_terminal_encoding())
559
560
        sys.stdout.encoding = None
561
        # if sys.stdout is None, fall back to sys.stdin
562
        self.assertEqual('stdin_encoding', osutils.get_terminal_encoding())
563
564
        sys.stdin.encoding = None
565
        # and in the worst case, use bzrlib.user_encoding
566
        self.assertEqual('user_encoding', osutils.get_terminal_encoding())
567
1963.1.5 by John Arbash Meinel
Create an osutils helper function for modifying the environment
568
569
class TestSetUnsetEnv(TestCase):
570
    """Test updating the environment"""
571
572
    def setUp(self):
573
        super(TestSetUnsetEnv, self).setUp()
574
575
        self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
576
                         'Environment was not cleaned up properly.'
577
                         ' Variable BZR_TEST_ENV_VAR should not exist.')
578
        def cleanup():
579
            if 'BZR_TEST_ENV_VAR' in os.environ:
580
                del os.environ['BZR_TEST_ENV_VAR']
581
582
        self.addCleanup(cleanup)
583
584
    def test_set(self):
585
        """Test that we can set an env variable"""
586
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
587
        self.assertEqual(None, old)
588
        self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
589
590
    def test_double_set(self):
591
        """Test that we get the old value out"""
592
        osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
593
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
594
        self.assertEqual('foo', old)
595
        self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
596
597
    def test_unicode(self):
598
        """Environment can only contain plain strings
599
        
600
        So Unicode strings must be encoded.
601
        """
602
        # Try a few different characters, to see if we can get
603
        # one that will be valid in the user_encoding
604
        possible_vals = [u'm\xb5', u'\xe1', u'\u0410']
605
        for uni_val in possible_vals:
606
            try:
607
                env_val = uni_val.encode(bzrlib.user_encoding)
608
            except UnicodeEncodeError:
609
                # Try a different character
610
                pass
611
            else:
612
                break
613
        else:
614
            raise TestSkipped('Cannot find a unicode character that works in'
615
                              ' encoding %s' % (bzrlib.user_encoding,))
616
617
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
618
        self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
619
620
    def test_unset(self):
621
        """Test that passing None will remove the env var"""
622
        osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
623
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
624
        self.assertEqual('foo', old)
625
        self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
626
        self.failIf('BZR_TEST_ENV_VAR' in os.environ)
627