/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: 2007-02-09 18:11:44 UTC
  • mto: This revision was merged to the branch mainline in revision 2294.
  • Revision ID: john@arbash-meinel.com-20070209181144-3cxnt3e4jre3e317
Update WorkingTree to use safe_revision_id when appropriate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 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
    def assertFormatedDelta(self, expected, seconds):
 
165
        """Assert osutils.format_delta formats as expected"""
 
166
        actual = osutils.format_delta(seconds)
 
167
        self.assertEqual(expected, actual)
 
168
 
 
169
    def test_format_delta(self):
 
170
        self.assertFormatedDelta('0 seconds ago', 0)
 
171
        self.assertFormatedDelta('1 second ago', 1)
 
172
        self.assertFormatedDelta('10 seconds ago', 10)
 
173
        self.assertFormatedDelta('59 seconds ago', 59)
 
174
        self.assertFormatedDelta('89 seconds ago', 89)
 
175
        self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
 
176
        self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
 
177
        self.assertFormatedDelta('3 minutes, 1 second ago', 181)
 
178
        self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
 
179
        self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
 
180
        self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
 
181
        self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
 
182
        self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
 
183
        self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
 
184
        self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
 
185
        self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
 
186
        self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
 
187
        self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
 
188
        self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
 
189
        self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
 
190
        self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
 
191
        self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
 
192
        self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
 
193
 
 
194
        # We handle when time steps the wrong direction because computers
 
195
        # don't have synchronized clocks.
 
196
        self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
 
197
        self.assertFormatedDelta('1 second in the future', -1)
 
198
        self.assertFormatedDelta('2 seconds in the future', -2)
 
199
 
 
200
    def test_dereference_path(self):
 
201
        if not osutils.has_symlinks():
 
202
            raise TestSkipped('Symlinks are not supported on this platform')
 
203
        cwd = osutils.realpath('.')
 
204
        os.mkdir('bar')
 
205
        bar_path = osutils.pathjoin(cwd, 'bar')
 
206
        # Using './' to avoid bug #1213894 (first path component not
 
207
        # dereferenced) in Python 2.4.1 and earlier
 
208
        self.assertEqual(bar_path, osutils.realpath('./bar'))
 
209
        os.symlink('bar', 'foo')
 
210
        self.assertEqual(bar_path, osutils.realpath('./foo'))
 
211
        
 
212
        # Does not dereference terminal symlinks
 
213
        foo_path = osutils.pathjoin(cwd, 'foo')
 
214
        self.assertEqual(foo_path, osutils.dereference_path('./foo'))
 
215
 
 
216
        # Dereferences parent symlinks
 
217
        os.mkdir('bar/baz')
 
218
        baz_path = osutils.pathjoin(bar_path, 'baz')
 
219
        self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
 
220
 
 
221
        # Dereferences parent symlinks that are the first path element
 
222
        self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
 
223
 
 
224
        # Dereferences parent symlinks in absolute paths
 
225
        foo_baz_path = osutils.pathjoin(foo_path, 'baz')
 
226
        self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
 
227
 
 
228
 
 
229
class TestSafeUnicode(TestCase):
 
230
 
 
231
    def test_from_ascii_string(self):
 
232
        self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
 
233
 
 
234
    def test_from_unicode_string_ascii_contents(self):
 
235
        self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
 
236
 
 
237
    def test_from_unicode_string_unicode_contents(self):
 
238
        self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
 
239
 
 
240
    def test_from_utf8_string(self):
 
241
        self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
 
242
 
 
243
    def test_bad_utf8_string(self):
 
244
        self.assertRaises(BzrBadParameterNotUnicode,
 
245
                          osutils.safe_unicode,
 
246
                          '\xbb\xbb')
 
247
 
 
248
 
 
249
class TestSafeUtf8(TestCase):
 
250
 
 
251
    def test_from_ascii_string(self):
 
252
        f = 'foobar'
 
253
        self.assertEqual('foobar', osutils.safe_utf8(f))
 
254
 
 
255
    def test_from_unicode_string_ascii_contents(self):
 
256
        self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
 
257
 
 
258
    def test_from_unicode_string_unicode_contents(self):
 
259
        self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
 
260
 
 
261
    def test_from_utf8_string(self):
 
262
        self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
 
263
 
 
264
    def test_bad_utf8_string(self):
 
265
        self.assertRaises(BzrBadParameterNotUnicode,
 
266
                          osutils.safe_utf8, '\xbb\xbb')
 
