1
# Copyright (C) 2005, 2006, 2007 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.osutils import (
34
is_inside_or_parent_of_any,
37
from bzrlib.tests import (
38
probe_unicode_in_user_encoding,
47
class TestOSUtils(TestCaseInTempDir):
49
def test_contains_whitespace(self):
50
self.failUnless(osutils.contains_whitespace(u' '))
51
self.failUnless(osutils.contains_whitespace(u'hello there'))
52
self.failUnless(osutils.contains_whitespace(u'hellothere\n'))
53
self.failUnless(osutils.contains_whitespace(u'hello\nthere'))
54
self.failUnless(osutils.contains_whitespace(u'hello\rthere'))
55
self.failUnless(osutils.contains_whitespace(u'hello\tthere'))
57
# \xa0 is "Non-breaking-space" which on some python locales thinks it
58
# is whitespace, but we do not.
59
self.failIf(osutils.contains_whitespace(u''))
60
self.failIf(osutils.contains_whitespace(u'hellothere'))
61
self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
63
def test_fancy_rename(self):
64
# This should work everywhere
66
osutils.fancy_rename(a, b,
67
rename_func=os.rename,
68
unlink_func=os.unlink)
70
open('a', 'wb').write('something in a\n')
72
self.failIfExists('a')
73
self.failUnlessExists('b')
74
self.check_file_contents('b', 'something in a\n')
76
open('a', 'wb').write('new something in a\n')
79
self.check_file_contents('a', 'something in a\n')
81
def test_rename(self):
82
# Rename should be semi-atomic on all platforms
83
open('a', 'wb').write('something in a\n')
84
osutils.rename('a', 'b')
85
self.failIfExists('a')
86
self.failUnlessExists('b')
87
self.check_file_contents('b', 'something in a\n')
89
open('a', 'wb').write('new something in a\n')
90
osutils.rename('b', 'a')
92
self.check_file_contents('a', 'something in a\n')
94
# TODO: test fancy_rename using a MemoryTransport
96
def test_rename_change_case(self):
97
# on Windows we should be able to change filename case by rename
98
self.build_tree(['a', 'b/'])
99
osutils.rename('a', 'A')
100
osutils.rename('b', 'B')
101
# we can't use failUnlessExists on case-insensitive filesystem
102
# so try to check shape of the tree
103
shape = sorted(os.listdir('.'))
104
self.assertEquals(['A', 'B'], shape)
106
def test_01_rand_chars_empty(self):
107
result = osutils.rand_chars(0)
108
self.assertEqual(result, '')
110
def test_02_rand_chars_100(self):
111
result = osutils.rand_chars(100)
112
self.assertEqual(len(result), 100)
113
self.assertEqual(type(result), str)
114
self.assertContainsRe(result, r'^[a-z0-9]{100}$')
116
def test_is_inside(self):
117
is_inside = osutils.is_inside
118
self.assertTrue(is_inside('src', 'src/foo.c'))
119
self.assertFalse(is_inside('src', 'srccontrol'))
120
self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
121
self.assertTrue(is_inside('foo.c', 'foo.c'))
122
self.assertFalse(is_inside('foo.c', ''))
123
self.assertTrue(is_inside('', 'foo.c'))
125
def test_is_inside_any(self):
126
SRC_FOO_C = pathjoin('src', 'foo.c')
127
for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
128
(['src'], SRC_FOO_C),
131
self.assert_(is_inside_any(dirs, fn))
132
for dirs, fn in [(['src'], 'srccontrol'),
133
(['src'], 'srccontrol/foo')]:
134
self.assertFalse(is_inside_any(dirs, fn))
136
def test_is_inside_or_parent_of_any(self):
137
for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
138
(['src'], 'src/foo.c'),
139
(['src/bar.c'], 'src'),
140
(['src/bar.c', 'bla/foo.c'], 'src'),
143
self.assert_(is_inside_or_parent_of_any(dirs, fn))
145
for dirs, fn in [(['src'], 'srccontrol'),
146
(['srccontrol/foo.c'], 'src'),
147
(['src'], 'srccontrol/foo')]:
148
self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
150
def test_rmtree(self):
151
# Check to remove tree with read-only files/dirs
153
f = file('dir/file', 'w')
156
# would like to also try making the directory readonly, but at the
157
# moment python shutil.rmtree doesn't handle that properly - it would
158
# need to chmod the directory before removing things inside it - deferred
159
# for now -- mbp 20060505
160
# osutils.make_readonly('dir')
161
osutils.make_readonly('dir/file')
163
osutils.rmtree('dir')
165
self.failIfExists('dir/file')
166
self.failIfExists('dir')
168
def test_file_kind(self):
169
self.build_tree(['file', 'dir/'])
170
self.assertEquals('file', osutils.file_kind('file'))
171
self.assertEquals('directory', osutils.file_kind('dir/'))
172
if osutils.has_symlinks():
173
os.symlink('symlink', 'symlink')
174
self.assertEquals('symlink', osutils.file_kind('symlink'))
176
# TODO: jam 20060529 Test a block device
178
os.lstat('/dev/null')
180
if e.errno not in (errno.ENOENT,):
183
self.assertEquals('chardev', osutils.file_kind('/dev/null'))
185
mkfifo = getattr(os, 'mkfifo', None)
189
self.assertEquals('fifo', osutils.file_kind('fifo'))
193
AF_UNIX = getattr(socket, 'AF_UNIX', None)
195
s = socket.socket(AF_UNIX)
198
self.assertEquals('socket', osutils.file_kind('socket'))
202
def test_kind_marker(self):
203
self.assertEqual(osutils.kind_marker('file'), '')
204
self.assertEqual(osutils.kind_marker('directory'), '/')
205
self.assertEqual(osutils.kind_marker('symlink'), '@')
206
self.assertEqual(osutils.kind_marker('tree-reference'), '+')
208
def test_get_umask(self):
209
if sys.platform == 'win32':
210
# umask always returns '0', no way to set it
211
self.assertEqual(0, osutils.get_umask())
214
orig_umask = osutils.get_umask()
217
self.assertEqual(0222, osutils.get_umask())
219
self.assertEqual(0022, osutils.get_umask())
221
self.assertEqual(0002, osutils.get_umask())
223
self.assertEqual(0027, osutils.get_umask())
227
def assertFormatedDelta(self, expected, seconds):
228
"""Assert osutils.format_delta formats as expected"""
229
actual = osutils.format_delta(seconds)
230
self.assertEqual(expected, actual)
232
def test_format_delta(self):
233
self.assertFormatedDelta('0 seconds ago', 0)
234
self.assertFormatedDelta('1 second ago', 1)
235
self.assertFormatedDelta('10 seconds ago', 10)
236
self.assertFormatedDelta('59 seconds ago', 59)
237
self.assertFormatedDelta('89 seconds ago', 89)
238
self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
239
self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
240
self.assertFormatedDelta('3 minutes, 1 second ago', 181)
241
self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
242
self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
243
self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
244
self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
245
self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
246
self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
247
self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
248
self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
249
self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
250
self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
251
self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
252
self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
253
self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
254
self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
255
self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
257
# We handle when time steps the wrong direction because computers
258
# don't have synchronized clocks.
259
self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
260
self.assertFormatedDelta('1 second in the future', -1)
261
self.assertFormatedDelta('2 seconds in the future', -2)
263
def test_dereference_path(self):
264
self.requireFeature(SymlinkFeature)
265
cwd = osutils.realpath('.')
267
bar_path = osutils.pathjoin(cwd, 'bar')
268
# Using './' to avoid bug #1213894 (first path component not
269
# dereferenced) in Python 2.4.1 and earlier
270
self.assertEqual(bar_path, osutils.realpath('./bar'))
271
os.symlink('bar', 'foo')
272
self.assertEqual(bar_path, osutils.realpath('./foo'))
274
# Does not dereference terminal symlinks
275
foo_path = osutils.pathjoin(cwd, 'foo')
276
self.assertEqual(foo_path, osutils.dereference_path('./foo'))
278
# Dereferences parent symlinks
280
baz_path = osutils.pathjoin(bar_path, 'baz')
281
self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
283
# Dereferences parent symlinks that are the first path element
284
self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
286
# Dereferences parent symlinks in absolute paths
287
foo_baz_path = osutils.pathjoin(foo_path, 'baz')
288
self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
290
def test_changing_access(self):
291
f = file('file', 'w')
295
# Make a file readonly
296
osutils.make_readonly('file')
297
mode = os.lstat('file').st_mode
298
self.assertEqual(mode, mode & 0777555)
300
# Make a file writable
301
osutils.make_writable('file')
302
mode = os.lstat('file').st_mode
303
self.assertEqual(mode, mode | 0200)
305
if osutils.has_symlinks():
306
# should not error when handed a symlink
307
os.symlink('nonexistent', 'dangling')
308
osutils.make_readonly('dangling')
309
osutils.make_writable('dangling')
311
def test_kind_marker(self):
312
self.assertEqual("", osutils.kind_marker("file"))
313
self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
314
self.assertEqual("@", osutils.kind_marker("symlink"))
315
self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
318
class TestSafeUnicode(TestCase):
320
def test_from_ascii_string(self):
321
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
323
def test_from_unicode_string_ascii_contents(self):
324
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
326
def test_from_unicode_string_unicode_contents(self):
327
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
329
def test_from_utf8_string(self):
330
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
332
def test_bad_utf8_string(self):
333
self.assertRaises(BzrBadParameterNotUnicode,
334
osutils.safe_unicode,
338
class TestSafeUtf8(TestCase):
340
def test_from_ascii_string(self):
342
self.assertEqual('foobar', osutils.safe_utf8(f))
344
def test_from_unicode_string_ascii_contents(self):
345
self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
347
def test_from_unicode_string_unicode_contents(self):
348
self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
350
def test_from_utf8_string(self):
351
self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
353
def test_bad_utf8_string(self):
354
self.assertRaises(BzrBadParameterNotUnicode,
355
osutils.safe_utf8, '\xbb\xbb')
358
class TestSafeRevisionId(TestCase):
360
def test_from_ascii_string(self):
361
# this shouldn't give a warning because it's getting an ascii string
362
self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
364
def test_from_unicode_string_ascii_contents(self):
365
self.assertEqual('bargam',
366
osutils.safe_revision_id(u'bargam', warn=False))
368
def test_from_unicode_deprecated(self):
369
self.assertEqual('bargam',
370
self.callDeprecated([osutils._revision_id_warning],
371
osutils.safe_revision_id, u'bargam'))
373
def test_from_unicode_string_unicode_contents(self):
374
self.assertEqual('bargam\xc2\xae',
375
osutils.safe_revision_id(u'bargam\xae', warn=False))
377
def test_from_utf8_string(self):
378
self.assertEqual('foo\xc2\xae',
379
osutils.safe_revision_id('foo\xc2\xae'))
382
"""Currently, None is a valid revision_id"""
383
self.assertEqual(None, osutils.safe_revision_id(None))
386
class TestSafeFileId(TestCase):
388
def test_from_ascii_string(self):
389
self.assertEqual('foobar', osutils.safe_file_id('foobar'))
391
def test_from_unicode_string_ascii_contents(self):
392
self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
394
def test_from_unicode_deprecated(self):
395
self.assertEqual('bargam',
396
self.callDeprecated([osutils._file_id_warning],
397
osutils.safe_file_id, u'bargam'))
399
def test_from_unicode_string_unicode_contents(self):
400
self.assertEqual('bargam\xc2\xae',
401
osutils.safe_file_id(u'bargam\xae', warn=False))
403
def test_from_utf8_string(self):
404
self.assertEqual('foo\xc2\xae',
405
osutils.safe_file_id('foo\xc2\xae'))
408
"""Currently, None is a valid revision_id"""
409
self.assertEqual(None, osutils.safe_file_id(None))
412
class TestWin32Funcs(TestCase):
413
"""Test that the _win32 versions of os utilities return appropriate paths."""
415
def test_abspath(self):
416
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
417
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
418
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
419
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
421
def test_realpath(self):
422
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
423
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
425
def test_pathjoin(self):
426
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
427
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
428
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
429
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
430
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
431
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
433
def test_normpath(self):
434
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
435
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
437
def test_getcwd(self):
438
cwd = osutils._win32_getcwd()
439
os_cwd = os.getcwdu()
440
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
441
# win32 is inconsistent whether it returns lower or upper case
442
# and even if it was consistent the user might type the other
443
# so we force it to uppercase
444
# running python.exe under cmd.exe return capital C:\\
445
# running win32 python inside a cygwin shell returns lowercase
446
self.assertEqual(os_cwd[0].upper(), cwd[0])
448
def test_fixdrive(self):
449
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
450
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
451
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
453
def test_win98_abspath(self):
455
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
456
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
458
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
459
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
461
cwd = osutils.getcwd().rstrip('/')
462
drive = osutils._nt_splitdrive(cwd)[0]
463
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
464
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
467
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
470
class TestWin32FuncsDirs(TestCaseInTempDir):
471
"""Test win32 functions that create files."""
473
def test_getcwd(self):
474
if win32utils.winver == 'Windows 98':
475
raise TestSkipped('Windows 98 cannot handle unicode filenames')
476
# Make sure getcwd can handle unicode filenames
480
raise TestSkipped("Unable to create Unicode filename")
483
# TODO: jam 20060427 This will probably fail on Mac OSX because
484
# it will change the normalization of B\xe5gfors
485
# Consider using a different unicode character, or make
486
# osutils.getcwd() renormalize the path.
487
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
489
def test_minimum_path_selection(self):
490
self.assertEqual(set(),
491
osutils.minimum_path_selection([]))
492
self.assertEqual(set(['a', 'b']),
493
osutils.minimum_path_selection(['a', 'b']))
494
self.assertEqual(set(['a/', 'b']),
495
osutils.minimum_path_selection(['a/', 'b']))
496
self.assertEqual(set(['a/', 'b']),
497
osutils.minimum_path_selection(['a/c', 'a/', 'b']))
499
def test_mkdtemp(self):
500
tmpdir = osutils._win32_mkdtemp(dir='.')
501
self.assertFalse('\\' in tmpdir)
503
def test_rename(self):
511
osutils._win32_rename('b', 'a')
512
self.failUnlessExists('a')
513
self.failIfExists('b')
514
self.assertFileEqual('baz\n', 'a')
516
def test_rename_missing_file(self):
522
osutils._win32_rename('b', 'a')
523
except (IOError, OSError), e:
524
self.assertEqual(errno.ENOENT, e.errno)
525
self.assertFileEqual('foo\n', 'a')
527
def test_rename_missing_dir(self):
530
osutils._win32_rename('b', 'a')
531
except (IOError, OSError), e:
532
self.assertEqual(errno.ENOENT, e.errno)
534
def test_rename_current_dir(self):
537
# You can't rename the working directory
538
# doing rename non-existant . usually
539
# just raises ENOENT, since non-existant
542
osutils._win32_rename('b', '.')
543
except (IOError, OSError), e:
544
self.assertEqual(errno.ENOENT, e.errno)
546
def test_splitpath(self):
547
def check(expected, path):
548
self.assertEqual(expected, osutils.splitpath(path))
551
check(['a', 'b'], 'a/b')
552
check(['a', 'b'], 'a/./b')
553
check(['a', '.b'], 'a/.b')
554
check(['a', '.b'], 'a\\.b')
556
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
559
class TestMacFuncsDirs(TestCaseInTempDir):
560
"""Test mac special functions that require directories."""
562
def test_getcwd(self):
563
# On Mac, this will actually create Ba\u030agfors
564
# but chdir will still work, because it accepts both paths
566
os.mkdir(u'B\xe5gfors')
568
raise TestSkipped("Unable to create Unicode filename")
570
os.chdir(u'B\xe5gfors')
571
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
573
def test_getcwd_nonnorm(self):
574
# Test that _mac_getcwd() will normalize this path
576
os.mkdir(u'Ba\u030agfors')
578
raise TestSkipped("Unable to create Unicode filename")
580
os.chdir(u'Ba\u030agfors')
581
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
584
class TestSplitLines(TestCase):
586
def test_split_unicode(self):
587
self.assertEqual([u'foo\n', u'bar\xae'],
588
osutils.split_lines(u'foo\nbar\xae'))
589
self.assertEqual([u'foo\n', u'bar\xae\n'],
590
osutils.split_lines(u'foo\nbar\xae\n'))
592
def test_split_with_carriage_returns(self):
593
self.assertEqual(['foo\rbar\n'],
594
osutils.split_lines('foo\rbar\n'))
597
class TestWalkDirs(TestCaseInTempDir):
599
def test_walkdirs(self):
608
self.build_tree(tree)
609
expected_dirblocks = [
611
[('0file', '0file', 'file'),
612
('1dir', '1dir', 'directory'),
613
('2file', '2file', 'file'),
617
[('1dir/0file', '0file', 'file'),
618
('1dir/1dir', '1dir', 'directory'),
621
(('1dir/1dir', './1dir/1dir'),
628
for dirdetail, dirblock in osutils.walkdirs('.'):
629
if len(dirblock) and dirblock[0][1] == '.bzr':
630
# this tests the filtering of selected paths
633
result.append((dirdetail, dirblock))
635
self.assertTrue(found_bzrdir)
636
self.assertEqual(expected_dirblocks,
637
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
638
# you can search a subdir only, with a supplied prefix.
640
for dirblock in osutils.walkdirs('./1dir', '1dir'):
641
result.append(dirblock)
642
self.assertEqual(expected_dirblocks[1:],
643
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
645
def test__walkdirs_utf8(self):
654
self.build_tree(tree)
655
expected_dirblocks = [
657
[('0file', '0file', 'file'),
658
('1dir', '1dir', 'directory'),
659
('2file', '2file', 'file'),
663
[('1dir/0file', '0file', 'file'),
664
('1dir/1dir', '1dir', 'directory'),
667
(('1dir/1dir', './1dir/1dir'),
674
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
675
if len(dirblock) and dirblock[0][1] == '.bzr':
676
# this tests the filtering of selected paths
679
result.append((dirdetail, dirblock))
681
self.assertTrue(found_bzrdir)
682
self.assertEqual(expected_dirblocks,
683
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
684
# you can search a subdir only, with a supplied prefix.
686
for dirblock in osutils.walkdirs('./1dir', '1dir'):
687
result.append(dirblock)
688
self.assertEqual(expected_dirblocks[1:],
689
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
691
def _filter_out_stat(self, result):
692
"""Filter out the stat value from the walkdirs result"""
693
for dirdetail, dirblock in result:
695
for info in dirblock:
696
# Ignore info[3] which is the stat
697
new_dirblock.append((info[0], info[1], info[2], info[4]))
698
dirblock[:] = new_dirblock
700
def test_unicode_walkdirs(self):
701
"""Walkdirs should always return unicode paths."""
702
name0 = u'0file-\xb6'
703
name1 = u'1dir-\u062c\u0648'
704
name2 = u'2file-\u0633'
709
name1 + '/' + name1 + '/',
713
self.build_tree(tree)
715
raise TestSkipped('Could not represent Unicode chars'
716
' in current encoding.')
717
expected_dirblocks = [
719
[(name0, name0, 'file', './' + name0),
720
(name1, name1, 'directory', './' + name1),
721
(name2, name2, 'file', './' + name2),
724
((name1, './' + name1),
725
[(name1 + '/' + name0, name0, 'file', './' + name1
727
(name1 + '/' + name1, name1, 'directory', './' + name1
731
((name1 + '/' + name1, './' + name1 + '/' + name1),
736
result = list(osutils.walkdirs('.'))
737
self._filter_out_stat(result)
738
self.assertEqual(expected_dirblocks, result)
739
result = list(osutils.walkdirs(u'./'+name1, name1))
740
self._filter_out_stat(result)
741
self.assertEqual(expected_dirblocks[1:], result)
743
def test_unicode__walkdirs_utf8(self):
744
"""Walkdirs_utf8 should always return utf8 paths.
746
The abspath portion might be in unicode or utf-8
748
name0 = u'0file-\xb6'
749
name1 = u'1dir-\u062c\u0648'
750
name2 = u'2file-\u0633'
755
name1 + '/' + name1 + '/',
759
self.build_tree(tree)
761
raise TestSkipped('Could not represent Unicode chars'
762
' in current encoding.')
763
name0 = name0.encode('utf8')
764
name1 = name1.encode('utf8')
765
name2 = name2.encode('utf8')
767
expected_dirblocks = [
769
[(name0, name0, 'file', './' + name0),
770
(name1, name1, 'directory', './' + name1),
771
(name2, name2, 'file', './' + name2),
774
((name1, './' + name1),
775
[(name1 + '/' + name0, name0, 'file', './' + name1
777
(name1 + '/' + name1, name1, 'directory', './' + name1
781
((name1 + '/' + name1, './' + name1 + '/' + name1),
787
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
788
# all abspaths are Unicode, and encode them back into utf8.
789
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
790
self.assertIsInstance(dirdetail[0], str)
791
if isinstance(dirdetail[1], unicode):
792
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
793
dirblock = [list(info) for info in dirblock]
794
for info in dirblock:
795
self.assertIsInstance(info[4], unicode)
796
info[4] = info[4].encode('utf8')
798
for info in dirblock:
799
self.assertIsInstance(info[0], str)
800
self.assertIsInstance(info[1], str)
801
self.assertIsInstance(info[4], str)
802
# Remove the stat information
803
new_dirblock.append((info[0], info[1], info[2], info[4]))
804
result.append((dirdetail, new_dirblock))
805
self.assertEqual(expected_dirblocks, result)
807
def test_unicode__walkdirs_unicode_to_utf8(self):
808
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
810
The abspath portion should be in unicode
812
name0u = u'0file-\xb6'
813
name1u = u'1dir-\u062c\u0648'
814
name2u = u'2file-\u0633'
818
name1u + '/' + name0u,
819
name1u + '/' + name1u + '/',
823
self.build_tree(tree)
825
raise TestSkipped('Could not represent Unicode chars'
826
' in current encoding.')
827
name0 = name0u.encode('utf8')
828
name1 = name1u.encode('utf8')
829
name2 = name2u.encode('utf8')
831
# All of the abspaths should be in unicode, all of the relative paths
833
expected_dirblocks = [
835
[(name0, name0, 'file', './' + name0u),
836
(name1, name1, 'directory', './' + name1u),
837
(name2, name2, 'file', './' + name2u),
840
((name1, './' + name1u),
841
[(name1 + '/' + name0, name0, 'file', './' + name1u
843
(name1 + '/' + name1, name1, 'directory', './' + name1u
847
((name1 + '/' + name1, './' + name1u + '/' + name1u),
852
result = list(osutils._walkdirs_unicode_to_utf8('.'))
853
self._filter_out_stat(result)
854
self.assertEqual(expected_dirblocks, result)
856
def assertPathCompare(self, path_less, path_greater):
857
"""check that path_less and path_greater compare correctly."""
858
self.assertEqual(0, osutils.compare_paths_prefix_order(
859
path_less, path_less))
860
self.assertEqual(0, osutils.compare_paths_prefix_order(
861
path_greater, path_greater))
862
self.assertEqual(-1, osutils.compare_paths_prefix_order(
863
path_less, path_greater))
864
self.assertEqual(1, osutils.compare_paths_prefix_order(
865
path_greater, path_less))
867
def test_compare_paths_prefix_order(self):
868
# root before all else
869
self.assertPathCompare("/", "/a")
871
self.assertPathCompare("/a", "/b")
872
self.assertPathCompare("/b", "/z")
873
# high dirs before lower.
874
self.assertPathCompare("/z", "/a/a")
875
# except if the deeper dir should be output first
876
self.assertPathCompare("/a/b/c", "/d/g")
877
# lexical betwen dirs of the same height
878
self.assertPathCompare("/a/z", "/z/z")
879
self.assertPathCompare("/a/c/z", "/a/d/e")
881
# this should also be consistent for no leading / paths
882
# root before all else
883
self.assertPathCompare("", "a")
885
self.assertPathCompare("a", "b")
886
self.assertPathCompare("b", "z")
887
# high dirs before lower.
888
self.assertPathCompare("z", "a/a")
889
# except if the deeper dir should be output first
890
self.assertPathCompare("a/b/c", "d/g")
891
# lexical betwen dirs of the same height
892
self.assertPathCompare("a/z", "z/z")
893
self.assertPathCompare("a/c/z", "a/d/e")
895
def test_path_prefix_sorting(self):
896
"""Doing a sort on path prefix should match our sample data."""
927
sorted(original_paths, key=osutils.path_prefix_key))
928
# using the comparison routine shoudl work too:
931
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
934
class TestCopyTree(TestCaseInTempDir):
936
def test_copy_basic_tree(self):
937
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
938
osutils.copy_tree('source', 'target')
939
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
940
self.assertEqual(['c'], os.listdir('target/b'))
942
def test_copy_tree_target_exists(self):
943
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
945
osutils.copy_tree('source', 'target')
946
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
947
self.assertEqual(['c'], os.listdir('target/b'))
949
def test_copy_tree_symlinks(self):
950
self.requireFeature(SymlinkFeature)
951
self.build_tree(['source/'])
952
os.symlink('a/generic/path', 'source/lnk')
953
osutils.copy_tree('source', 'target')
954
self.assertEqual(['lnk'], os.listdir('target'))
955
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
957
def test_copy_tree_handlers(self):
960
def file_handler(from_path, to_path):
961
processed_files.append(('f', from_path, to_path))
962
def dir_handler(from_path, to_path):
963
processed_files.append(('d', from_path, to_path))
964
def link_handler(from_path, to_path):
965
processed_links.append((from_path, to_path))
966
handlers = {'file':file_handler,
967
'directory':dir_handler,
968
'symlink':link_handler,
971
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
972
if osutils.has_symlinks():
973
os.symlink('a/generic/path', 'source/lnk')
974
osutils.copy_tree('source', 'target', handlers=handlers)
976
self.assertEqual([('d', 'source', 'target'),
977
('f', 'source/a', 'target/a'),
978
('d', 'source/b', 'target/b'),
979
('f', 'source/b/c', 'target/b/c'),
981
self.failIfExists('target')
982
if osutils.has_symlinks():
983
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
986
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
987
# [bialix] 2006/12/26
990
class TestSetUnsetEnv(TestCase):
991
"""Test updating the environment"""
994
super(TestSetUnsetEnv, self).setUp()
996
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
997
'Environment was not cleaned up properly.'
998
' Variable BZR_TEST_ENV_VAR should not exist.')
1000
if 'BZR_TEST_ENV_VAR' in os.environ:
1001
del os.environ['BZR_TEST_ENV_VAR']
1003
self.addCleanup(cleanup)
1006
"""Test that we can set an env variable"""
1007
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1008
self.assertEqual(None, old)
1009
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
1011
def test_double_set(self):
1012
"""Test that we get the old value out"""
1013
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1014
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
1015
self.assertEqual('foo', old)
1016
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1018
def test_unicode(self):
1019
"""Environment can only contain plain strings
1021
So Unicode strings must be encoded.
1023
uni_val, env_val = probe_unicode_in_user_encoding()
1025
raise TestSkipped('Cannot find a unicode character that works in'
1026
' encoding %s' % (bzrlib.user_encoding,))
1028
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1029
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1031
def test_unset(self):
1032
"""Test that passing None will remove the env var"""
1033
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1034
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1035
self.assertEqual('foo', old)
1036
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1037
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1040
class TestLocalTimeOffset(TestCase):
1042
def test_local_time_offset(self):
1043
"""Test that local_time_offset() returns a sane value."""
1044
offset = osutils.local_time_offset()
1045
self.assertTrue(isinstance(offset, int))
1046
# Test that the offset is no more than a eighteen hours in
1048
# Time zone handling is system specific, so it is difficult to
1049
# do more specific tests, but a value outside of this range is
1051
eighteen_hours = 18 * 3600
1052
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1054
def test_local_time_offset_with_timestamp(self):
1055
"""Test that local_time_offset() works with a timestamp."""
1056
offset = osutils.local_time_offset(1000000000.1234567)
1057
self.assertTrue(isinstance(offset, int))
1058
eighteen_hours = 18 * 3600
1059
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1062
class TestShaFileByName(TestCaseInTempDir):
1064
def test_sha_empty(self):
1065
self.build_tree_contents([('foo', '')])
1066
expected_sha = osutils.sha_string('')
1067
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1069
def test_sha_mixed_endings(self):
1070
text = 'test\r\nwith\nall\rpossible line endings\r\n'
1071
self.build_tree_contents([('foo', text)])
1072
expected_sha = osutils.sha_string(text)
1073
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))