~bzr-pqm/bzr/bzr.dev

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