267
 
 
268
 
 
269
class TestSafeRevisionId(TestCase):
 
270
 
 
271
    def test_from_ascii_string(self):
 
272
        f = 'foobar'
 
273
        self.assertEqual('foobar', osutils.safe_revision_id(f))
 
274
        self.assertIs(osutils.safe_utf8(f), f)
 
275
 
 
276
    def test_from_unicode_string_ascii_contents(self):
 
277
        self.assertEqual('bargam', osutils.safe_revision_id(u'bargam'))
 
278
 
 
279
    def test_from_unicode_string_unicode_contents(self):
 
280
        self.assertEqual('bargam\xc2\xae',
 
281
                         osutils.safe_revision_id(u'bargam\xae'))
 
282
 
 
283
    def test_from_utf8_string(self):
 
284
        self.assertEqual('foo\xc2\xae',
 
285
                         osutils.safe_revision_id('foo\xc2\xae'))
 
286
 
 
287
    def test_bad_utf8_string(self):
 
288
        # This check may eventually go away
 
289
        self.assertRaises(BzrBadParameterNotUnicode,
 
290
                          osutils.safe_utf8, '\xbb\xbb')
 
291
 
 
292
    def test_none(self):
 
293
        """Currently, None is a valid revision_id"""
 
294
        self.assertEqual(None, osutils.safe_revision_id(None))
 
295
 
 
296
 
 
297
class TestWin32Funcs(TestCase):
 
298
    """Test that the _win32 versions of os utilities return appropriate paths."""
 
299
 
 
300
    def test_abspath(self):
 
301
        self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
 
302
        self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
 
303
 
 
304
    def test_realpath(self):
 
305
        self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
 
306
        self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
 
307
 
 
308
    def test_pathjoin(self):
 
309
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
 
310
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
 
311
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
 
312
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
 
313
        self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
 
314
        self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
 
315
 
 
316
    def test_normpath(self):
 
317
        self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
 
318
        self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
 
319
 
 
320
    def test_getcwd(self):
 
321
        cwd = osutils._win32_getcwd()
 
322
        os_cwd = os.getcwdu()
 
323
        self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
 
324
        # win32 is inconsistent whether it returns lower or upper case
 
325
        # and even if it was consistent the user might type the other
 
326
        # so we force it to uppercase
 
327
        # running python.exe under cmd.exe return capital C:\\
 
328
        # running win32 python inside a cygwin shell returns lowercase
 
329
        self.assertEqual(os_cwd[0].upper(), cwd[0])
 
330
 
 
331
    def test_fixdrive(self):
 
332
        self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
 
333
        self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
 
334
        self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
 
335
 
 
336
 
 
337
class TestWin32FuncsDirs(TestCaseInTempDir):
 
338
    """Test win32 functions that create files."""
 
339
    
 
340
    def test_getcwd(self):
 
341
        # Make sure getcwd can handle unicode filenames
 
342
        try:
 
343
            os.mkdir(u'mu-\xb5')
 
344
        except UnicodeError:
 
345
            raise TestSkipped("Unable to create Unicode filename")
 
346
 
 
347
        os.chdir(u'mu-\xb5')
 
348
        # TODO: jam 20060427 This will probably fail on Mac OSX because
 
349
        #       it will change the normalization of B\xe5gfors
 
350
        #       Consider using a different unicode character, or make
 
351
        #       osutils.getcwd() renormalize the path.
 
352
        self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
 
353
 
 
354
    def test_mkdtemp(self):
 
355
        tmpdir = osutils._win32_mkdtemp(dir='.')
 
356
        self.assertFalse('\\' in tmpdir)
 
357
 
 
358
    def test_rename(self):
 
359
        a = open('a', 'wb')
 
360
        a.write('foo\n')
 
361
        a.close()
 
362
        b = open('b', 'wb')
 
363
        b.write('baz\n')
 
364
        b.close()
 
365
 
 
366
        osutils._win32_rename('b', 'a')
 
367
        self.failUnlessExists('a')
 
368
        self.failIfExists('b')
 
369
        self.assertFileEqual('baz\n', 'a')
 
370
 
 
371
    def test_rename_missing_file(self):
 
372
        a = open('a', 'wb')
 
373
        a.write('foo\n')
 
374
        a.close()
 
375
 
 
376
        try:
 
377
            osutils._win32_rename('b', 'a')
 
378
        except (IOError, OSError), e:
 
379
            self.assertEqual(errno.ENOENT, e.errno)
 
380
        self.assertFileEqual('foo\n', 'a')
 
