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
# this shouldn't give a warning because it's getting an ascii string
354
self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
356
def test_from_unicode_string_ascii_contents(self):
357
self.assertEqual('bargam',
358
osutils.safe_revision_id(u'bargam', warn=False))
360
def test_from_unicode_deprecated(self):
361
self.assertEqual('bargam',
362
self.callDeprecated([osutils._revision_id_warning],
363
osutils.safe_revision_id, u'bargam'))
365
def test_from_unicode_string_unicode_contents(self):
366
self.assertEqual('bargam\xc2\xae',
367
osutils.safe_revision_id(u'bargam\xae', warn=False))
369
def test_from_utf8_string(self):
370
self.assertEqual('foo\xc2\xae',
371
osutils.safe_revision_id('foo\xc2\xae'))
374
"""Currently, None is a valid revision_id"""
375
self.assertEqual(None, osutils.safe_revision_id(None))
378
class TestSafeFileId(TestCase):
380
def test_from_ascii_string(self):
381
self.assertEqual('foobar', osutils.safe_file_id('foobar'))
383
def test_from_unicode_string_ascii_contents(self):
384
self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
386
def test_from_unicode_deprecated(self):
387
self.assertEqual('bargam',
388
self.callDeprecated([osutils._file_id_warning],
389
osutils.safe_file_id, u'bargam'))
391
def test_from_unicode_string_unicode_contents(self):
392
self.assertEqual('bargam\xc2\xae',
393
osutils.safe_file_id(u'bargam\xae', warn=False))
395
def test_from_utf8_string(self):
396
self.assertEqual('foo\xc2\xae',
397
osutils.safe_file_id('foo\xc2\xae'))
400
"""Currently, None is a valid revision_id"""
401
self.assertEqual(None, osutils.safe_file_id(None))
404
class TestWin32Funcs(TestCase):
405
"""Test that the _win32 versions of os utilities return appropriate paths."""
407
def test_abspath(self):
408
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
409
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
410
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
411
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
413
def test_realpath(self):
414
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
415
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
417
def test_pathjoin(self):
418
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
419
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
420
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
421
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
422
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
423
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
425
def test_normpath(self):
426
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
427
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
429
def test_getcwd(self):
430
cwd = osutils._win32_getcwd()
431
os_cwd = os.getcwdu()
432
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
433
# win32 is inconsistent whether it returns lower or upper case
434
# and even if it was consistent the user might type the other
435
# so we force it to uppercase
436
# running python.exe under cmd.exe return capital C:\\
437
# running win32 python inside a cygwin shell returns lowercase
438
self.assertEqual(os_cwd[0].upper(), cwd[0])
440
def test_fixdrive(self):
441
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
442
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
443
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
445
def test_win98_abspath(self):
447
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
448
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
450
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
451
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
453
cwd = osutils.getcwd().rstrip('/')
454
drive = osutils._nt_splitdrive(cwd)[0]
455
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
456
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
459
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
462
class TestWin32FuncsDirs(TestCaseInTempDir):
463
"""Test win32 functions that create files."""
465
def test_getcwd(self):
466
if win32utils.winver == 'Windows 98':
467
raise TestSkipped('Windows 98 cannot handle unicode filenames')
468
# Make sure getcwd can handle unicode filenames
472
raise TestSkipped("Unable to create Unicode filename")
475
# TODO: jam 20060427 This will probably fail on Mac OSX because
476
# it will change the normalization of B\xe5gfors
477
# Consider using a different unicode character, or make
478
# osutils.getcwd() renormalize the path.
479
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
481
def test_minimum_path_selection(self):
482
self.assertEqual(set(),
483
osutils.minimum_path_selection([]))
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/', 'b']))
488
self.assertEqual(set(['a/', 'b']),
489
osutils.minimum_path_selection(['a/c', 'a/', 'b']))
491
def test_mkdtemp(self):
492
tmpdir = osutils._win32_mkdtemp(dir='.')
493
self.assertFalse('\\' in tmpdir)
495
def test_rename(self):
503
osutils._win32_rename('b', 'a')
504
self.failUnlessExists('a')
505
self.failIfExists('b')
506
self.assertFileEqual('baz\n', 'a')
508
def test_rename_missing_file(self):
514
osutils._win32_rename('b', 'a')
515
except (IOError, OSError), e:
516
self.assertEqual(errno.ENOENT, e.errno)
517
self.assertFileEqual('foo\n', 'a')
519
def test_rename_missing_dir(self):
522
osutils._win32_rename('b', 'a')
523
except (IOError, OSError), e:
524
self.assertEqual(errno.ENOENT, e.errno)
526
def test_rename_current_dir(self):
529
# You can't rename the working directory
530
# doing rename non-existant . usually
531
# just raises ENOENT, since non-existant
534
osutils._win32_rename('b', '.')
535
except (IOError, OSError), e:
536
self.assertEqual(errno.ENOENT, e.errno)
538
def test_splitpath(self):
539
def check(expected, path):
540
self.assertEqual(expected, osutils.splitpath(path))
543
check(['a', 'b'], 'a/b')
544
check(['a', 'b'], 'a/./b')
545
check(['a', '.b'], 'a/.b')
546
check(['a', '.b'], 'a\\.b')
548
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
551
class TestMacFuncsDirs(TestCaseInTempDir):
552
"""Test mac special functions that require directories."""
554
def test_getcwd(self):
555
# On Mac, this will actually create Ba\u030agfors
556
# but chdir will still work, because it accepts both paths
558
os.mkdir(u'B\xe5gfors')
560
raise TestSkipped("Unable to create Unicode filename")
562
os.chdir(u'B\xe5gfors')
563
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
565
def test_getcwd_nonnorm(self):
566
# Test that _mac_getcwd() will normalize this path
568
os.mkdir(u'Ba\u030agfors')
570
raise TestSkipped("Unable to create Unicode filename")
572
os.chdir(u'Ba\u030agfors')
573
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
576
class TestSplitLines(TestCase):
578
def test_split_unicode(self):
579
self.assertEqual([u'foo\n', u'bar\xae'],
580
osutils.split_lines(u'foo\nbar\xae'))
581
self.assertEqual([u'foo\n', u'bar\xae\n'],
582
osutils.split_lines(u'foo\nbar\xae\n'))
584
def test_split_with_carriage_returns(self):
585
self.assertEqual(['foo\rbar\n'],
586
osutils.split_lines('foo\rbar\n'))
589
class TestWalkDirs(TestCaseInTempDir):
591
def test_walkdirs(self):
600
self.build_tree(tree)
601
expected_dirblocks = [
603
[('0file', '0file', 'file'),
604
('1dir', '1dir', 'directory'),
605
('2file', '2file', 'file'),
609
[('1dir/0file', '0file', 'file'),
610
('1dir/1dir', '1dir', 'directory'),
613
(('1dir/1dir', './1dir/1dir'),
620
for dirdetail, dirblock in osutils.walkdirs('.'):
621
if len(dirblock) and dirblock[0][1] == '.bzr':
622
# this tests the filtering of selected paths
625
result.append((dirdetail, dirblock))
627
self.assertTrue(found_bzrdir)
628
self.assertEqual(expected_dirblocks,
629
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
630
# you can search a subdir only, with a supplied prefix.
632
for dirblock in osutils.walkdirs('./1dir', '1dir'):
633
result.append(dirblock)
634
self.assertEqual(expected_dirblocks[1:],
635
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
637
def test__walkdirs_utf8(self):
646
self.build_tree(tree)
647
expected_dirblocks = [
649
[('0file', '0file', 'file'),
650
('1dir', '1dir', 'directory'),
651
('2file', '2file', 'file'),
655
[('1dir/0file', '0file', 'file'),
656
('1dir/1dir', '1dir', 'directory'),
659
(('1dir/1dir', './1dir/1dir'),
666
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
667
if len(dirblock) and dirblock[0][1] == '.bzr':
668
# this tests the filtering of selected paths
671
result.append((dirdetail, dirblock))
673
self.assertTrue(found_bzrdir)
674
self.assertEqual(expected_dirblocks,
675
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
676
# you can search a subdir only, with a supplied prefix.
678
for dirblock in osutils.walkdirs('./1dir', '1dir'):
679
result.append(dirblock)
680
self.assertEqual(expected_dirblocks[1:],
681
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
683
def _filter_out_stat(self, result):
684
"""Filter out the stat value from the walkdirs result"""
685
for dirdetail, dirblock in result:
687
for info in dirblock:
688
# Ignore info[3] which is the stat
689
new_dirblock.append((info[0], info[1], info[2], info[4]))
690
dirblock[:] = new_dirblock
692
def test_unicode_walkdirs(self):
693
"""Walkdirs should always return unicode paths."""
694
name0 = u'0file-\xb6'
695
name1 = u'1dir-\u062c\u0648'
696
name2 = u'2file-\u0633'
701
name1 + '/' + name1 + '/',
705
self.build_tree(tree)
707
raise TestSkipped('Could not represent Unicode chars'
708
' in current encoding.')
709
expected_dirblocks = [
711
[(name0, name0, 'file', './' + name0),
712
(name1, name1, 'directory', './' + name1),
713
(name2, name2, 'file', './' + name2),
716
((name1, './' + name1),
717
[(name1 + '/' + name0, name0, 'file', './' + name1
719
(name1 + '/' + name1, name1, 'directory', './' + name1
723
((name1 + '/' + name1, './' + name1 + '/' + name1),
728
result = list(osutils.walkdirs('.'))
729
self._filter_out_stat(result)
730
self.assertEqual(expected_dirblocks, result)
731
result = list(osutils.walkdirs(u'./'+name1, name1))
732
self._filter_out_stat(result)
733
self.assertEqual(expected_dirblocks[1:], result)
735
def test_unicode__walkdirs_utf8(self):
736
"""Walkdirs_utf8 should always return utf8 paths.
738
The abspath portion might be in unicode or utf-8
740
name0 = u'0file-\xb6'
741
name1 = u'1dir-\u062c\u0648'
742
name2 = u'2file-\u0633'
747
name1 + '/' + name1 + '/',
751
self.build_tree(tree)
753
raise TestSkipped('Could not represent Unicode chars'
754
' in current encoding.')
755
name0 = name0.encode('utf8')
756
name1 = name1.encode('utf8')
757
name2 = name2.encode('utf8')
759
expected_dirblocks = [
761
[(name0, name0, 'file', './' + name0),
762
(name1, name1, 'directory', './' + name1),
763
(name2, name2, 'file', './' + name2),
766
((name1, './' + name1),
767
[(name1 + '/' + name0, name0, 'file', './' + name1
769
(name1 + '/' + name1, name1, 'directory', './' + name1
773
((name1 + '/' + name1, './' + name1 + '/' + name1),
779
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
780
# all abspaths are Unicode, and encode them back into utf8.
781
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
782
self.assertIsInstance(dirdetail[0], str)
783
if isinstance(dirdetail[1], unicode):
784
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
785
dirblock = [list(info) for info in dirblock]
786
for info in dirblock:
787
self.assertIsInstance(info[4], unicode)
788
info[4] = info[4].encode('utf8')
790
for info in dirblock:
791
self.assertIsInstance(info[0], str)
792
self.assertIsInstance(info[1], str)
793
self.assertIsInstance(info[4], str)
794
# Remove the stat information
795
new_dirblock.append((info[0], info[1], info[2], info[4]))
796
result.append((dirdetail, new_dirblock))
797
self.assertEqual(expected_dirblocks, result)
799
def test_unicode__walkdirs_unicode_to_utf8(self):
800
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
802
The abspath portion should be in unicode
804
name0u = u'0file-\xb6'
805
name1u = u'1dir-\u062c\u0648'
806
name2u = u'2file-\u0633'
810
name1u + '/' + name0u,
811
name1u + '/' + name1u + '/',
815
self.build_tree(tree)
817
raise TestSkipped('Could not represent Unicode chars'
818
' in current encoding.')
819
name0 = name0u.encode('utf8')
820
name1 = name1u.encode('utf8')
821
name2 = name2u.encode('utf8')
823
# All of the abspaths should be in unicode, all of the relative paths
825
expected_dirblocks = [
827
[(name0, name0, 'file', './' + name0u),
828
(name1, name1, 'directory', './' + name1u),
829
(name2, name2, 'file', './' + name2u),
832
((name1, './' + name1u),
833
[(name1 + '/' + name0, name0, 'file', './' + name1u
835
(name1 + '/' + name1, name1, 'directory', './' + name1u
839
((name1 + '/' + name1, './' + name1u + '/' + name1u),
844
result = list(osutils._walkdirs_unicode_to_utf8('.'))
845
self._filter_out_stat(result)
846
self.assertEqual(expected_dirblocks, result)
848
def assertPathCompare(self, path_less, path_greater):
849
"""check that path_less and path_greater compare correctly."""
850
self.assertEqual(0, osutils.compare_paths_prefix_order(
851
path_less, path_less))
852
self.assertEqual(0, osutils.compare_paths_prefix_order(
853
path_greater, path_greater))
854
self.assertEqual(-1, osutils.compare_paths_prefix_order(
855
path_less, path_greater))
856
self.assertEqual(1, osutils.compare_paths_prefix_order(
857
path_greater, path_less))
859
def test_compare_paths_prefix_order(self):
860
# root before all else
861
self.assertPathCompare("/", "/a")
863
self.assertPathCompare("/a", "/b")
864
self.assertPathCompare("/b", "/z")
865
# high dirs before lower.
866
self.assertPathCompare("/z", "/a/a")
867
# except if the deeper dir should be output first
868
self.assertPathCompare("/a/b/c", "/d/g")
869
# lexical betwen dirs of the same height
870
self.assertPathCompare("/a/z", "/z/z")
871
self.assertPathCompare("/a/c/z", "/a/d/e")
873
# this should also be consistent for no leading / paths
874
# root before all else
875
self.assertPathCompare("", "a")
877
self.assertPathCompare("a", "b")
878
self.assertPathCompare("b", "z")
879
# high dirs before lower.
880
self.assertPathCompare("z", "a/a")
881
# except if the deeper dir should be output first
882
self.assertPathCompare("a/b/c", "d/g")
883
# lexical betwen dirs of the same height
884
self.assertPathCompare("a/z", "z/z")
885
self.assertPathCompare("a/c/z", "a/d/e")
887
def test_path_prefix_sorting(self):
888
"""Doing a sort on path prefix should match our sample data."""
919
sorted(original_paths, key=osutils.path_prefix_key))
920
# using the comparison routine shoudl work too:
923
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
926
class TestCopyTree(TestCaseInTempDir):
928
def test_copy_basic_tree(self):
929
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
930
osutils.copy_tree('source', 'target')
931
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
932
self.assertEqual(['c'], os.listdir('target/b'))
934
def test_copy_tree_target_exists(self):
935
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
937
osutils.copy_tree('source', 'target')
938
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
939
self.assertEqual(['c'], os.listdir('target/b'))
941
def test_copy_tree_symlinks(self):
942
if not osutils.has_symlinks():
944
self.build_tree(['source/'])
945
os.symlink('a/generic/path', 'source/lnk')
946
osutils.copy_tree('source', 'target')
947
self.assertEqual(['lnk'], os.listdir('target'))
948
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
950
def test_copy_tree_handlers(self):
953
def file_handler(from_path, to_path):
954
processed_files.append(('f', from_path, to_path))
955
def dir_handler(from_path, to_path):
956
processed_files.append(('d', from_path, to_path))
957
def link_handler(from_path, to_path):
958
processed_links.append((from_path, to_path))
959
handlers = {'file':file_handler,
960
'directory':dir_handler,
961
'symlink':link_handler,
964
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
965
if osutils.has_symlinks():
966
os.symlink('a/generic/path', 'source/lnk')
967
osutils.copy_tree('source', 'target', handlers=handlers)
969
self.assertEqual([('d', 'source', 'target'),
970
('f', 'source/a', 'target/a'),
971
('d', 'source/b', 'target/b'),
972
('f', 'source/b/c', 'target/b/c'),
974
self.failIfExists('target')
975
if osutils.has_symlinks():
976
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
979
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
980
# [bialix] 2006/12/26
983
class TestSetUnsetEnv(TestCase):
984
"""Test updating the environment"""
987
super(TestSetUnsetEnv, self).setUp()
989
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
990
'Environment was not cleaned up properly.'
991
' Variable BZR_TEST_ENV_VAR should not exist.')
993
if 'BZR_TEST_ENV_VAR' in os.environ:
994
del os.environ['BZR_TEST_ENV_VAR']
996
self.addCleanup(cleanup)
999
"""Test that we can set an env variable"""
1000
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1001
self.assertEqual(None, old)
1002
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
1004
def test_double_set(self):
1005
"""Test that we get the old value out"""
1006
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1007
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
1008
self.assertEqual('foo', old)
1009
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1011
def test_unicode(self):
1012
"""Environment can only contain plain strings
1014
So Unicode strings must be encoded.
1016
uni_val, env_val = probe_unicode_in_user_encoding()
1018
raise TestSkipped('Cannot find a unicode character that works in'
1019
' encoding %s' % (bzrlib.user_encoding,))
1021
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1022
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1024
def test_unset(self):
1025
"""Test that passing None will remove the env var"""
1026
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1027
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1028
self.assertEqual('foo', old)
1029
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1030
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1033
class TestLocalTimeOffset(TestCase):
1035
def test_local_time_offset(self):
1036
"""Test that local_time_offset() returns a sane value."""
1037
offset = osutils.local_time_offset()
1038
self.assertTrue(isinstance(offset, int))
1039
# Test that the offset is no more than a eighteen hours in
1041
# Time zone handling is system specific, so it is difficult to
1042
# do more specific tests, but a value outside of this range is
1044
eighteen_hours = 18 * 3600
1045
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1047
def test_local_time_offset_with_timestamp(self):
1048
"""Test that local_time_offset() works with a timestamp."""
1049
offset = osutils.local_time_offset(1000000000.1234567)
1050
self.assertTrue(isinstance(offset, int))
1051
eighteen_hours = 18 * 3600
1052
self.assertTrue(-eighteen_hours < offset < eighteen_hours)