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))
281
def test_changing_access(self):
282
f = file('file', 'w')
286
# Make a file readonly
287
osutils.make_readonly('file')
288
mode = osutils.lstat('file').st_mode
289
self.assertEqual(mode, mode & 0777555)
291
# Make a file writable
292
osutils.make_writable('file')
293
mode = osutils.lstat('file').st_mode
294
self.assertEqual(mode, mode | 0200)
296
if osutils.has_symlinks():
297
# should not error when handed a symlink
298
os.symlink('nonexistent', 'dangling')
299
osutils.make_readonly('dangling')
300
osutils.make_writable('dangling')
303
def test_kind_marker(self):
304
self.assertEqual("", osutils.kind_marker("file"))
305
self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
306
self.assertEqual("@", osutils.kind_marker("symlink"))
307
self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
310
class TestSafeUnicode(TestCase):
312
def test_from_ascii_string(self):
313
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
315
def test_from_unicode_string_ascii_contents(self):
316
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
318
def test_from_unicode_string_unicode_contents(self):
319
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
321
def test_from_utf8_string(self):
322
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
324
def test_bad_utf8_string(self):
325
self.assertRaises(BzrBadParameterNotUnicode,
326
osutils.safe_unicode,
330
class TestSafeUtf8(TestCase):
332
def test_from_ascii_string(self):
334
self.assertEqual('foobar', osutils.safe_utf8(f))
336
def test_from_unicode_string_ascii_contents(self):
337
self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
339
def test_from_unicode_string_unicode_contents(self):
340
self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
342
def test_from_utf8_string(self):
343
self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
345
def test_bad_utf8_string(self):
346
self.assertRaises(BzrBadParameterNotUnicode,
347
osutils.safe_utf8, '\xbb\xbb')
350
class TestSafeRevisionId(TestCase):
352
def test_from_ascii_string(self):
353
self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
355
def test_from_unicode_string_ascii_contents(self):
356
self.assertEqual('bargam',
357
osutils.safe_revision_id(u'bargam', warn=False))
359
def test_from_unicode_deprecated(self):
360
self.assertEqual('bargam',
361
self.callDeprecated([osutils._revision_id_warning],
362
osutils.safe_revision_id, u'bargam'))
364
def test_from_unicode_string_unicode_contents(self):
365
self.assertEqual('bargam\xc2\xae',
366
osutils.safe_revision_id(u'bargam\xae', warn=False))
368
def test_from_utf8_string(self):
369
self.assertEqual('foo\xc2\xae',
370
osutils.safe_revision_id('foo\xc2\xae'))
373
"""Currently, None is a valid revision_id"""
374
self.assertEqual(None, osutils.safe_revision_id(None))
377
class TestSafeFileId(TestCase):
379
def test_from_ascii_string(self):
380
self.assertEqual('foobar', osutils.safe_file_id('foobar'))
382
def test_from_unicode_string_ascii_contents(self):
383
self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
385
def test_from_unicode_deprecated(self):
386
self.assertEqual('bargam',
387
self.callDeprecated([osutils._file_id_warning],
388
osutils.safe_file_id, u'bargam'))
390
def test_from_unicode_string_unicode_contents(self):
391
self.assertEqual('bargam\xc2\xae',
392
osutils.safe_file_id(u'bargam\xae', warn=False))
394
def test_from_utf8_string(self):
395
self.assertEqual('foo\xc2\xae',
396
osutils.safe_file_id('foo\xc2\xae'))
399
"""Currently, None is a valid revision_id"""
400
self.assertEqual(None, osutils.safe_file_id(None))
403
class TestWin32Funcs(TestCase):
404
"""Test that the _win32 versions of os utilities return appropriate paths."""
406
def test_abspath(self):
407
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
408
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
409
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
410
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
412
def test_realpath(self):
413
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
414
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
416
def test_pathjoin(self):
417
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
418
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
419
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
420
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
421
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
422
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
424
def test_normpath(self):
425
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
426
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
428
def test_getcwd(self):
429
cwd = osutils._win32_getcwd()
430
os_cwd = os.getcwdu()
431
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
432
# win32 is inconsistent whether it returns lower or upper case
433
# and even if it was consistent the user might type the other
434
# so we force it to uppercase
435
# running python.exe under cmd.exe return capital C:\\
436
# running win32 python inside a cygwin shell returns lowercase
437
self.assertEqual(os_cwd[0].upper(), cwd[0])
439
def test_fixdrive(self):
440
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
441
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
442
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
444
def test_win98_abspath(self):
446
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
447
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
449
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
450
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
452
cwd = osutils.getcwd().rstrip('/')
453
drive = osutils._nt_splitdrive(cwd)[0]
454
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
455
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
458
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
461
class TestWin32FuncsDirs(TestCaseInTempDir):
462
"""Test win32 functions that create files."""
464
def test_getcwd(self):
465
if win32utils.winver == 'Windows 98':
466
raise TestSkipped('Windows 98 cannot handle unicode filenames')
467
# Make sure getcwd can handle unicode filenames
471
raise TestSkipped("Unable to create Unicode filename")
474
# TODO: jam 20060427 This will probably fail on Mac OSX because
475
# it will change the normalization of B\xe5gfors
476
# Consider using a different unicode character, or make
477
# osutils.getcwd() renormalize the path.
478
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
480
def test_mkdtemp(self):
481
tmpdir = osutils._win32_mkdtemp(dir='.')
482
self.assertFalse('\\' in tmpdir)
484
def test_rename(self):
492
osutils._win32_rename('b', 'a')
493
self.failUnlessExists('a')
494
self.failIfExists('b')
495
self.assertFileEqual('baz\n', 'a')
497
def test_rename_missing_file(self):
503
osutils._win32_rename('b', 'a')
504
except (IOError, OSError), e:
505
self.assertEqual(errno.ENOENT, e.errno)
506
self.assertFileEqual('foo\n', 'a')
508
def test_rename_missing_dir(self):
511
osutils._win32_rename('b', 'a')
512
except (IOError, OSError), e:
513
self.assertEqual(errno.ENOENT, e.errno)
515
def test_rename_current_dir(self):
518
# You can't rename the working directory
519
# doing rename non-existant . usually
520
# just raises ENOENT, since non-existant
523
osutils._win32_rename('b', '.')
524
except (IOError, OSError), e:
525
self.assertEqual(errno.ENOENT, e.errno)
527
def test_splitpath(self):
528
def check(expected, path):
529
self.assertEqual(expected, osutils.splitpath(path))
532
check(['a', 'b'], 'a/b')
533
check(['a', 'b'], 'a/./b')
534
check(['a', '.b'], 'a/.b')
535
check(['a', '.b'], 'a\\.b')
537
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
540
class TestMacFuncsDirs(TestCaseInTempDir):
541
"""Test mac special functions that require directories."""
543
def test_getcwd(self):
544
# On Mac, this will actually create Ba\u030agfors
545
# but chdir will still work, because it accepts both paths
547
os.mkdir(u'B\xe5gfors')
549
raise TestSkipped("Unable to create Unicode filename")
551
os.chdir(u'B\xe5gfors')
552
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
554
def test_getcwd_nonnorm(self):
555
# Test that _mac_getcwd() will normalize this path
557
os.mkdir(u'Ba\u030agfors')
559
raise TestSkipped("Unable to create Unicode filename")
561
os.chdir(u'Ba\u030agfors')
562
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
565
class TestSplitLines(TestCase):
567
def test_split_unicode(self):
568
self.assertEqual([u'foo\n', u'bar\xae'],
569
osutils.split_lines(u'foo\nbar\xae'))
570
self.assertEqual([u'foo\n', u'bar\xae\n'],
571
osutils.split_lines(u'foo\nbar\xae\n'))
573
def test_split_with_carriage_returns(self):
574
self.assertEqual(['foo\rbar\n'],
575
osutils.split_lines('foo\rbar\n'))
578
class TestWalkDirs(TestCaseInTempDir):
580
def test_walkdirs(self):
589
self.build_tree(tree)
590
expected_dirblocks = [
592
[('0file', '0file', 'file'),
593
('1dir', '1dir', 'directory'),
594
('2file', '2file', 'file'),
598
[('1dir/0file', '0file', 'file'),
599
('1dir/1dir', '1dir', 'directory'),
602
(('1dir/1dir', './1dir/1dir'),
609
for dirdetail, dirblock in osutils.walkdirs('.'):
610
if len(dirblock) and dirblock[0][1] == '.bzr':
611
# this tests the filtering of selected paths
614
result.append((dirdetail, dirblock))
616
self.assertTrue(found_bzrdir)
617
self.assertEqual(expected_dirblocks,
618
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
619
# you can search a subdir only, with a supplied prefix.
621
for dirblock in osutils.walkdirs('./1dir', '1dir'):
622
result.append(dirblock)
623
self.assertEqual(expected_dirblocks[1:],
624
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
626
def test__walkdirs_utf8(self):
635
self.build_tree(tree)
636
expected_dirblocks = [
638
[('0file', '0file', 'file'),
639
('1dir', '1dir', 'directory'),
640
('2file', '2file', 'file'),
644
[('1dir/0file', '0file', 'file'),
645
('1dir/1dir', '1dir', 'directory'),
648
(('1dir/1dir', './1dir/1dir'),
655
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
656
if len(dirblock) and dirblock[0][1] == '.bzr':
657
# this tests the filtering of selected paths
660
result.append((dirdetail, dirblock))
662
self.assertTrue(found_bzrdir)
663
self.assertEqual(expected_dirblocks,
664
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
665
# you can search a subdir only, with a supplied prefix.
667
for dirblock in osutils.walkdirs('./1dir', '1dir'):
668
result.append(dirblock)
669
self.assertEqual(expected_dirblocks[1:],
670
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
672
def _filter_out_stat(self, result):
673
"""Filter out the stat value from the walkdirs result"""
674
for dirdetail, dirblock in result:
676
for info in dirblock:
677
# Ignore info[3] which is the stat
678
new_dirblock.append((info[0], info[1], info[2], info[4]))
679
dirblock[:] = new_dirblock
681
def test_unicode_walkdirs(self):
682
"""Walkdirs should always return unicode paths."""
683
name0 = u'0file-\xb6'
684
name1 = u'1dir-\u062c\u0648'
685
name2 = u'2file-\u0633'
690
name1 + '/' + name1 + '/',
694
self.build_tree(tree)
696
raise TestSkipped('Could not represent Unicode chars'
697
' in current encoding.')
698
expected_dirblocks = [
700
[(name0, name0, 'file', './' + name0),
701
(name1, name1, 'directory', './' + name1),
702
(name2, name2, 'file', './' + name2),
705
((name1, './' + name1),
706
[(name1 + '/' + name0, name0, 'file', './' + name1
708
(name1 + '/' + name1, name1, 'directory', './' + name1
712
((name1 + '/' + name1, './' + name1 + '/' + name1),
717
result = list(osutils.walkdirs('.'))
718
self._filter_out_stat(result)
719
self.assertEqual(expected_dirblocks, result)
720
result = list(osutils.walkdirs(u'./'+name1, name1))
721
self._filter_out_stat(result)
722
self.assertEqual(expected_dirblocks[1:], result)
724
def test_unicode__walkdirs_utf8(self):
725
"""Walkdirs_utf8 should always return utf8 paths.
727
The abspath portion might be in unicode or utf-8
729
name0 = u'0file-\xb6'
730
name1 = u'1dir-\u062c\u0648'
731
name2 = u'2file-\u0633'
736
name1 + '/' + name1 + '/',
740
self.build_tree(tree)
742
raise TestSkipped('Could not represent Unicode chars'
743
' in current encoding.')
744
name0 = name0.encode('utf8')
745
name1 = name1.encode('utf8')
746
name2 = name2.encode('utf8')
748
expected_dirblocks = [
750
[(name0, name0, 'file', './' + name0),
751
(name1, name1, 'directory', './' + name1),
752
(name2, name2, 'file', './' + name2),
755
((name1, './' + name1),
756
[(name1 + '/' + name0, name0, 'file', './' + name1
758
(name1 + '/' + name1, name1, 'directory', './' + name1
762
((name1 + '/' + name1, './' + name1 + '/' + name1),
768
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
769
# all abspaths are Unicode, and encode them back into utf8.
770
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
771
self.assertIsInstance(dirdetail[0], str)
772
if isinstance(dirdetail[1], unicode):
773
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
774
dirblock = [list(info) for info in dirblock]
775
for info in dirblock:
776
self.assertIsInstance(info[4], unicode)
777
info[4] = info[4].encode('utf8')
779
for info in dirblock:
780
self.assertIsInstance(info[0], str)
781
self.assertIsInstance(info[1], str)
782
self.assertIsInstance(info[4], str)
783
# Remove the stat information
784
new_dirblock.append((info[0], info[1], info[2], info[4]))
785
result.append((dirdetail, new_dirblock))
786
self.assertEqual(expected_dirblocks, result)
788
def test_unicode__walkdirs_unicode_to_utf8(self):
789
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
791
The abspath portion should be in unicode
793
name0u = u'0file-\xb6'
794
name1u = u'1dir-\u062c\u0648'
795
name2u = u'2file-\u0633'
799
name1u + '/' + name0u,
800
name1u + '/' + name1u + '/',
804
self.build_tree(tree)
806
raise TestSkipped('Could not represent Unicode chars'
807
' in current encoding.')
808
name0 = name0u.encode('utf8')
809
name1 = name1u.encode('utf8')
810
name2 = name2u.encode('utf8')
812
# All of the abspaths should be in unicode, all of the relative paths
814
expected_dirblocks = [
816
[(name0, name0, 'file', './' + name0u),
817
(name1, name1, 'directory', './' + name1u),
818
(name2, name2, 'file', './' + name2u),
821
((name1, './' + name1u),
822
[(name1 + '/' + name0, name0, 'file', './' + name1u
824
(name1 + '/' + name1, name1, 'directory', './' + name1u
828
((name1 + '/' + name1, './' + name1u + '/' + name1u),
833
result = list(osutils._walkdirs_unicode_to_utf8('.'))
834
self._filter_out_stat(result)
835
self.assertEqual(expected_dirblocks, result)
837
def assertPathCompare(self, path_less, path_greater):
838
"""check that path_less and path_greater compare correctly."""
839
self.assertEqual(0, osutils.compare_paths_prefix_order(
840
path_less, path_less))
841
self.assertEqual(0, osutils.compare_paths_prefix_order(
842
path_greater, path_greater))
843
self.assertEqual(-1, osutils.compare_paths_prefix_order(
844
path_less, path_greater))
845
self.assertEqual(1, osutils.compare_paths_prefix_order(
846
path_greater, path_less))
848
def test_compare_paths_prefix_order(self):
849
# root before all else
850
self.assertPathCompare("/", "/a")
852
self.assertPathCompare("/a", "/b")
853
self.assertPathCompare("/b", "/z")
854
# high dirs before lower.
855
self.assertPathCompare("/z", "/a/a")
856
# except if the deeper dir should be output first
857
self.assertPathCompare("/a/b/c", "/d/g")
858
# lexical betwen dirs of the same height
859
self.assertPathCompare("/a/z", "/z/z")
860
self.assertPathCompare("/a/c/z", "/a/d/e")
862
# this should also be consistent for no leading / paths
863
# root before all else
864
self.assertPathCompare("", "a")
866
self.assertPathCompare("a", "b")
867
self.assertPathCompare("b", "z")
868
# high dirs before lower.
869
self.assertPathCompare("z", "a/a")
870
# except if the deeper dir should be output first
871
self.assertPathCompare("a/b/c", "d/g")
872
# lexical betwen dirs of the same height
873
self.assertPathCompare("a/z", "z/z")
874
self.assertPathCompare("a/c/z", "a/d/e")
876
def test_path_prefix_sorting(self):
877
"""Doing a sort on path prefix should match our sample data."""
908
sorted(original_paths, key=osutils.path_prefix_key))
909
# using the comparison routine shoudl work too:
912
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
915
class TestCopyTree(TestCaseInTempDir):
917
def test_copy_basic_tree(self):
918
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
919
osutils.copy_tree('source', 'target')
920
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
921
self.assertEqual(['c'], os.listdir('target/b'))
923
def test_copy_tree_target_exists(self):
924
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
926
osutils.copy_tree('source', 'target')
927
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
928
self.assertEqual(['c'], os.listdir('target/b'))
930
def test_copy_tree_symlinks(self):
931
if not osutils.has_symlinks():
933
self.build_tree(['source/'])
934
os.symlink('a/generic/path', 'source/lnk')
935
osutils.copy_tree('source', 'target')
936
self.assertEqual(['lnk'], os.listdir('target'))
937
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
939
def test_copy_tree_handlers(self):
942
def file_handler(from_path, to_path):
943
processed_files.append(('f', from_path, to_path))
944
def dir_handler(from_path, to_path):
945
processed_files.append(('d', from_path, to_path))
946
def link_handler(from_path, to_path):
947
processed_links.append((from_path, to_path))
948
handlers = {'file':file_handler,
949
'directory':dir_handler,
950
'symlink':link_handler,
953
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
954
if osutils.has_symlinks():
955
os.symlink('a/generic/path', 'source/lnk')
956
osutils.copy_tree('source', 'target', handlers=handlers)
958
self.assertEqual([('d', 'source', 'target'),
959
('f', 'source/a', 'target/a'),
960
('d', 'source/b', 'target/b'),
961
('f', 'source/b/c', 'target/b/c'),
963
self.failIfExists('target')
964
if osutils.has_symlinks():
965
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
968
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
969
# [bialix] 2006/12/26
972
class TestSetUnsetEnv(TestCase):
973
"""Test updating the environment"""
976
super(TestSetUnsetEnv, self).setUp()
978
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
979
'Environment was not cleaned up properly.'
980
' Variable BZR_TEST_ENV_VAR should not exist.')
982
if 'BZR_TEST_ENV_VAR' in os.environ:
983
del os.environ['BZR_TEST_ENV_VAR']
985
self.addCleanup(cleanup)
988
"""Test that we can set an env variable"""
989
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
990
self.assertEqual(None, old)
991
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
993
def test_double_set(self):
994
"""Test that we get the old value out"""
995
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
996
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
997
self.assertEqual('foo', old)
998
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1000
def test_unicode(self):
1001
"""Environment can only contain plain strings
1003
So Unicode strings must be encoded.
1005
uni_val, env_val = probe_unicode_in_user_encoding()
1007
raise TestSkipped('Cannot find a unicode character that works in'
1008
' encoding %s' % (bzrlib.user_encoding,))
1010
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1011
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1013
def test_unset(self):
1014
"""Test that passing None will remove the env var"""
1015
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1016
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1017
self.assertEqual('foo', old)
1018
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1019
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1022
class TestLocalTimeOffset(TestCase):
1024
def test_local_time_offset(self):
1025
"""Test that local_time_offset() returns a sane value."""
1026
offset = osutils.local_time_offset()
1027
self.assertTrue(isinstance(offset, int))
1028
# Test that the offset is no more than a eighteen hours in
1030
# Time zone handling is system specific, so it is difficult to
1031
# do more specific tests, but a value outside of this range is
1033
eighteen_hours = 18 * 3600
1034
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1036
def test_local_time_offset_with_timestamp(self):
1037
"""Test that local_time_offset() works with a timestamp."""
1038
offset = osutils.local_time_offset(1000000000.1234567)
1039
self.assertTrue(isinstance(offset, int))
1040
eighteen_hours = 18 * 3600
1041
self.assertTrue(-eighteen_hours < offset < eighteen_hours)