381
 
 
382
    def test_rename_missing_dir(self):
 
383
        os.mkdir('a')
 
384
        try:
 
385
            osutils._win32_rename('b', 'a')
 
386
        except (IOError, OSError), e:
 
387
            self.assertEqual(errno.ENOENT, e.errno)
 
388
 
 
389
    def test_rename_current_dir(self):
 
390
        os.mkdir('a')
 
391
        os.chdir('a')
 
392
        # You can't rename the working directory
 
393
        # doing rename non-existant . usually
 
394
        # just raises ENOENT, since non-existant
 
395
        # doesn't exist.
 
396
        try:
 
397
            osutils._win32_rename('b', '.')
 
398
        except (IOError, OSError), e:
 
399
            self.assertEqual(errno.ENOENT, e.errno)
 
400
 
 
401
    def test_splitpath(self):
 
402
        def check(expected, path):
 
403
            self.assertEqual(expected, osutils.splitpath(path))
 
404
 
 
405
        check(['a'], 'a')
 
406
        check(['a', 'b'], 'a/b')
 
407
        check(['a', 'b'], 'a/./b')
 
408
        check(['a', '.b'], 'a/.b')
 
409
        check(['a', '.b'], 'a\\.b')
 
410
 
 
411
        self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
 
412
 
 
413
 
 
414
class TestMacFuncsDirs(TestCaseInTempDir):
 
415
    """Test mac special functions that require directories."""
 
416
 
 
417
    def test_getcwd(self):
 
418
        # On Mac, this will actually create Ba\u030agfors
 
419
        # but chdir will still work, because it accepts both paths
 
420
        try:
 
421
            os.mkdir(u'B\xe5gfors')
 
422
        except UnicodeError:
 
423
            raise TestSkipped("Unable to create Unicode filename")
 
424
 
 
425
        os.chdir(u'B\xe5gfors')
 
426
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
 
427
 
 
428
    def test_getcwd_nonnorm(self):
 
429
        # Test that _mac_getcwd() will normalize this path
 
430
        try:
 
431
            os.mkdir(u'Ba\u030agfors')
 
432
        except UnicodeError:
 
433
            raise TestSkipped("Unable to create Unicode filename")
 
434
 
 
435
        os.chdir(u'Ba\u030agfors')
 
436
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
 
437
 
 
438
 
 
439
class TestSplitLines(TestCase):
 
440
 
 
441
    def test_split_unicode(self):
 
442
        self.assertEqual([u'foo\n', u'bar\xae'],
 
443
                         osutils.split_lines(u'foo\nbar\xae'))
 
444
        self.assertEqual([u'foo\n', u'bar\xae\n'],
 
445
                         osutils.split_lines(u'foo\nbar\xae\n'))
 
446
 
 
447
    def test_split_with_carriage_returns(self):
 
448
        self.assertEqual(['foo\rbar\n'],
 
449
                         osutils.split_lines('foo\rbar\n'))
 
450
 
 
451
 
 
452
class TestWalkDirs(TestCaseInTempDir):
 
453
 
 
454
    def test_walkdirs(self):
 
455
        tree = [
 
456
            '.bzr',
 
457
            '0file',
 
458
            '1dir/',
 
459
            '1dir/0file',
 
460
            '1dir/1dir/',
 
461
            '2file'
 
462
            ]
 
463
        self.build_tree(tree)
 
464
        expected_dirblocks = [
 
465
                (('', '.'),
 
466
                 [('0file', '0file', 'file'),
 
467
                  ('1dir', '1dir', 'directory'),
 
468
                  ('2file', '2file', 'file'),
 
469
                 ]
 
470
                ),
 
471
                (('1dir', './1dir'),
 
472
                 [('1dir/0file', '0file', 'file'),
 
473
                  ('1dir/1dir', '1dir', 'directory'),
 
474
                 ]
 
475
                ),
 
476
                (('1dir/1dir', './1dir/1dir'),
 
477
                 [
 
478
                 ]
 
479
                ),
 
480
            ]
 
481
        result = []
 
482
        found_bzrdir = False
 
483
        for dirdetail, dirblock in osutils.walkdirs('.'):
 
484
            if len(dirblock) and dirblock[0][1] == '.bzr':
 
485
                # this tests the filtering of selected paths
 
486
                found_bzrdir = True
 
487
                del dirblock[0]
 
488
            result.append((dirdetail, dirblock))
 
489
 
 
490
        self.assertTrue(found_bzrdir)
 
