1
# Copyright (C) 2005, 2006 Canonical Ltd
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.
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.
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
17
"""Tests for the osutils wrapper."""
31
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
32
from bzrlib.tests import (
40
class TestOSUtils(TestCaseInTempDir):
42
def test_contains_whitespace(self):
43
self.failUnless(osutils.contains_whitespace(u' '))
44
self.failUnless(osutils.contains_whitespace(u'hello there'))
45
self.failUnless(osutils.contains_whitespace(u'hellothere\n'))
46
self.failUnless(osutils.contains_whitespace(u'hello\nthere'))
47
self.failUnless(osutils.contains_whitespace(u'hello\rthere'))
48
self.failUnless(osutils.contains_whitespace(u'hello\tthere'))
50
# \xa0 is "Non-breaking-space" which on some python locales thinks it
51
# is whitespace, but we do not.
52
self.failIf(osutils.contains_whitespace(u''))
53
self.failIf(osutils.contains_whitespace(u'hellothere'))
54
self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
56
def test_fancy_rename(self):
57
# This should work everywhere
59
osutils.fancy_rename(a, b,
60
rename_func=os.rename,
61
unlink_func=os.unlink)
63
open('a', 'wb').write('something in a\n')
65
self.failIfExists('a')
66
self.failUnlessExists('b')
67
self.check_file_contents('b', 'something in a\n')
69
open('a', 'wb').write('new something in a\n')
72
self.check_file_contents('a', 'something in a\n')
74
def test_rename(self):
75
# Rename should be semi-atomic on all platforms
76
open('a', 'wb').write('something in a\n')
77
osutils.rename('a', 'b')
78
self.failIfExists('a')
79
self.failUnlessExists('b')
80
self.check_file_contents('b', 'something in a\n')
82
open('a', 'wb').write('new something in a\n')
83
osutils.rename('b', 'a')
85
self.check_file_contents('a', 'something in a\n')
87
# TODO: test fancy_rename using a MemoryTransport
89
def test_01_rand_chars_empty(self):
90
result = osutils.rand_chars(0)
91
self.assertEqual(result, '')
93
def test_02_rand_chars_100(self):
94
result = osutils.rand_chars(100)
95
self.assertEqual(len(result), 100)
96
self.assertEqual(type(result), str)
97
self.assertContainsRe(result, r'^[a-z0-9]{100}$')
99
def test_is_inside(self):
100
is_inside = osutils.is_inside
101
self.assertTrue(is_inside('src', 'src/foo.c'))
102
self.assertFalse(is_inside('src', 'srccontrol'))
103
self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
104
self.assertTrue(is_inside('foo.c', 'foo.c'))
105
self.assertFalse(is_inside('foo.c', ''))
106
self.assertTrue(is_inside('', 'foo.c'))
108
def test_rmtree(self):
109
# Check to remove tree with read-only files/dirs
111
f = file('dir/file', 'w')
114
# would like to also try making the directory readonly, but at the
115
# moment python shutil.rmtree doesn't handle that properly - it would
116
# need to chmod the directory before removing things inside it - deferred
117
# for now -- mbp 20060505
118
# osutils.make_readonly('dir')
119
osutils.make_readonly('dir/file')
121
osutils.rmtree('dir')
123
self.failIfExists('dir/file')
124
self.failIfExists('dir')
126
def test_file_kind(self):
127
self.build_tree(['file', 'dir/'])
128
self.assertEquals('file', osutils.file_kind('file'))
129
self.assertEquals('directory', osutils.file_kind('dir/'))
130
if osutils.has_symlinks():
131
os.symlink('symlink', 'symlink')
132
self.assertEquals('symlink', osutils.file_kind('symlink'))
134
# TODO: jam 20060529 Test a block device
136
os.lstat('/dev/null')
138
if e.errno not in (errno.ENOENT,):
141
self.assertEquals('chardev', osutils.file_kind('/dev/null'))
143
mkfifo = getattr(os, 'mkfifo', None)
147
self.assertEquals('fifo', osutils.file_kind('fifo'))
151
AF_UNIX = getattr(socket, 'AF_UNIX', None)
153
s = socket.socket(AF_UNIX)
156
self.assertEquals('socket', osutils.file_kind('socket'))
160
def test_get_umask(self):
161
if sys.platform == 'win32':
162
# umask always returns '0', no way to set it
163
self.assertEqual(0, osutils.get_umask())
166
orig_umask = osutils.get_umask()
169
self.assertEqual(0222, osutils.get_umask())
171
self.assertEqual(0022, osutils.get_umask())
173
self.assertEqual(0002, osutils.get_umask())
175
self.assertEqual(0027, osutils.get_umask())
179
def assertFormatedDelta(self, expected, seconds):
180
"""Assert osutils.format_delta formats as expected"""
181
actual = osutils.format_delta(seconds)
182
self.assertEqual(expected, actual)
184
def test_format_delta(self):
185
self.assertFormatedDelta('0 seconds ago', 0)
186
self.assertFormatedDelta('1 second ago', 1)
187
self.assertFormatedDelta('10 seconds ago', 10)
188
self.assertFormatedDelta('59 seconds ago', 59)
189
self.assertFormatedDelta('89 seconds ago', 89)
190
self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
191
self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
192
self.assertFormatedDelta('3 minutes, 1 second ago', 181)
193
self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
194
self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
195
self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
196
self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
197
self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
198
self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
199
self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
200
self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
201
self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
202
self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
203
self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
204
self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
205
self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
206
self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
207
self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
209
# We handle when time steps the wrong direction because computers
210
# don't have synchronized clocks.
211
self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
212
self.assertFormatedDelta('1 second in the future', -1)
213
self.assertFormatedDelta('2 seconds in the future', -2)
215
def test_dereference_path(self):
216
if not osutils.has_symlinks():
217
raise TestSkipped('Symlinks are not supported on this platform')
218
cwd = osutils.realpath('.')
220
bar_path = osutils.pathjoin(cwd, 'bar')
221
# Using './' to avoid bug #1213894 (first path component not
222
# dereferenced) in Python 2.4.1 and earlier
223
self.assertEqual(bar_path, osutils.realpath('./bar'))
224
os.symlink('bar', 'foo')
225
self.assertEqual(bar_path, osutils.realpath('./foo'))
227
# Does not dereference terminal symlinks
228
foo_path = osutils.pathjoin(cwd, 'foo')
229
self.assertEqual(foo_path, osutils.dereference_path('./foo'))
231
# Dereferences parent symlinks
233
baz_path = osutils.pathjoin(bar_path, 'baz')
234
self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
236
# Dereferences parent symlinks that are the first path element
237
self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
239
# Dereferences parent symlinks in absolute paths
240
foo_baz_path = osutils.pathjoin(foo_path, 'baz')
241
self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
244
class TestSafeUnicode(TestCase):
246
def test_from_ascii_string(self):
247
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
249
def test_from_unicode_string_ascii_contents(self):
250
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
252
def test_from_unicode_string_unicode_contents(self):
253
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
255
def test_from_utf8_string(self):
256
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
258
def test_bad_utf8_string(self):
259
self.assertRaises(BzrBadParameterNotUnicode,
260
osutils.safe_unicode,
264
class TestSafeUtf8(TestCase):
266
def test_from_ascii_string(self):
268
self.assertEqual('foobar', osutils.safe_utf8(f))
270
def test_from_unicode_string_ascii_contents(self):
271
self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
273
def test_from_unicode_string_unicode_contents(self):
274
self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
276
def test_from_utf8_string(self):
277
self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
279
def test_bad_utf8_string(self):
280
self.assertRaises(BzrBadParameterNotUnicode,
281
osutils.safe_utf8, '\xbb\xbb')
284
class TestSafeRevisionId(TestCase):
286
def test_from_ascii_string(self):
288
self.assertEqual('foobar', osutils.safe_revision_id(f))
289
self.assertIs(osutils.safe_utf8(f), f)
291
def test_from_unicode_string_ascii_contents(self):
292
self.assertEqual('bargam', osutils.safe_revision_id(u'bargam'))
294
def test_from_unicode_string_unicode_contents(self):
295
self.assertEqual('bargam\xc2\xae',
296
osutils.safe_revision_id(u'bargam\xae'))
298
def test_from_utf8_string(self):
299
self.assertEqual('foo\xc2\xae',
300
osutils.safe_revision_id('foo\xc2\xae'))
302
def test_bad_utf8_string(self):
303
# This check may eventually go away
304
self.assertRaises(BzrBadParameterNotUnicode,
305
osutils.safe_revision_id, '\xbb\xbb')
308
"""Currently, None is a valid revision_id"""
309
self.assertEqual(None, osutils.safe_revision_id(None))
312
class TestSafeFileId(TestCase):
314
def test_from_ascii_string(self):
316
self.assertEqual('foobar', osutils.safe_file_id(f))
318
def test_from_unicode_string_ascii_contents(self):
319
self.assertEqual('bargam', osutils.safe_file_id(u'bargam'))
321
def test_from_unicode_string_unicode_contents(self):
322
self.assertEqual('bargam\xc2\xae',
323
osutils.safe_file_id(u'bargam\xae'))
325
def test_from_utf8_string(self):
326
self.assertEqual('foo\xc2\xae',
327
osutils.safe_file_id('foo\xc2\xae'))
329
def test_bad_utf8_string(self):
330
# This check may eventually go away
331
self.assertRaises(BzrBadParameterNotUnicode,
332
osutils.safe_file_id, '\xbb\xbb')
335
"""Currently, None is a valid revision_id"""
336
self.assertEqual(None, osutils.safe_file_id(None))
339
class TestWin32Funcs(TestCase):
340
"""Test that the _win32 versions of os utilities return appropriate paths."""
342
def test_abspath(self):
343
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
344
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
345
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
346
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
348
def test_realpath(self):
349
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
350
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
352
def test_pathjoin(self):
353
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
354
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
355
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
356
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
357
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
358
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
360
def test_normpath(self):
361
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
362
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
364
def test_getcwd(self):
365
cwd = osutils._win32_getcwd()
366
os_cwd = os.getcwdu()
367
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
368
# win32 is inconsistent whether it returns lower or upper case
369
# and even if it was consistent the user might type the other
370
# so we force it to uppercase
371
# running python.exe under cmd.exe return capital C:\\
372
# running win32 python inside a cygwin shell returns lowercase
373
self.assertEqual(os_cwd[0].upper(), cwd[0])
375
def test_fixdrive(self):
376
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
377
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
378
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
380
def test_win98_abspath(self):
382
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
383
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
385
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
386
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
388
cwd = osutils.getcwd().rstrip('/')
389
drive = osutils._nt_splitdrive(cwd)[0]
390
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
391
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
394
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
397
class TestWin32FuncsDirs(TestCaseInTempDir):
398
"""Test win32 functions that create files."""
400
def test_getcwd(self):
401
if win32utils.winver == 'Windows 98':
402
raise TestSkipped('Windows 98 cannot handle unicode filenames')
403
# Make sure getcwd can handle unicode filenames
407
raise TestSkipped("Unable to create Unicode filename")
410
# TODO: jam 20060427 This will probably fail on Mac OSX because
411
# it will change the normalization of B\xe5gfors
412
# Consider using a different unicode character, or make
413
# osutils.getcwd() renormalize the path.
414
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
416
def test_mkdtemp(self):
417
tmpdir = osutils._win32_mkdtemp(dir='.')
418
self.assertFalse('\\' in tmpdir)
420
def test_rename(self):
428
osutils._win32_rename('b', 'a')
429
self.failUnlessExists('a')
430
self.failIfExists('b')
431
self.assertFileEqual('baz\n', 'a')
433
def test_rename_missing_file(self):
439
osutils._win32_rename('b', 'a')
440
except (IOError, OSError), e:
441
self.assertEqual(errno.ENOENT, e.errno)
442
self.assertFileEqual('foo\n', 'a')
444
def test_rename_missing_dir(self):
447
osutils._win32_rename('b', 'a')
448
except (IOError, OSError), e:
449
self.assertEqual(errno.ENOENT, e.errno)
451
def test_rename_current_dir(self):
454
# You can't rename the working directory
455
# doing rename non-existant . usually
456
# just raises ENOENT, since non-existant
459
osutils._win32_rename('b', '.')
460
except (IOError, OSError), e:
461
self.assertEqual(errno.ENOENT, e.errno)
463
def test_splitpath(self):
464
def check(expected, path):
465
self.assertEqual(expected, osutils.splitpath(path))
468
check(['a', 'b'], 'a/b')
469
check(['a', 'b'], 'a/./b')
470
check(['a', '.b'], 'a/.b')
471
check(['a', '.b'], 'a\\.b')
473
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
476
class TestMacFuncsDirs(TestCaseInTempDir):
477
"""Test mac special functions that require directories."""
479
def test_getcwd(self):
480
# On Mac, this will actually create Ba\u030agfors
481
# but chdir will still work, because it accepts both paths
483
os.mkdir(u'B\xe5gfors')
485
raise TestSkipped("Unable to create Unicode filename")
487
os.chdir(u'B\xe5gfors')
488
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
490
def test_getcwd_nonnorm(self):
491
# Test that _mac_getcwd() will normalize this path
493
os.mkdir(u'Ba\u030agfors')
495
raise TestSkipped("Unable to create Unicode filename")
497
os.chdir(u'Ba\u030agfors')
498
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
501
class TestSplitLines(TestCase):
503
def test_split_unicode(self):
504
self.assertEqual([u'foo\n', u'bar\xae'],
505
osutils.split_lines(u'foo\nbar\xae'))
506
self.assertEqual([u'foo\n', u'bar\xae\n'],
507
osutils.split_lines(u'foo\nbar\xae\n'))
509
def test_split_with_carriage_returns(self):
510
self.assertEqual(['foo\rbar\n'],
511
osutils.split_lines('foo\rbar\n'))
514
class TestWalkDirs(TestCaseInTempDir):
516
def test_walkdirs(self):
525
self.build_tree(tree)
526
expected_dirblocks = [
528
[('0file', '0file', 'file'),
529
('1dir', '1dir', 'directory'),
530
('2file', '2file', 'file'),
534
[('1dir/0file', '0file', 'file'),
535
('1dir/1dir', '1dir', 'directory'),
538
(('1dir/1dir', './1dir/1dir'),
545
for dirdetail, dirblock in osutils.walkdirs('.'):
546
if len(dirblock) and dirblock[0][1] == '.bzr':
547
# this tests the filtering of selected paths
550
result.append((dirdetail, dirblock))
552
self.assertTrue(found_bzrdir)
553
self.assertEqual(expected_dirblocks,
554
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
555
# you can search a subdir only, with a supplied prefix.
557
for dirblock in osutils.walkdirs('./1dir', '1dir'):
558
result.append(dirblock)
559
self.assertEqual(expected_dirblocks[1:],
560
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
562
def test__walkdirs_utf8(self):
571
self.build_tree(tree)
572
expected_dirblocks = [
574
[('0file', '0file', 'file'),
575
('1dir', '1dir', 'directory'),
576
('2file', '2file', 'file'),
580
[('1dir/0file', '0file', 'file'),
581
('1dir/1dir', '1dir', 'directory'),
584
(('1dir/1dir', './1dir/1dir'),
591
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
592
if len(dirblock) and dirblock[0][1] == '.bzr':
593
# this tests the filtering of selected paths
596
result.append((dirdetail, dirblock))
598
self.assertTrue(found_bzrdir)
599
self.assertEqual(expected_dirblocks,
600
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
601
# you can search a subdir only, with a supplied prefix.
603
for dirblock in osutils.walkdirs('./1dir', '1dir'):
604
result.append(dirblock)
605
self.assertEqual(expected_dirblocks[1:],
606
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
608
def _filter_out_stat(self, result):
609
"""Filter out the stat value from the walkdirs result"""
610
for dirdetail, dirblock in result:
612
for info in dirblock:
613
# Ignore info[3] which is the stat
614
new_dirblock.append((info[0], info[1], info[2], info[4]))
615
dirblock[:] = new_dirblock
617
def test_unicode_walkdirs(self):
618
"""Walkdirs should always return unicode paths."""
619
name0 = u'0file-\xb6'
620
name1 = u'1dir-\u062c\u0648'
621
name2 = u'2file-\u0633'
626
name1 + '/' + name1 + '/',
630
self.build_tree(tree)
632
raise TestSkipped('Could not represent Unicode chars'
633
' in current encoding.')
634
expected_dirblocks = [
636
[(name0, name0, 'file', './' + name0),
637
(name1, name1, 'directory', './' + name1),
638
(name2, name2, 'file', './' + name2),
641
((name1, './' + name1),
642
[(name1 + '/' + name0, name0, 'file', './' + name1
644
(name1 + '/' + name1, name1, 'directory', './' + name1
648
((name1 + '/' + name1, './' + name1 + '/' + name1),
653
result = list(osutils.walkdirs('.'))
654
self._filter_out_stat(result)
655
self.assertEqual(expected_dirblocks, result)
656
result = list(osutils.walkdirs(u'./'+name1, name1))
657
self._filter_out_stat(result)
658
self.assertEqual(expected_dirblocks[1:], result)
660
def test_unicode__walkdirs_utf8(self):
661
"""Walkdirs_utf8 should always return utf8 paths.
663
The abspath portion might be in unicode or utf-8
665
name0 = u'0file-\xb6'
666
name1 = u'1dir-\u062c\u0648'
667
name2 = u'2file-\u0633'
672
name1 + '/' + name1 + '/',
676
self.build_tree(tree)
678
raise TestSkipped('Could not represent Unicode chars'
679
' in current encoding.')
680
name0 = name0.encode('utf8')
681
name1 = name1.encode('utf8')
682
name2 = name2.encode('utf8')
684
expected_dirblocks = [
686
[(name0, name0, 'file', './' + name0),
687
(name1, name1, 'directory', './' + name1),
688
(name2, name2, 'file', './' + name2),
691
((name1, './' + name1),
692
[(name1 + '/' + name0, name0, 'file', './' + name1
694
(name1 + '/' + name1, name1, 'directory', './' + name1
698
((name1 + '/' + name1, './' + name1 + '/' + name1),
704
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
705
# all abspaths are Unicode, and encode them back into utf8.
706
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
707
self.assertIsInstance(dirdetail[0], str)
708
if isinstance(dirdetail[1], unicode):
709
dirdetail[1] = dirdetail[1].encode('utf8')
710
for info in dirblock:
711
self.assertIsInstance(info[4], unicode)
712
info[4] = info[4].encode('utf8')
714
for info in dirblock:
715
self.assertIsInstance(info[0], str)
716
self.assertIsInstance(info[1], str)
717
self.assertIsInstance(info[4], str)
718
# Remove the stat information
719
new_dirblock.append((info[0], info[1], info[2], info[4]))
720
result.append((dirdetail, new_dirblock))
721
self.assertEqual(expected_dirblocks, result)
723
def test_unicode__walkdirs_unicode_to_utf8(self):
724
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
726
The abspath portion should be in unicode
728
name0u = u'0file-\xb6'
729
name1u = u'1dir-\u062c\u0648'
730
name2u = u'2file-\u0633'
734
name1u + '/' + name0u,
735
name1u + '/' + name1u + '/',
739
self.build_tree(tree)
741
raise TestSkipped('Could not represent Unicode chars'
742
' in current encoding.')
743
name0 = name0u.encode('utf8')
744
name1 = name1u.encode('utf8')
745
name2 = name2u.encode('utf8')
747
# All of the abspaths should be in unicode, all of the relative paths
749
expected_dirblocks = [
751
[(name0, name0, 'file', './' + name0u),
752
(name1, name1, 'directory', './' + name1u),
753
(name2, name2, 'file', './' + name2u),
756
((name1, './' + name1u),
757
[(name1 + '/' + name0, name0, 'file', './' + name1u
759
(name1 + '/' + name1, name1, 'directory', './' + name1u
763
((name1 + '/' + name1, './' + name1u + '/' + name1u),
768
result = list(osutils._walkdirs_unicode_to_utf8('.'))
769
self._filter_out_stat(result)
770
self.assertEqual(expected_dirblocks, result)
772
def assertPathCompare(self, path_less, path_greater):
773
"""check that path_less and path_greater compare correctly."""
774
self.assertEqual(0, osutils.compare_paths_prefix_order(
775
path_less, path_less))
776
self.assertEqual(0, osutils.compare_paths_prefix_order(
777
path_greater, path_greater))
778
self.assertEqual(-1, osutils.compare_paths_prefix_order(
779
path_less, path_greater))
780
self.assertEqual(1, osutils.compare_paths_prefix_order(
781
path_greater, path_less))
783
def test_compare_paths_prefix_order(self):
784
# root before all else
785
self.assertPathCompare("/", "/a")
787
self.assertPathCompare("/a", "/b")
788
self.assertPathCompare("/b", "/z")
789
# high dirs before lower.
790
self.assertPathCompare("/z", "/a/a")
791
# except if the deeper dir should be output first
792
self.assertPathCompare("/a/b/c", "/d/g")
793
# lexical betwen dirs of the same height
794
self.assertPathCompare("/a/z", "/z/z")
795
self.assertPathCompare("/a/c/z", "/a/d/e")
797
# this should also be consistent for no leading / paths
798
# root before all else
799
self.assertPathCompare("", "a")
801
self.assertPathCompare("a", "b")
802
self.assertPathCompare("b", "z")
803
# high dirs before lower.
804
self.assertPathCompare("z", "a/a")
805
# except if the deeper dir should be output first
806
self.assertPathCompare("a/b/c", "d/g")
807
# lexical betwen dirs of the same height
808
self.assertPathCompare("a/z", "z/z")
809
self.assertPathCompare("a/c/z", "a/d/e")
811
def test_path_prefix_sorting(self):
812
"""Doing a sort on path prefix should match our sample data."""
843
sorted(original_paths, key=osutils.path_prefix_key))
844
# using the comparison routine shoudl work too:
847
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
850
class TestCopyTree(TestCaseInTempDir):
852
def test_copy_basic_tree(self):
853
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
854
osutils.copy_tree('source', 'target')
855
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
856
self.assertEqual(['c'], os.listdir('target/b'))
858
def test_copy_tree_target_exists(self):
859
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
861
osutils.copy_tree('source', 'target')
862
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
863
self.assertEqual(['c'], os.listdir('target/b'))
865
def test_copy_tree_symlinks(self):
866
if not osutils.has_symlinks():
868
self.build_tree(['source/'])
869
os.symlink('a/generic/path', 'source/lnk')
870
osutils.copy_tree('source', 'target')
871
self.assertEqual(['lnk'], os.listdir('target'))
872
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
874
def test_copy_tree_handlers(self):
877
def file_handler(from_path, to_path):
878
processed_files.append(('f', from_path, to_path))
879
def dir_handler(from_path, to_path):
880
processed_files.append(('d', from_path, to_path))
881
def link_handler(from_path, to_path):
882
processed_links.append((from_path, to_path))
883
handlers = {'file':file_handler,
884
'directory':dir_handler,
885
'symlink':link_handler,
888
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
889
if osutils.has_symlinks():
890
os.symlink('a/generic/path', 'source/lnk')
891
osutils.copy_tree('source', 'target', handlers=handlers)
893
self.assertEqual([('d', 'source', 'target'),
894
('f', 'source/a', 'target/a'),
895
('d', 'source/b', 'target/b'),
896
('f', 'source/b/c', 'target/b/c'),
898
self.failIfExists('target')
899
if osutils.has_symlinks():
900
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
903
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
904
# [bialix] 2006/12/26
907
class TestSetUnsetEnv(TestCase):
908
"""Test updating the environment"""
911
super(TestSetUnsetEnv, self).setUp()
913
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
914
'Environment was not cleaned up properly.'
915
' Variable BZR_TEST_ENV_VAR should not exist.')
917
if 'BZR_TEST_ENV_VAR' in os.environ:
918
del os.environ['BZR_TEST_ENV_VAR']
920
self.addCleanup(cleanup)
923
"""Test that we can set an env variable"""
924
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
925
self.assertEqual(None, old)
926
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
928
def test_double_set(self):
929
"""Test that we get the old value out"""
930
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
931
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
932
self.assertEqual('foo', old)
933
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
935
def test_unicode(self):
936
"""Environment can only contain plain strings
938
So Unicode strings must be encoded.
940
# Try a few different characters, to see if we can get
941
# one that will be valid in the user_encoding
942
possible_vals = [u'm\xb5', u'\xe1', u'\u0410']
943
for uni_val in possible_vals:
945
env_val = uni_val.encode(bzrlib.user_encoding)
946
except UnicodeEncodeError:
947
# Try a different character
952
raise TestSkipped('Cannot find a unicode character that works in'
953
' encoding %s' % (bzrlib.user_encoding,))
955
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
956
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
958
def test_unset(self):
959
"""Test that passing None will remove the env var"""
960
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
961
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
962
self.assertEqual('foo', old)
963
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
964
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
967
class TestLocalTimeOffset(TestCase):
969
def test_local_time_offset(self):
970
"""Test that local_time_offset() returns a sane value."""
971
offset = osutils.local_time_offset()
972
self.assertTrue(isinstance(offset, int))
973
# Test that the offset is no more than a eighteen hours in
975
# Time zone handling is system specific, so it is difficult to
976
# do more specific tests, but a value outside of this range is
978
eighteen_hours = 18 * 3600
979
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
981
def test_local_time_offset_with_timestamp(self):
982
"""Test that local_time_offset() works with a timestamp."""
983
offset = osutils.local_time_offset(1000000000.1234567)
984
self.assertTrue(isinstance(offset, int))
985
eighteen_hours = 18 * 3600
986
self.assertTrue(-eighteen_hours < offset < eighteen_hours)