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,
46
class TestOSUtils(TestCaseInTempDir):
48
def test_contains_whitespace(self):
49
self.failUnless(osutils.contains_whitespace(u' '))
50
self.failUnless(osutils.contains_whitespace(u'hello there'))
51
self.failUnless(osutils.contains_whitespace(u'hellothere\n'))
52
self.failUnless(osutils.contains_whitespace(u'hello\nthere'))
53
self.failUnless(osutils.contains_whitespace(u'hello\rthere'))
54
self.failUnless(osutils.contains_whitespace(u'hello\tthere'))
56
# \xa0 is "Non-breaking-space" which on some python locales thinks it
57
# is whitespace, but we do not.
58
self.failIf(osutils.contains_whitespace(u''))
59
self.failIf(osutils.contains_whitespace(u'hellothere'))
60
self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
62
def test_fancy_rename(self):
63
# This should work everywhere
65
osutils.fancy_rename(a, b,
66
rename_func=os.rename,
67
unlink_func=os.unlink)
69
open('a', 'wb').write('something in a\n')
71
self.failIfExists('a')
72
self.failUnlessExists('b')
73
self.check_file_contents('b', 'something in a\n')
75
open('a', 'wb').write('new something in a\n')
78
self.check_file_contents('a', 'something in a\n')
80
def test_rename(self):
81
# Rename should be semi-atomic on all platforms
82
open('a', 'wb').write('something in a\n')
83
osutils.rename('a', 'b')
84
self.failIfExists('a')
85
self.failUnlessExists('b')
86
self.check_file_contents('b', 'something in a\n')
88
open('a', 'wb').write('new something in a\n')
89
osutils.rename('b', 'a')
91
self.check_file_contents('a', 'something in a\n')
93
# TODO: test fancy_rename using a MemoryTransport
95
def test_01_rand_chars_empty(self):
96
result = osutils.rand_chars(0)
97
self.assertEqual(result, '')
99
def test_02_rand_chars_100(self):
100
result = osutils.rand_chars(100)
101
self.assertEqual(len(result), 100)
102
self.assertEqual(type(result), str)
103
self.assertContainsRe(result, r'^[a-z0-9]{100}$')
105
def test_is_inside(self):
106
is_inside = osutils.is_inside
107
self.assertTrue(is_inside('src', 'src/foo.c'))
108
self.assertFalse(is_inside('src', 'srccontrol'))
109
self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
110
self.assertTrue(is_inside('foo.c', 'foo.c'))
111
self.assertFalse(is_inside('foo.c', ''))
112
self.assertTrue(is_inside('', 'foo.c'))
114
def test_is_inside_any(self):
115
SRC_FOO_C = pathjoin('src', 'foo.c')
116
for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
117
(['src'], SRC_FOO_C),
120
self.assert_(is_inside_any(dirs, fn))
121
for dirs, fn in [(['src'], 'srccontrol'),
122
(['src'], 'srccontrol/foo')]:
123
self.assertFalse(is_inside_any(dirs, fn))
125
def test_is_inside_or_parent_of_any(self):
126
for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
127
(['src'], 'src/foo.c'),
128
(['src/bar.c'], 'src'),
129
(['src/bar.c', 'bla/foo.c'], 'src'),
132
self.assert_(is_inside_or_parent_of_any(dirs, fn))
134
for dirs, fn in [(['src'], 'srccontrol'),
135
(['srccontrol/foo.c'], 'src'),
136
(['src'], 'srccontrol/foo')]:
137
self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
139
def test_rmtree(self):
140
# Check to remove tree with read-only files/dirs
142
f = file('dir/file', 'w')
145
# would like to also try making the directory readonly, but at the
146
# moment python shutil.rmtree doesn't handle that properly - it would
147
# need to chmod the directory before removing things inside it - deferred
148
# for now -- mbp 20060505
149
# osutils.make_readonly('dir')
150
osutils.make_readonly('dir/file')
152
osutils.rmtree('dir')
154
self.failIfExists('dir/file')
155
self.failIfExists('dir')
157
def test_file_kind(self):
158
self.build_tree(['file', 'dir/'])
159
self.assertEquals('file', osutils.file_kind('file'))
160
self.assertEquals('directory', osutils.file_kind('dir/'))
161
if osutils.has_symlinks():
162
os.symlink('symlink', 'symlink')
163
self.assertEquals('symlink', osutils.file_kind('symlink'))
165
# TODO: jam 20060529 Test a block device
167
os.lstat('/dev/null')
169
if e.errno not in (errno.ENOENT,):
172
self.assertEquals('chardev', osutils.file_kind('/dev/null'))
174
mkfifo = getattr(os, 'mkfifo', None)
178
self.assertEquals('fifo', osutils.file_kind('fifo'))
182
AF_UNIX = getattr(socket, 'AF_UNIX', None)
184
s = socket.socket(AF_UNIX)
187
self.assertEquals('socket', osutils.file_kind('socket'))
191
def test_kind_marker(self):
192
self.assertEqual(osutils.kind_marker('file'), '')
193
self.assertEqual(osutils.kind_marker('directory'), '/')
194
self.assertEqual(osutils.kind_marker('symlink'), '@')
195
self.assertEqual(osutils.kind_marker('tree-reference'), '+')
197
def test_get_umask(self):
198
if sys.platform == 'win32':
199
# umask always returns '0', no way to set it
200
self.assertEqual(0, osutils.get_umask())
203
orig_umask = osutils.get_umask()
206
self.assertEqual(0222, osutils.get_umask())
208
self.assertEqual(0022, osutils.get_umask())
210
self.assertEqual(0002, osutils.get_umask())
212
self.assertEqual(0027, osutils.get_umask())
216
def assertFormatedDelta(self, expected, seconds):
217
"""Assert osutils.format_delta formats as expected"""
218
actual = osutils.format_delta(seconds)
219
self.assertEqual(expected, actual)
221
def test_format_delta(self):
222
self.assertFormatedDelta('0 seconds ago', 0)
223
self.assertFormatedDelta('1 second ago', 1)
224
self.assertFormatedDelta('10 seconds ago', 10)
225
self.assertFormatedDelta('59 seconds ago', 59)
226
self.assertFormatedDelta('89 seconds ago', 89)
227
self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
228
self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
229
self.assertFormatedDelta('3 minutes, 1 second ago', 181)
230
self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
231
self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
232
self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
233
self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
234
self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
235
self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
236
self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
237
self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
238
self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
239
self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
240
self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
241
self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
242
self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
243
self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
244
self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
246
# We handle when time steps the wrong direction because computers
247
# don't have synchronized clocks.
248
self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
249
self.assertFormatedDelta('1 second in the future', -1)
250
self.assertFormatedDelta('2 seconds in the future', -2)
252
def test_dereference_path(self):
253
if not osutils.has_symlinks():
254
raise TestSkipped('Symlinks are not supported on this platform')
255
cwd = osutils.realpath('.')
257
bar_path = osutils.pathjoin(cwd, 'bar')
258
# Using './' to avoid bug #1213894 (first path component not
259
# dereferenced) in Python 2.4.1 and earlier
260
self.assertEqual(bar_path, osutils.realpath('./bar'))
261
os.symlink('bar', 'foo')
262
self.assertEqual(bar_path, osutils.realpath('./foo'))
264
# Does not dereference terminal symlinks
265
foo_path = osutils.pathjoin(cwd, 'foo')
266
self.assertEqual(foo_path, osutils.dereference_path('./foo'))
268
# Dereferences parent symlinks
270
baz_path = osutils.pathjoin(bar_path, 'baz')
271
self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
273
# Dereferences parent symlinks that are the first path element
274
self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
276
# Dereferences parent symlinks in absolute paths
277
foo_baz_path = osutils.pathjoin(foo_path, 'baz')
278
self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
280
def test_changing_access(self):
281
f = file('file', 'w')
285
# Make a file readonly
286
osutils.make_readonly('file')
287
mode = osutils.lstat('file').st_mode
288
self.assertEqual(mode, mode & 0777555)
290
# Make a file writable
291
osutils.make_writable('file')
292
mode = osutils.lstat('file').st_mode
293
self.assertEqual(mode, mode | 0200)
295
if osutils.has_symlinks():
296
# should not error when handed a symlink
297
os.symlink('nonexistent', 'dangling')
298
osutils.make_readonly('dangling')
299
osutils.make_writable('dangling')
301
def test_kind_marker(self):
302
self.assertEqual("", osutils.kind_marker("file"))
303
self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
304
self.assertEqual("@", osutils.kind_marker("symlink"))
305
self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
308
class TestSafeUnicode(TestCase):
310
def test_from_ascii_string(self):
311
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
313
def test_from_unicode_string_ascii_contents(self):
314
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
316
def test_from_unicode_string_unicode_contents(self):
317
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
319
def test_from_utf8_string(self):
320
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
322
def test_bad_utf8_string(self):
323
self.assertRaises(BzrBadParameterNotUnicode,
324
osutils.safe_unicode,
328
class TestSafeUtf8(TestCase):
330
def test_from_ascii_string(self):
332
self.assertEqual('foobar', osutils.safe_utf8(f))
334
def test_from_unicode_string_ascii_contents(self):
335
self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
337
def test_from_unicode_string_unicode_contents(self):
338
self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
340
def test_from_utf8_string(self):
341
self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
343
def test_bad_utf8_string(self):
344
self.assertRaises(BzrBadParameterNotUnicode,
345
osutils.safe_utf8, '\xbb\xbb')
348
class TestSafeRevisionId(TestCase):
350
def test_from_ascii_string(self):
351
# this shouldn't give a warning because it's getting an ascii string
352
self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
354
def test_from_unicode_string_ascii_contents(self):
355
self.assertEqual('bargam',
356
osutils.safe_revision_id(u'bargam', warn=False))
358
def test_from_unicode_deprecated(self):
359
self.assertEqual('bargam',
360
self.callDeprecated([osutils._revision_id_warning],
361
osutils.safe_revision_id, u'bargam'))
363
def test_from_unicode_string_unicode_contents(self):
364
self.assertEqual('bargam\xc2\xae',
365
osutils.safe_revision_id(u'bargam\xae', warn=False))
367
def test_from_utf8_string(self):
368
self.assertEqual('foo\xc2\xae',
369
osutils.safe_revision_id('foo\xc2\xae'))
372
"""Currently, None is a valid revision_id"""
373
self.assertEqual(None, osutils.safe_revision_id(None))
376
class TestSafeFileId(TestCase):
378
def test_from_ascii_string(self):
379
self.assertEqual('foobar', osutils.safe_file_id('foobar'))
381
def test_from_unicode_string_ascii_contents(self):
382
self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
384
def test_from_unicode_deprecated(self):
385
self.assertEqual('bargam',
386
self.callDeprecated([osutils._file_id_warning],
387
osutils.safe_file_id, u'bargam'))
389
def test_from_unicode_string_unicode_contents(self):
390
self.assertEqual('bargam\xc2\xae',
391
osutils.safe_file_id(u'bargam\xae', warn=False))
393
def test_from_utf8_string(self):
394
self.assertEqual('foo\xc2\xae',
395
osutils.safe_file_id('foo\xc2\xae'))
398
"""Currently, None is a valid revision_id"""
399
self.assertEqual(None, osutils.safe_file_id(None))
402
class TestWin32Funcs(TestCase):
403
"""Test that the _win32 versions of os utilities return appropriate paths."""
405
def test_abspath(self):
406
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
407
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
408
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
409
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
411
def test_realpath(self):
412
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
413
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
415
def test_pathjoin(self):
416
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
417
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
418
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
419
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
420
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
421
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
423
def test_normpath(self):
424
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
425
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
427
def test_getcwd(self):
428
cwd = osutils._win32_getcwd()
429
os_cwd = os.getcwdu()
430
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
431
# win32 is inconsistent whether it returns lower or upper case
432
# and even if it was consistent the user might type the other
433
# so we force it to uppercase
434
# running python.exe under cmd.exe return capital C:\\
435
# running win32 python inside a cygwin shell returns lowercase
436
self.assertEqual(os_cwd[0].upper(), cwd[0])
438
def test_fixdrive(self):
439
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
440
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
441
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
443
def test_win98_abspath(self):
445
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
446
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
448
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
449
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
451
cwd = osutils.getcwd().rstrip('/')
452
drive = osutils._nt_splitdrive(cwd)[0]
453
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
454
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
457
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
460
class TestWin32FuncsDirs(TestCaseInTempDir):
461
"""Test win32 functions that create files."""
463
def test_getcwd(self):
464
if win32utils.winver == 'Windows 98':
465
raise TestSkipped('Windows 98 cannot handle unicode filenames')
466
# Make sure getcwd can handle unicode filenames
470
raise TestSkipped("Unable to create Unicode filename")
473
# TODO: jam 20060427 This will probably fail on Mac OSX because
474
# it will change the normalization of B\xe5gfors
475
# Consider using a different unicode character, or make
476
# osutils.getcwd() renormalize the path.
477
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
479
def test_minimum_path_selection(self):
480
self.assertEqual(set(),
481
osutils.minimum_path_selection([]))
482
self.assertEqual(set(['a', 'b']),
483
osutils.minimum_path_selection(['a', 'b']))
484
self.assertEqual(set(['a/', 'b']),
485
osutils.minimum_path_selection(['a/', 'b']))
486
self.assertEqual(set(['a/', 'b']),
487
osutils.minimum_path_selection(['a/c', 'a/', 'b']))
489
def test_mkdtemp(self):
490
tmpdir = osutils._win32_mkdtemp(dir='.')
491
self.assertFalse('\\' in tmpdir)
493
def test_rename(self):
501
osutils._win32_rename('b', 'a')
502
self.failUnlessExists('a')
503
self.failIfExists('b')
504
self.assertFileEqual('baz\n', 'a')
506
def test_rename_missing_file(self):
512
osutils._win32_rename('b', 'a')
513
except (IOError, OSError), e:
514
self.assertEqual(errno.ENOENT, e.errno)
515
self.assertFileEqual('foo\n', 'a')
517
def test_rename_missing_dir(self):
520
osutils._win32_rename('b', 'a')
521
except (IOError, OSError), e:
522
self.assertEqual(errno.ENOENT, e.errno)
524
def test_rename_current_dir(self):
527
# You can't rename the working directory
528
# doing rename non-existant . usually
529
# just raises ENOENT, since non-existant
532
osutils._win32_rename('b', '.')
533
except (IOError, OSError), e:
534
self.assertEqual(errno.ENOENT, e.errno)
536
def test_splitpath(self):
537
def check(expected, path):
538
self.assertEqual(expected, osutils.splitpath(path))
541
check(['a', 'b'], 'a/b')
542
check(['a', 'b'], 'a/./b')
543
check(['a', '.b'], 'a/.b')
544
check(['a', '.b'], 'a\\.b')
546
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
549
class TestMacFuncsDirs(TestCaseInTempDir):
550
"""Test mac special functions that require directories."""
552
def test_getcwd(self):
553
# On Mac, this will actually create Ba\u030agfors
554
# but chdir will still work, because it accepts both paths
556
os.mkdir(u'B\xe5gfors')
558
raise TestSkipped("Unable to create Unicode filename")
560
os.chdir(u'B\xe5gfors')
561
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
563
def test_getcwd_nonnorm(self):
564
# Test that _mac_getcwd() will normalize this path
566
os.mkdir(u'Ba\u030agfors')
568
raise TestSkipped("Unable to create Unicode filename")
570
os.chdir(u'Ba\u030agfors')
571
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
574
class TestSplitLines(TestCase):
576
def test_split_unicode(self):
577
self.assertEqual([u'foo\n', u'bar\xae'],
578
osutils.split_lines(u'foo\nbar\xae'))
579
self.assertEqual([u'foo\n', u'bar\xae\n'],
580
osutils.split_lines(u'foo\nbar\xae\n'))
582
def test_split_with_carriage_returns(self):
583
self.assertEqual(['foo\rbar\n'],
584
osutils.split_lines('foo\rbar\n'))
587
class TestWalkDirs(TestCaseInTempDir):
589
def test_walkdirs(self):
598
self.build_tree(tree)
599
expected_dirblocks = [
601
[('0file', '0file', 'file'),
602
('1dir', '1dir', 'directory'),
603
('2file', '2file', 'file'),
607
[('1dir/0file', '0file', 'file'),
608
('1dir/1dir', '1dir', 'directory'),
611
(('1dir/1dir', './1dir/1dir'),
618
for dirdetail, dirblock in osutils.walkdirs('.'):
619
if len(dirblock) and dirblock[0][1] == '.bzr':
620
# this tests the filtering of selected paths
623
result.append((dirdetail, dirblock))
625
self.assertTrue(found_bzrdir)
626
self.assertEqual(expected_dirblocks,
627
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
628
# you can search a subdir only, with a supplied prefix.
630
for dirblock in osutils.walkdirs('./1dir', '1dir'):
631
result.append(dirblock)
632
self.assertEqual(expected_dirblocks[1:],
633
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
635
def test__walkdirs_utf8(self):
644
self.build_tree(tree)
645
expected_dirblocks = [
647
[('0file', '0file', 'file'),
648
('1dir', '1dir', 'directory'),
649
('2file', '2file', 'file'),
653
[('1dir/0file', '0file', 'file'),
654
('1dir/1dir', '1dir', 'directory'),
657
(('1dir/1dir', './1dir/1dir'),
664
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
665
if len(dirblock) and dirblock[0][1] == '.bzr':
666
# this tests the filtering of selected paths
669
result.append((dirdetail, dirblock))
671
self.assertTrue(found_bzrdir)
672
self.assertEqual(expected_dirblocks,
673
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
674
# you can search a subdir only, with a supplied prefix.
676
for dirblock in osutils.walkdirs('./1dir', '1dir'):
677
result.append(dirblock)
678
self.assertEqual(expected_dirblocks[1:],
679
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
681
def _filter_out_stat(self, result):
682
"""Filter out the stat value from the walkdirs result"""
683
for dirdetail, dirblock in result:
685
for info in dirblock:
686
# Ignore info[3] which is the stat
687
new_dirblock.append((info[0], info[1], info[2], info[4]))
688
dirblock[:] = new_dirblock
690
def test_unicode_walkdirs(self):
691
"""Walkdirs should always return unicode paths."""
692
name0 = u'0file-\xb6'
693
name1 = u'1dir-\u062c\u0648'
694
name2 = u'2file-\u0633'
699
name1 + '/' + name1 + '/',
703
self.build_tree(tree)
705
raise TestSkipped('Could not represent Unicode chars'
706
' in current encoding.')
707
expected_dirblocks = [
709
[(name0, name0, 'file', './' + name0),
710
(name1, name1, 'directory', './' + name1),
711
(name2, name2, 'file', './' + name2),
714
((name1, './' + name1),
715
[(name1 + '/' + name0, name0, 'file', './' + name1
717
(name1 + '/' + name1, name1, 'directory', './' + name1
721
((name1 + '/' + name1, './' + name1 + '/' + name1),
726
result = list(osutils.walkdirs('.'))
727
self._filter_out_stat(result)
728
self.assertEqual(expected_dirblocks, result)
729
result = list(osutils.walkdirs(u'./'+name1, name1))
730
self._filter_out_stat(result)
731
self.assertEqual(expected_dirblocks[1:], result)
733
def test_unicode__walkdirs_utf8(self):
734
"""Walkdirs_utf8 should always return utf8 paths.
736
The abspath portion might be in unicode or utf-8
738
name0 = u'0file-\xb6'
739
name1 = u'1dir-\u062c\u0648'
740
name2 = u'2file-\u0633'
745
name1 + '/' + name1 + '/',
749
self.build_tree(tree)
751
raise TestSkipped('Could not represent Unicode chars'
752
' in current encoding.')
753
name0 = name0.encode('utf8')
754
name1 = name1.encode('utf8')
755
name2 = name2.encode('utf8')
757
expected_dirblocks = [
759
[(name0, name0, 'file', './' + name0),
760
(name1, name1, 'directory', './' + name1),
761
(name2, name2, 'file', './' + name2),
764
((name1, './' + name1),
765
[(name1 + '/' + name0, name0, 'file', './' + name1
767
(name1 + '/' + name1, name1, 'directory', './' + name1
771
((name1 + '/' + name1, './' + name1 + '/' + name1),
777
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
778
# all abspaths are Unicode, and encode them back into utf8.
779
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
780
self.assertIsInstance(dirdetail[0], str)
781
if isinstance(dirdetail[1], unicode):
782
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
783
dirblock = [list(info) for info in dirblock]
784
for info in dirblock:
785
self.assertIsInstance(info[4], unicode)
786
info[4] = info[4].encode('utf8')
788
for info in dirblock:
789
self.assertIsInstance(info[0], str)
790
self.assertIsInstance(info[1], str)
791
self.assertIsInstance(info[4], str)
792
# Remove the stat information
793
new_dirblock.append((info[0], info[1], info[2], info[4]))
794
result.append((dirdetail, new_dirblock))
795
self.assertEqual(expected_dirblocks, result)
797
def test_unicode__walkdirs_unicode_to_utf8(self):
798
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
800
The abspath portion should be in unicode
802
name0u = u'0file-\xb6'
803
name1u = u'1dir-\u062c\u0648'
804
name2u = u'2file-\u0633'
808
name1u + '/' + name0u,
809
name1u + '/' + name1u + '/',
813
self.build_tree(tree)
815
raise TestSkipped('Could not represent Unicode chars'
816
' in current encoding.')
817
name0 = name0u.encode('utf8')
818
name1 = name1u.encode('utf8')
819
name2 = name2u.encode('utf8')
821
# All of the abspaths should be in unicode, all of the relative paths
823
expected_dirblocks = [
825
[(name0, name0, 'file', './' + name0u),
826
(name1, name1, 'directory', './' + name1u),
827
(name2, name2, 'file', './' + name2u),
830
((name1, './' + name1u),
831
[(name1 + '/' + name0, name0, 'file', './' + name1u
833
(name1 + '/' + name1, name1, 'directory', './' + name1u
837
((name1 + '/' + name1, './' + name1u + '/' + name1u),
842
result = list(osutils._walkdirs_unicode_to_utf8('.'))
843
self._filter_out_stat(result)
844
self.assertEqual(expected_dirblocks, result)
846
def assertPathCompare(self, path_less, path_greater):
847
"""check that path_less and path_greater compare correctly."""
848
self.assertEqual(0, osutils.compare_paths_prefix_order(
849
path_less, path_less))
850
self.assertEqual(0, osutils.compare_paths_prefix_order(
851
path_greater, path_greater))
852
self.assertEqual(-1, osutils.compare_paths_prefix_order(
853
path_less, path_greater))
854
self.assertEqual(1, osutils.compare_paths_prefix_order(
855
path_greater, path_less))
857
def test_compare_paths_prefix_order(self):
858
# root before all else
859
self.assertPathCompare("/", "/a")
861
self.assertPathCompare("/a", "/b")
862
self.assertPathCompare("/b", "/z")
863
# high dirs before lower.
864
self.assertPathCompare("/z", "/a/a")
865
# except if the deeper dir should be output first
866
self.assertPathCompare("/a/b/c", "/d/g")
867
# lexical betwen dirs of the same height
868
self.assertPathCompare("/a/z", "/z/z")
869
self.assertPathCompare("/a/c/z", "/a/d/e")
871
# this should also be consistent for no leading / paths
872
# root before all else
873
self.assertPathCompare("", "a")
875
self.assertPathCompare("a", "b")
876
self.assertPathCompare("b", "z")
877
# high dirs before lower.
878
self.assertPathCompare("z", "a/a")
879
# except if the deeper dir should be output first
880
self.assertPathCompare("a/b/c", "d/g")
881
# lexical betwen dirs of the same height
882
self.assertPathCompare("a/z", "z/z")
883
self.assertPathCompare("a/c/z", "a/d/e")
885
def test_path_prefix_sorting(self):
886
"""Doing a sort on path prefix should match our sample data."""
917
sorted(original_paths, key=osutils.path_prefix_key))
918
# using the comparison routine shoudl work too:
921
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
924
class TestCopyTree(TestCaseInTempDir):
926
def test_copy_basic_tree(self):
927
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
928
osutils.copy_tree('source', 'target')
929
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
930
self.assertEqual(['c'], os.listdir('target/b'))
932
def test_copy_tree_target_exists(self):
933
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
935
osutils.copy_tree('source', 'target')
936
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
937
self.assertEqual(['c'], os.listdir('target/b'))
939
def test_copy_tree_symlinks(self):
940
if not osutils.has_symlinks():
942
self.build_tree(['source/'])
943
os.symlink('a/generic/path', 'source/lnk')
944
osutils.copy_tree('source', 'target')
945
self.assertEqual(['lnk'], os.listdir('target'))
946
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
948
def test_copy_tree_handlers(self):
951
def file_handler(from_path, to_path):
952
processed_files.append(('f', from_path, to_path))
953
def dir_handler(from_path, to_path):
954
processed_files.append(('d', from_path, to_path))
955
def link_handler(from_path, to_path):
956
processed_links.append((from_path, to_path))
957
handlers = {'file':file_handler,
958
'directory':dir_handler,
959
'symlink':link_handler,
962
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
963
if osutils.has_symlinks():
964
os.symlink('a/generic/path', 'source/lnk')
965
osutils.copy_tree('source', 'target', handlers=handlers)
967
self.assertEqual([('d', 'source', 'target'),
968
('f', 'source/a', 'target/a'),
969
('d', 'source/b', 'target/b'),
970
('f', 'source/b/c', 'target/b/c'),
972
self.failIfExists('target')
973
if osutils.has_symlinks():
974
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
977
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
978
# [bialix] 2006/12/26
981
class TestSetUnsetEnv(TestCase):
982
"""Test updating the environment"""
985
super(TestSetUnsetEnv, self).setUp()
987
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
988
'Environment was not cleaned up properly.'
989
' Variable BZR_TEST_ENV_VAR should not exist.')
991
if 'BZR_TEST_ENV_VAR' in os.environ:
992
del os.environ['BZR_TEST_ENV_VAR']
994
self.addCleanup(cleanup)
997
"""Test that we can set an env variable"""
998
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
999
self.assertEqual(None, old)
1000
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
1002
def test_double_set(self):
1003
"""Test that we get the old value out"""
1004
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1005
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
1006
self.assertEqual('foo', old)
1007
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1009
def test_unicode(self):
1010
"""Environment can only contain plain strings
1012
So Unicode strings must be encoded.
1014
uni_val, env_val = probe_unicode_in_user_encoding()
1016
raise TestSkipped('Cannot find a unicode character that works in'
1017
' encoding %s' % (bzrlib.user_encoding,))
1019
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1020
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1022
def test_unset(self):
1023
"""Test that passing None will remove the env var"""
1024
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1025
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1026
self.assertEqual('foo', old)
1027
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1028
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1031
class TestLocalTimeOffset(TestCase):
1033
def test_local_time_offset(self):
1034
"""Test that local_time_offset() returns a sane value."""
1035
offset = osutils.local_time_offset()
1036
self.assertTrue(isinstance(offset, int))
1037
# Test that the offset is no more than a eighteen hours in
1039
# Time zone handling is system specific, so it is difficult to
1040
# do more specific tests, but a value outside of this range is
1042
eighteen_hours = 18 * 3600
1043
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1045
def test_local_time_offset_with_timestamp(self):
1046
"""Test that local_time_offset() works with a timestamp."""
1047
offset = osutils.local_time_offset(1000000000.1234567)
1048
self.assertTrue(isinstance(offset, int))
1049
eighteen_hours = 18 * 3600
1050
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1053
class TestShaFileByName(TestCaseInTempDir):
1055
def test_sha_empty(self):
1056
self.build_tree_contents([('foo', '')])
1057
expected_sha = osutils.sha_string('')
1058
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1060
def test_sha_mixed_endings(self):
1061
text = 'test\r\nwith\nall\rpossible line endings\r\n'
1062
self.build_tree_contents([('foo', text)])
1063
expected_sha = osutils.sha_string(text)
1064
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))