491
        self.assertEqual(expected_dirblocks,
 
492
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
493
        # you can search a subdir only, with a supplied prefix.
 
494
        result = []
 
495
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
 
496
            result.append(dirblock)
 
497
        self.assertEqual(expected_dirblocks[1:],
 
498
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
499
 
 
500
    def assertPathCompare(self, path_less, path_greater):
 
501
        """check that path_less and path_greater compare correctly."""
 
502
        self.assertEqual(0, osutils.compare_paths_prefix_order(
 
503
            path_less, path_less))
 
504
        self.assertEqual(0, osutils.compare_paths_prefix_order(
 
505
            path_greater, path_greater))
 
506
        self.assertEqual(-1, osutils.compare_paths_prefix_order(
 
507
            path_less, path_greater))
 
508
        self.assertEqual(1, osutils.compare_paths_prefix_order(
 
509
            path_greater, path_less))
 
510
 
 
511
    def test_compare_paths_prefix_order(self):
 
512
        # root before all else
 
513
        self.assertPathCompare("/", "/a")
 
514
        # alpha within a dir
 
515
        self.assertPathCompare("/a", "/b")
 
516
        self.assertPathCompare("/b", "/z")
 
517
        # high dirs before lower.
 
518
        self.assertPathCompare("/z", "/a/a")
 
519
        # except if the deeper dir should be output first
 
520
        self.assertPathCompare("/a/b/c", "/d/g")
 
521
        # lexical betwen dirs of the same height
 
522
        self.assertPathCompare("/a/z", "/z/z")
 
523
        self.assertPathCompare("/a/c/z", "/a/d/e")
 
524
 
 
525
        # this should also be consistent for no leading / paths
 
526
        # root before all else
 
527
        self.assertPathCompare("", "a")
 
528
        # alpha within a dir
 
529
        self.assertPathCompare("a", "b")
 
530
        self.assertPathCompare("b", "z")
 
531
        # high dirs before lower.
 
532
        self.assertPathCompare("z", "a/a")
 
533
        # except if the deeper dir should be output first
 
534
        self.assertPathCompare("a/b/c", "d/g")
 
535
        # lexical betwen dirs of the same height
 
536
        self.assertPathCompare("a/z", "z/z")
 
537
        self.assertPathCompare("a/c/z", "a/d/e")
 
538
 
 
539
    def test_path_prefix_sorting(self):
 
540
        """Doing a sort on path prefix should match our sample data."""
 
541
        original_paths = [
 
542
            'a',
 
543
            'a/b',
 
544
            'a/b/c',
 
545
            'b',
 
546
            'b/c',
 
547
            'd',
 
548
            'd/e',
 
549
            'd/e/f',
 
550
            'd/f',
 
551
            'd/g',
 
552
            'g',
 
553
            ]
 
554
 
 
555
        dir_sorted_paths = [
 
556
            'a',
 
557
            'b',
 
558
            'd',
 
559
            'g',
 
560
            'a/b',
 
561
            'a/b/c',
 
562
            'b/c',
 
563
            'd/e',
 
564
            'd/f',
 
565
            'd/g',
 
566
            'd/e/f',
 
567
            ]
 
568
 
 
569
        self.assertEqual(
 
570
            dir_sorted_paths,
 
571
            sorted(original_paths, key=osutils.path_prefix_key))
 
572
        # using the comparison routine shoudl work too:
 
573
        self.assertEqual(
 
574
            dir_sorted_paths,
 
575
            sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
 
576
 
 
577
 
 
578
class TestCopyTree(TestCaseInTempDir):
 
579
    
 
580
    def test_copy_basic_tree(self):
 
581
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
 
582
        osutils.copy_tree('source', 'target')
 
583
        self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
 
584
        self.assertEqual(['c'], os.listdir('target/b'))
 
585
 
 
586
    def test_copy_tree_target_exists(self):
 
587
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
 
588
                         'target/'])
 
589
        osutils.copy_tree('source', 'target')
 
590
        self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
 
591
        self.assertEqual(['c'], os.listdir('target/b'))
 
592
 
 
593
    def test_copy_tree_symlinks(self):
 
594
        if not osutils.has_symlinks():
 
595
            return
 
596
        self.build_tree(['source/'])
 
597
        os.symlink('a/generic/path', 'source/lnk')
 
598
        osutils.copy_tree('source', 'target')
 
599
        self.assertEqual(['lnk'], os.listdir('target'))
 
600
        self.assertEqual('a/generic/path', os.readlink('target/lnk'))
 
601
 
 
602
    def test_copy_tree_handlers(self):
 
603
        processed_files = []
 
604
        processed_links = []
 
605
        def file_handler(from_path, to_path):
 
606
            processed_files.append(('f', from_path, to_path))
 
607
        def dir_handler(from_path, to_path):
 
608
            processed_files.append(('d', from_path, to_path))
 
609
        def link_handler(from_path, to_path):
 
610
            processed_links.append((from_path, to_path))
 
611
        handlers = {'file':file_handler,
 
612
                    'directory':dir_handler,
 
613
                    'symlink':link_handler,
 
614
                   }
 
615
 
 
616
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
 
617
        if osutils.has_symlinks():
 
618
            os.symlink('a/generic/path', 'source/lnk')
 
619
        osutils.copy_tree('source', 'target', handlers=handlers)
 
620
 
 
621
        self.assertEqual([('d', 'source', 'target'),
 
622
                          ('f', 'source/a', 'target/a'),
 
623
                          ('d', 'source/b', 'target/b'),
 
624
                          ('f', 'source/b/c', 'target/b/c'),
 
625
                         ], processed_files)
 
626
        self.failIfExists('target')
 
627
        if osutils.has_symlinks():
 
628
            self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
 
629
 
 
630
 
 
631
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
 
632
# [bialix] 2006/12/26
 
633
 
 
634
 
 
635
class TestSetUnsetEnv(TestCase):
 
636
    """Test updating the environment"""
 
637
 
 
638
    def setUp(self):
 
639
        super(TestSetUnsetEnv, self).setUp()
 
640
 
 
641
        self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
 
642
                         'Environment was not cleaned up properly.'
 
643
                         ' Variable BZR_TEST_ENV_VAR should not exist.')
 
