/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_osutils.py

  • Committer: John Arbash Meinel
  • Date: 2006-09-13 03:21:03 UTC
  • mto: This revision was merged to the branch mainline in revision 2071.
  • Revision ID: john@arbash-meinel.com-20060913032103-c2ad6ab606f96839
lazy_import plugin and transport/local

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
17
"""Tests for the osutils wrapper."""
 
18
 
 
19
import errno
 
20
import os
 
21
import socket
 
22
import stat
 
23
import sys
 
24
 
 
25
import bzrlib
 
26
from bzrlib import (
 
27
    errors,
 
28
    osutils,
 
29
    )
 
30
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
 
31
from bzrlib.tests import (
 
32
        StringIOWrapper,
 
33
        TestCase, 
 
34
        TestCaseInTempDir, 
 
35
        TestSkipped,
 
36
        )
 
37
 
 
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
 
 
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
 
 
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'))
 
92
 
 
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
 
 
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'))
 
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')
 
144
 
 
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
 
 
164
 
 
165
class TestSafeUnicode(TestCase):
 
166
 
 
167
    def test_from_ascii_string(self):
 
168
        self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
 
169
 
 
170
    def test_from_unicode_string_ascii_contents(self):
 
171
        self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
 
172
 
 
173
    def test_from_unicode_string_unicode_contents(self):
 
174
        self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
 
175
 
 
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):
 
180
        self.assertRaises(BzrBadParameterNotUnicode,
 
181
                          osutils.safe_unicode,
 
182
                          '\xbb\xbb')
 
183
 
 
184
 
 
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):
 
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'))
 
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:
 
231
            os.mkdir(u'mu-\xb5')
 
232
        except UnicodeError:
 
233
            raise TestSkipped("Unable to create Unicode filename")
 
234
 
 
235
        os.chdir(u'mu-\xb5')
 
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.
 
240
        self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
 
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
 
 
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
 
 
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
 
 
301
 
 
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
 
 
326
 
 
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'))
 
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 = [
 
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
                ),
 
368
            ]
 
369
        result = []
 
370
        found_bzrdir = False
 
371
        for dirdetail, dirblock in osutils.walkdirs('.'):
 
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]
 
376
            result.append((dirdetail, dirblock))
 
377
 
 
378
        self.assertTrue(found_bzrdir)
 
379
        self.assertEqual(expected_dirblocks,
 
380
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
381
        # you can search a subdir only, with a supplied prefix.
 
382
        result = []
 
383
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
 
384
            result.append(dirblock)
 
385
        self.assertEqual(expected_dirblocks[1:],
 
386
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
387
 
 
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")
 
407
        # except if the deeper dir should be output first
 
408
        self.assertPathCompare("/a/b/c", "/d/g")
 
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")
 
421
        # except if the deeper dir should be output first
 
422
        self.assertPathCompare("a/b/c", "d/g")
 
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
 
 
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))
 
464
 
 
465
 
 
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
 
 
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
 
 
518
 
 
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
 
 
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