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_minimum_path_selection(self):
481
self.assertEqual(set(),
482
osutils.minimum_path_selection([]))
483
self.assertEqual(set(['a', 'b']),
484
osutils.minimum_path_selection(['a', 'b']))
485
self.assertEqual(set(['a/', 'b']),
486
osutils.minimum_path_selection(['a/', 'b']))
487
self.assertEqual(set(['a/', 'b']),
488
osutils.minimum_path_selection(['a/c', 'a/', 'b']))
490
def test_mkdtemp(self):
491
tmpdir = osutils._win32_mkdtemp(dir='.')
492
self.assertFalse('\\' in tmpdir)
494
def test_rename(self):
502
osutils._win32_rename('b', 'a')
503
self.failUnlessExists('a')
504
self.failIfExists('b')
505
self.assertFileEqual('baz\n', 'a')
507
def test_rename_missing_file(self):
513
osutils._win32_rename('b', 'a')
514
except (IOError, OSError), e:
515
self.assertEqual(errno.ENOENT, e.errno)
516
self.assertFileEqual('foo\n', 'a')
518
def test_rename_missing_dir(self):
521
osutils._win32_rename('b', 'a')
522
except (IOError, OSError), e:
523
self.assertEqual(errno.ENOENT, e.errno)
525
def test_rename_current_dir(self):
528
# You can't rename the working directory
529
# doing rename non-existant . usually
530
# just raises ENOENT, since non-existant
533
osutils._win32_rename('b', '.')
534
except (IOError, OSError), e:
535
self.assertEqual(errno.ENOENT, e.errno)
537
def test_splitpath(self):
538
def check(expected, path):
539
self.assertEqual(expected, osutils.splitpath(path))
542
check(['a', 'b'], 'a/b')
543
check(['a', 'b'], 'a/./b')
544
check(['a', '.b'], 'a/.b')
545
check(['a', '.b'], 'a\\.b')
547
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
550
class TestMacFuncsDirs(TestCaseInTempDir):
551
"""Test mac special functions that require directories."""
553
def test_getcwd(self):
554
# On Mac, this will actually create Ba\u030agfors
555
# but chdir will still work, because it accepts both paths
557
os.mkdir(u'B\xe5gfors')
559
raise TestSkipped("Unable to create Unicode filename")
561
os.chdir(u'B\xe5gfors')
562
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
564
def test_getcwd_nonnorm(self):
565
# Test that _mac_getcwd() will normalize this path
567
os.mkdir(u'Ba\u030agfors')
569
raise TestSkipped("Unable to create Unicode filename")
571
os.chdir(u'Ba\u030agfors')
572
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
575
class TestSplitLines(TestCase):
577
def test_split_unicode(self):
578
self.assertEqual([u'foo\n', u'bar\xae'],
579
osutils.split_lines(u'foo\nbar\xae'))
580
self.assertEqual([u'foo\n', u'bar\xae\n'],
581
osutils.split_lines(u'foo\nbar\xae\n'))
583
def test_split_with_carriage_returns(self):
584
self.assertEqual(['foo\rbar\n'],
585
osutils.split_lines('foo\rbar\n'))
588
class TestWalkDirs(TestCaseInTempDir):
590
def test_walkdirs(self):
599
self.build_tree(tree)
600
expected_dirblocks = [
602
[('0file', '0file', 'file'),
603
('1dir', '1dir', 'directory'),
604
('2file', '2file', 'file'),
608
[('1dir/0file', '0file', 'file'),
609
('1dir/1dir', '1dir', 'directory'),
612
(('1dir/1dir', './1dir/1dir'),
619
for dirdetail, dirblock in osutils.walkdirs('.'):
620
if len(dirblock) and dirblock[0][1] == '.bzr':
621
# this tests the filtering of selected paths
624
result.append((dirdetail, dirblock))
626
self.assertTrue(found_bzrdir)
627
self.assertEqual(expected_dirblocks,
628
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
629
# you can search a subdir only, with a supplied prefix.
631
for dirblock in osutils.walkdirs('./1dir', '1dir'):
632
result.append(dirblock)
633
self.assertEqual(expected_dirblocks[1:],
634
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
636
def test__walkdirs_utf8(self):
645
self.build_tree(tree)
646
expected_dirblocks = [
648
[('0file', '0file', 'file'),
649
('1dir', '1dir', 'directory'),
650
('2file', '2file', 'file'),
654
[('1dir/0file', '0file', 'file'),
655
('1dir/1dir', '1dir', 'directory'),
658
(('1dir/1dir', './1dir/1dir'),
665
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
666
if len(dirblock) and dirblock[0][1] == '.bzr':
667
# this tests the filtering of selected paths
670
result.append((dirdetail, dirblock))
672
self.assertTrue(found_bzrdir)
673
self.assertEqual(expected_dirblocks,
674
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
675
# you can search a subdir only, with a supplied prefix.
677
for dirblock in osutils.walkdirs('./1dir', '1dir'):
678
result.append(dirblock)
679
self.assertEqual(expected_dirblocks[1:],
680
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
682
def _filter_out_stat(self, result):
683
"""Filter out the stat value from the walkdirs result"""
684
for dirdetail, dirblock in result:
686
for info in dirblock:
687
# Ignore info[3] which is the stat
688
new_dirblock.append((info[0], info[1], info[2], info[4]))
689
dirblock[:] = new_dirblock
691
def test_unicode_walkdirs(self):
692
"""Walkdirs should always return unicode paths."""
693
name0 = u'0file-\xb6'
694
name1 = u'1dir-\u062c\u0648'
695
name2 = u'2file-\u0633'
700
name1 + '/' + name1 + '/',
704
self.build_tree(tree)
706
raise TestSkipped('Could not represent Unicode chars'
707
' in current encoding.')
708
expected_dirblocks = [
710
[(name0, name0, 'file', './' + name0),
711
(name1, name1, 'directory', './' + name1),
712
(name2, name2, 'file', './' + name2),
715
((name1, './' + name1),
716
[(name1 + '/' + name0, name0, 'file', './' + name1
718
(name1 + '/' + name1, name1, 'directory', './' + name1
722
((name1 + '/' + name1, './' + name1 + '/' + name1),
727
result = list(osutils.walkdirs('.'))
728
self._filter_out_stat(result)
729
self.assertEqual(expected_dirblocks, result)
730
result = list(osutils.walkdirs(u'./'+name1, name1))
731
self._filter_out_stat(result)
732
self.assertEqual(expected_dirblocks[1:], result)
734
def test_unicode__walkdirs_utf8(self):
735
"""Walkdirs_utf8 should always return utf8 paths.
737
The abspath portion might be in unicode or utf-8
739
name0 = u'0file-\xb6'
740
name1 = u'1dir-\u062c\u0648'
741
name2 = u'2file-\u0633'
746
name1 + '/' + name1 + '/',
750
self.build_tree(tree)
752
raise TestSkipped('Could not represent Unicode chars'
753
' in current encoding.')
754
name0 = name0.encode('utf8')
755
name1 = name1.encode('utf8')
756
name2 = name2.encode('utf8')
758
expected_dirblocks = [
760
[(name0, name0, 'file', './' + name0),
761
(name1, name1, 'directory', './' + name1),
762
(name2, name2, 'file', './' + name2),
765
((name1, './' + name1),
766
[(name1 + '/' + name0, name0, 'file', './' + name1
768
(name1 + '/' + name1, name1, 'directory', './' + name1
772
((name1 + '/' + name1, './' + name1 + '/' + name1),
778
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
779
# all abspaths are Unicode, and encode them back into utf8.
780
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
781
self.assertIsInstance(dirdetail[0], str)
782
if isinstance(dirdetail[1], unicode):
783
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
784
dirblock = [list(info) for info in dirblock]
785
for info in dirblock:
786
self.assertIsInstance(info[4], unicode)
787
info[4] = info[4].encode('utf8')
789
for info in dirblock:
790
self.assertIsInstance(info[0], str)
791
self.assertIsInstance(info[1], str)
792
self.assertIsInstance(info[4], str)
793
# Remove the stat information
794
new_dirblock.append((info[0], info[1], info[2], info[4]))
795
result.append((dirdetail, new_dirblock))
796
self.assertEqual(expected_dirblocks, result)
798
def test_unicode__walkdirs_unicode_to_utf8(self):
799
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
801
The abspath portion should be in unicode
803
name0u = u'0file-\xb6'
804
name1u = u'1dir-\u062c\u0648'
805
name2u = u'2file-\u0633'
809
name1u + '/' + name0u,
810
name1u + '/' + name1u + '/',
814
self.build_tree(tree)
816
raise TestSkipped('Could not represent Unicode chars'
817
' in current encoding.')
818
name0 = name0u.encode('utf8')
819
name1 = name1u.encode('utf8')
820
name2 = name2u.encode('utf8')
822
# All of the abspaths should be in unicode, all of the relative paths
824
expected_dirblocks = [
826
[(name0, name0, 'file', './' + name0u),
827
(name1, name1, 'directory', './' + name1u),
828
(name2, name2, 'file', './' + name2u),
831
((name1, './' + name1u),
832
[(name1 + '/' + name0, name0, 'file', './' + name1u
834
(name1 + '/' + name1, name1, 'directory', './' + name1u
838
((name1 + '/' + name1, './' + name1u + '/' + name1u),
843
result = list(osutils._walkdirs_unicode_to_utf8('.'))
844
self._filter_out_stat(result)
845
self.assertEqual(expected_dirblocks, result)
847
def assertPathCompare(self, path_less, path_greater):
848
"""check that path_less and path_greater compare correctly."""
849
self.assertEqual(0, osutils.compare_paths_prefix_order(
850
path_less, path_less))
851
self.assertEqual(0, osutils.compare_paths_prefix_order(
852
path_greater, path_greater))
853
self.assertEqual(-1, osutils.compare_paths_prefix_order(
854
path_less, path_greater))
855
self.assertEqual(1, osutils.compare_paths_prefix_order(
856
path_greater, path_less))
858
def test_compare_paths_prefix_order(self):
859
# root before all else
860
self.assertPathCompare("/", "/a")
862
self.assertPathCompare("/a", "/b")
863
self.assertPathCompare("/b", "/z")
864
# high dirs before lower.
865
self.assertPathCompare("/z", "/a/a")
866
# except if the deeper dir should be output first
867
self.assertPathCompare("/a/b/c", "/d/g")
868
# lexical betwen dirs of the same height
869
self.assertPathCompare("/a/z", "/z/z")
870
self.assertPathCompare("/a/c/z", "/a/d/e")
872
# this should also be consistent for no leading / paths
873
# root before all else
874
self.assertPathCompare("", "a")
876
self.assertPathCompare("a", "b")
877
self.assertPathCompare("b", "z")
878
# high dirs before lower.
879
self.assertPathCompare("z", "a/a")
880
# except if the deeper dir should be output first
881
self.assertPathCompare("a/b/c", "d/g")
882
# lexical betwen dirs of the same height
883
self.assertPathCompare("a/z", "z/z")
884
self.assertPathCompare("a/c/z", "a/d/e")
886
def test_path_prefix_sorting(self):
887
"""Doing a sort on path prefix should match our sample data."""
918
sorted(original_paths, key=osutils.path_prefix_key))
919
# using the comparison routine shoudl work too:
922
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
925
class TestCopyTree(TestCaseInTempDir):
927
def test_copy_basic_tree(self):
928
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
929
osutils.copy_tree('source', 'target')
930
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
931
self.assertEqual(['c'], os.listdir('target/b'))
933
def test_copy_tree_target_exists(self):
934
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
936
osutils.copy_tree('source', 'target')
937
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
938
self.assertEqual(['c'], os.listdir('target/b'))
940
def test_copy_tree_symlinks(self):
941
if not osutils.has_symlinks():
943
self.build_tree(['source/'])
944
os.symlink('a/generic/path', 'source/lnk')
945
osutils.copy_tree('source', 'target')
946
self.assertEqual(['lnk'], os.listdir('target'))
947
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
949
def test_copy_tree_handlers(self):
952
def file_handler(from_path, to_path):
953
processed_files.append(('f', from_path, to_path))
954
def dir_handler(from_path, to_path):
955
processed_files.append(('d', from_path, to_path))
956
def link_handler(from_path, to_path):
957
processed_links.append((from_path, to_path))
958
handlers = {'file':file_handler,
959
'directory':dir_handler,
960
'symlink':link_handler,
963
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
964
if osutils.has_symlinks():
965
os.symlink('a/generic/path', 'source/lnk')
966
osutils.copy_tree('source', 'target', handlers=handlers)
968
self.assertEqual([('d', 'source', 'target'),
969
('f', 'source/a', 'target/a'),
970
('d', 'source/b', 'target/b'),
971
('f', 'source/b/c', 'target/b/c'),
973
self.failIfExists('target')
974
if osutils.has_symlinks():
975
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
978
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
979
# [bialix] 2006/12/26
982
class TestSetUnsetEnv(TestCase):
983
"""Test updating the environment"""
986
super(TestSetUnsetEnv, self).setUp()
988
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
989
'Environment was not cleaned up properly.'
990
' Variable BZR_TEST_ENV_VAR should not exist.')
992
if 'BZR_TEST_ENV_VAR' in os.environ:
993
del os.environ['BZR_TEST_ENV_VAR']
995
self.addCleanup(cleanup)
998
"""Test that we can set an env variable"""
999
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1000
self.assertEqual(None, old)
1001
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
1003
def test_double_set(self):
1004
"""Test that we get the old value out"""
1005
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1006
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
1007
self.assertEqual('foo', old)
1008
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1010
def test_unicode(self):
1011
"""Environment can only contain plain strings
1013
So Unicode strings must be encoded.
1015
uni_val, env_val = probe_unicode_in_user_encoding()
1017
raise TestSkipped('Cannot find a unicode character that works in'
1018
' encoding %s' % (bzrlib.user_encoding,))
1020
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1021
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1023
def test_unset(self):
1024
"""Test that passing None will remove the env var"""
1025
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1026
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1027
self.assertEqual('foo', old)
1028
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1029
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1032
class TestLocalTimeOffset(TestCase):
1034
def test_local_time_offset(self):
1035
"""Test that local_time_offset() returns a sane value."""
1036
offset = osutils.local_time_offset()
1037
self.assertTrue(isinstance(offset, int))
1038
# Test that the offset is no more than a eighteen hours in
1040
# Time zone handling is system specific, so it is difficult to
1041
# do more specific tests, but a value outside of this range is
1043
eighteen_hours = 18 * 3600
1044
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1046
def test_local_time_offset_with_timestamp(self):
1047
"""Test that local_time_offset() works with a timestamp."""
1048
offset = osutils.local_time_offset(1000000000.1234567)
1049
self.assertTrue(isinstance(offset, int))
1050
eighteen_hours = 18 * 3600
1051
self.assertTrue(-eighteen_hours < offset < eighteen_hours)