644
        def cleanup():
 
645
            if 'BZR_TEST_ENV_VAR' in os.environ:
 
646
                del os.environ['BZR_TEST_ENV_VAR']
 
647
 
 
648
        self.addCleanup(cleanup)
 
649
 
 
650
    def test_set(self):
 
651
        """Test that we can set an env variable"""
 
652
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
 
653
        self.assertEqual(None, old)
 
654
        self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
 
655
 
 
656
    def test_double_set(self):
 
657
        """Test that we get the old value out"""
 
658
        osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
 
659
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
 
660
        self.assertEqual('foo', old)
 
661
        self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
 
662
 
 
663
    def test_unicode(self):
 
664
        """Environment can only contain plain strings
 
665
        
 
666
        So Unicode strings must be encoded.
 
667
        """
 
668
        # Try a few different characters, to see if we can get
 
669
        # one that will be valid in the user_encoding
 
670
        possible_vals = [u'm\xb5', u'\xe1', u'\u0410']
 
671
        for uni_val in possible_vals:
 
672
            try:
 
673
                env_val = uni_val.encode(bzrlib.user_encoding)
 
674
            except UnicodeEncodeError:
 
675
                # Try a different character
 
676
                pass
 
677
            else:
 
678
                break
 
679
        else:
 
680
            raise TestSkipped('Cannot find a unicode character that works in'
 
681
                              ' encoding %s' % (bzrlib.user_encoding,))
 
682
 
 
683
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
 
684
        self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
 
685
 
 
686
    def test_unset(self):
 
687
        """Test that passing None will remove the env var"""
 
688
        osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
 
689
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
 
690
        self.assertEqual('foo', old)
 
691
        self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
 
692
        self.failIf('BZR_TEST_ENV_VAR' in os.environ)
 
693
 
 
694
 
 
695
class TestLocalTimeOffset(TestCase):
 
696
 
 
697
    def test_local_time_offset(self):
 
698
        """Test that local_time_offset() returns a sane value."""
 
699
        offset = osutils.local_time_offset()
 
700
        self.assertTrue(isinstance(offset, int))
 
701
        # Test that the offset is no more than a eighteen hours in
 
702
        # either direction.
 
703
        # Time zone handling is system specific, so it is difficult to
 
704
        # do more specific tests, but a value outside of this range is
 
705
        # probably wrong.
 
706
        eighteen_hours = 18 * 3600
 
707
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
708
 
 
709
    def test_local_time_offset_with_timestamp(self):
 
710
        """Test that local_time_offset() works with a timestamp."""
 
711
        offset = osutils.local_time_offset(1000000000.1234567)
 
712
        self.assertTrue(isinstance(offset, int))
 
713
        eighteen_hours = 18 * 3600
 
714
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)