1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Tests for the osutils wrapper."""
31
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
32
from bzrlib.osutils import (
34
is_inside_or_parent_of_any,
37
from bzrlib.tests import (
38
probe_unicode_in_user_encoding,
47
class TestOSUtils(TestCaseInTempDir):
49
def test_contains_whitespace(self):
50
self.failUnless(osutils.contains_whitespace(u' '))
51
self.failUnless(osutils.contains_whitespace(u'hello there'))
52
self.failUnless(osutils.contains_whitespace(u'hellothere\n'))
53
self.failUnless(osutils.contains_whitespace(u'hello\nthere'))
54
self.failUnless(osutils.contains_whitespace(u'hello\rthere'))
55
self.failUnless(osutils.contains_whitespace(u'hello\tthere'))
57
# \xa0 is "Non-breaking-space" which on some python locales thinks it
58
# is whitespace, but we do not.
59
self.failIf(osutils.contains_whitespace(u''))
60
self.failIf(osutils.contains_whitespace(u'hellothere'))
61
self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
63
def test_fancy_rename(self):
64
# This should work everywhere
66
osutils.fancy_rename(a, b,
67
rename_func=os.rename,
68
unlink_func=os.unlink)
70
open('a', 'wb').write('something in a\n')
72
self.failIfExists('a')
73
self.failUnlessExists('b')
74
self.check_file_contents('b', 'something in a\n')
76
open('a', 'wb').write('new something in a\n')
79
self.check_file_contents('a', 'something in a\n')
81
def test_rename(self):
82
# Rename should be semi-atomic on all platforms
83
open('a', 'wb').write('something in a\n')
84
osutils.rename('a', 'b')
85
self.failIfExists('a')
86
self.failUnlessExists('b')
87
self.check_file_contents('b', 'something in a\n')
89
open('a', 'wb').write('new something in a\n')
90
osutils.rename('b', 'a')
92
self.check_file_contents('a', 'something in a\n')
94
# TODO: test fancy_rename using a MemoryTransport
96
def test_rename_change_case(self):
97
# on Windows we should be able to change filename case by rename
98
self.build_tree(['a', 'b/'])
99
osutils.rename('a', 'A')
100
osutils.rename('b', 'B')
101
# we can't use failUnlessExists on case-insensitive filesystem
102
# so try to check shape of the tree
103
shape = sorted(os.listdir('.'))
104
self.assertEquals(['A', 'B'], shape)
106
def test_01_rand_chars_empty(self):
107
result = osutils.rand_chars(0)
108
self.assertEqual(result, '')
110
def test_02_rand_chars_100(self):
111
result = osutils.rand_chars(100)
112
self.assertEqual(len(result), 100)
113
self.assertEqual(type(result), str)
114
self.assertContainsRe(result, r'^[a-z0-9]{100}$')
116
def test_is_inside(self):
117
is_inside = osutils.is_inside
118
self.assertTrue(is_inside('src', 'src/foo.c'))
119
self.assertFalse(is_inside('src', 'srccontrol'))
120
self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
121
self.assertTrue(is_inside('foo.c', 'foo.c'))
122
self.assertFalse(is_inside('foo.c', ''))
123
self.assertTrue(is_inside('', 'foo.c'))
125
def test_is_inside_any(self):
126
SRC_FOO_C = pathjoin('src', 'foo.c')
127
for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
128
(['src'], SRC_FOO_C),
131
self.assert_(is_inside_any(dirs, fn))
132
for dirs, fn in [(['src'], 'srccontrol'),
133
(['src'], 'srccontrol/foo')]:
134
self.assertFalse(is_inside_any(dirs, fn))
136
def test_is_inside_or_parent_of_any(self):
137
for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
138
(['src'], 'src/foo.c'),
139
(['src/bar.c'], 'src'),
140
(['src/bar.c', 'bla/foo.c'], 'src'),
143
self.assert_(is_inside_or_parent_of_any(dirs, fn))
145
for dirs, fn in [(['src'], 'srccontrol'),
146
(['srccontrol/foo.c'], 'src'),
147
(['src'], 'srccontrol/foo')]:
148
self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
150
def test_rmtree(self):
151
# Check to remove tree with read-only files/dirs
153
f = file('dir/file', 'w')
156
# would like to also try making the directory readonly, but at the
157
# moment python shutil.rmtree doesn't handle that properly - it would
158
# need to chmod the directory before removing things inside it - deferred
159
# for now -- mbp 20060505
160
# osutils.make_readonly('dir')
161
osutils.make_readonly('dir/file')
163
osutils.rmtree('dir')
165
self.failIfExists('dir/file')
166
self.failIfExists('dir')
168
def test_file_kind(self):
169
self.build_tree(['file', 'dir/'])
170
self.assertEquals('file', osutils.file_kind('file'))
171
self.assertEquals('directory', osutils.file_kind('dir/'))
172
if osutils.has_symlinks():
173
os.symlink('symlink', 'symlink')
174
self.assertEquals('symlink', osutils.file_kind('symlink'))
176
# TODO: jam 20060529 Test a block device
178
os.lstat('/dev/null')
180
if e.errno not in (errno.ENOENT,):
183
self.assertEquals('chardev', osutils.file_kind('/dev/null'))
185
mkfifo = getattr(os, 'mkfifo', None)
189
self.assertEquals('fifo', osutils.file_kind('fifo'))
193
AF_UNIX = getattr(socket, 'AF_UNIX', None)
195
s = socket.socket(AF_UNIX)
198
self.assertEquals('socket', osutils.file_kind('socket'))
202
def test_kind_marker(self):
203
self.assertEqual(osutils.kind_marker('file'), '')
204
self.assertEqual(osutils.kind_marker('directory'), '/')
205
self.assertEqual(osutils.kind_marker('symlink'), '@')
206
self.assertEqual(osutils.kind_marker('tree-reference'), '+')
208
def test_get_umask(self):
209
if sys.platform == 'win32':
210
# umask always returns '0', no way to set it
211
self.assertEqual(0, osutils.get_umask())
214
orig_umask = osutils.get_umask()
217
self.assertEqual(0222, osutils.get_umask())
219
self.assertEqual(0022, osutils.get_umask())
221
self.assertEqual(0002, osutils.get_umask())
223
self.assertEqual(0027, osutils.get_umask())
227
def assertFormatedDelta(self, expected, seconds):
228
"""Assert osutils.format_delta formats as expected"""
229
actual = osutils.format_delta(seconds)
230
self.assertEqual(expected, actual)
232
def test_format_delta(self):
233
self.assertFormatedDelta('0 seconds ago', 0)
234
self.assertFormatedDelta('1 second ago', 1)
235
self.assertFormatedDelta('10 seconds ago', 10)
236
self.assertFormatedDelta('59 seconds ago', 59)
237
self.assertFormatedDelta('89 seconds ago', 89)
238
self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
239
self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
240
self.assertFormatedDelta('3 minutes, 1 second ago', 181)
241
self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
242
self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
243
self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
244
self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
245
self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
246
self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
247
self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
248
self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
249
self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
250
self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
251
self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
252
self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
253
self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
254
self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
255
self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
257
# We handle when time steps the wrong direction because computers
258
# don't have synchronized clocks.
259
self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
260
self.assertFormatedDelta('1 second in the future', -1)
261
self.assertFormatedDelta('2 seconds in the future', -2)
263
def test_format_date(self):
264
self.assertRaises(errors.UnsupportedTimezoneFormat,
265
osutils.format_date, 0, timezone='foo')
267
def test_dereference_path(self):
268
self.requireFeature(SymlinkFeature)
269
cwd = osutils.realpath('.')
271
bar_path = osutils.pathjoin(cwd, 'bar')
272
# Using './' to avoid bug #1213894 (first path component not
273
# dereferenced) in Python 2.4.1 and earlier
274
self.assertEqual(bar_path, osutils.realpath('./bar'))
275
os.symlink('bar', 'foo')
276
self.assertEqual(bar_path, osutils.realpath('./foo'))
278
# Does not dereference terminal symlinks
279
foo_path = osutils.pathjoin(cwd, 'foo')
280
self.assertEqual(foo_path, osutils.dereference_path('./foo'))
282
# Dereferences parent symlinks
284
baz_path = osutils.pathjoin(bar_path, 'baz')
285
self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
287
# Dereferences parent symlinks that are the first path element
288
self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
290
# Dereferences parent symlinks in absolute paths
291
foo_baz_path = osutils.pathjoin(foo_path, 'baz')
292
self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
294
def test_changing_access(self):
295
f = file('file', 'w')
299
# Make a file readonly
300
osutils.make_readonly('file')
301
mode = os.lstat('file').st_mode
302
self.assertEqual(mode, mode & 0777555)
304
# Make a file writable
305
osutils.make_writable('file')
306
mode = os.lstat('file').st_mode
307
self.assertEqual(mode, mode | 0200)
309
if osutils.has_symlinks():
310
# should not error when handed a symlink
311
os.symlink('nonexistent', 'dangling')
312
osutils.make_readonly('dangling')
313
osutils.make_writable('dangling')
315
def test_kind_marker(self):
316
self.assertEqual("", osutils.kind_marker("file"))
317
self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
318
self.assertEqual("@", osutils.kind_marker("symlink"))
319
self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
322
class TestSafeUnicode(TestCase):
324
def test_from_ascii_string(self):
325
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
327
def test_from_unicode_string_ascii_contents(self):
328
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
330
def test_from_unicode_string_unicode_contents(self):
331
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
333
def test_from_utf8_string(self):
334
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
336
def test_bad_utf8_string(self):
337
self.assertRaises(BzrBadParameterNotUnicode,
338
osutils.safe_unicode,
342
class TestSafeUtf8(TestCase):
344
def test_from_ascii_string(self):
346
self.assertEqual('foobar', osutils.safe_utf8(f))
348
def test_from_unicode_string_ascii_contents(self):
349
self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
351
def test_from_unicode_string_unicode_contents(self):
352
self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
354
def test_from_utf8_string(self):
355
self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
357
def test_bad_utf8_string(self):
358
self.assertRaises(BzrBadParameterNotUnicode,
359
osutils.safe_utf8, '\xbb\xbb')
362
class TestSafeRevisionId(TestCase):
364
def test_from_ascii_string(self):
365
# this shouldn't give a warning because it's getting an ascii string
366
self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
368
def test_from_unicode_string_ascii_contents(self):
369
self.assertEqual('bargam',
370
osutils.safe_revision_id(u'bargam', warn=False))
372
def test_from_unicode_deprecated(self):
373
self.assertEqual('bargam',
374
self.callDeprecated([osutils._revision_id_warning],
375
osutils.safe_revision_id, u'bargam'))
377
def test_from_unicode_string_unicode_contents(self):
378
self.assertEqual('bargam\xc2\xae',
379
osutils.safe_revision_id(u'bargam\xae', warn=False))
381
def test_from_utf8_string(self):
382
self.assertEqual('foo\xc2\xae',
383
osutils.safe_revision_id('foo\xc2\xae'))
386
"""Currently, None is a valid revision_id"""
387
self.assertEqual(None, osutils.safe_revision_id(None))
390
class TestSafeFileId(TestCase):
392
def test_from_ascii_string(self):
393
self.assertEqual('foobar', osutils.safe_file_id('foobar'))
395
def test_from_unicode_string_ascii_contents(self):
396
self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
398
def test_from_unicode_deprecated(self):
399
self.assertEqual('bargam',
400
self.callDeprecated([osutils._file_id_warning],
401
osutils.safe_file_id, u'bargam'))
403
def test_from_unicode_string_unicode_contents(self):
404
self.assertEqual('bargam\xc2\xae',
405
osutils.safe_file_id(u'bargam\xae', warn=False))
407
def test_from_utf8_string(self):
408
self.assertEqual('foo\xc2\xae',
409
osutils.safe_file_id('foo\xc2\xae'))
412
"""Currently, None is a valid revision_id"""
413
self.assertEqual(None, osutils.safe_file_id(None))
416
class TestWin32Funcs(TestCase):
417
"""Test that the _win32 versions of os utilities return appropriate paths."""
419
def test_abspath(self):
420
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
421
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
422
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
423
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
425
def test_realpath(self):
426
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
427
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
429
def test_pathjoin(self):
430
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
431
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
432
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
433
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
434
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
435
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
437
def test_normpath(self):
438
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
439
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
441
def test_getcwd(self):
442
cwd = osutils._win32_getcwd()
443
os_cwd = os.getcwdu()
444
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
445
# win32 is inconsistent whether it returns lower or upper case
446
# and even if it was consistent the user might type the other
447
# so we force it to uppercase
448
# running python.exe under cmd.exe return capital C:\\
449
# running win32 python inside a cygwin shell returns lowercase
450
self.assertEqual(os_cwd[0].upper(), cwd[0])
452
def test_fixdrive(self):
453
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
454
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
455
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
457
def test_win98_abspath(self):
459
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
460
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
462
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
463
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
465
cwd = osutils.getcwd().rstrip('/')
466
drive = osutils._nt_splitdrive(cwd)[0]
467
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
468
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
471
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
474
class TestWin32FuncsDirs(TestCaseInTempDir):
475
"""Test win32 functions that create files."""
477
def test_getcwd(self):
478
if win32utils.winver == 'Windows 98':
479
raise TestSkipped('Windows 98 cannot handle unicode filenames')
480
# Make sure getcwd can handle unicode filenames
484
raise TestSkipped("Unable to create Unicode filename")
487
# TODO: jam 20060427 This will probably fail on Mac OSX because
488
# it will change the normalization of B\xe5gfors
489
# Consider using a different unicode character, or make
490
# osutils.getcwd() renormalize the path.
491
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
493
def test_minimum_path_selection(self):
494
self.assertEqual(set(),
495
osutils.minimum_path_selection([]))
496
self.assertEqual(set(['a', 'b']),
497
osutils.minimum_path_selection(['a', 'b']))
498
self.assertEqual(set(['a/', 'b']),
499
osutils.minimum_path_selection(['a/', 'b']))
500
self.assertEqual(set(['a/', 'b']),
501
osutils.minimum_path_selection(['a/c', 'a/', 'b']))
503
def test_mkdtemp(self):
504
tmpdir = osutils._win32_mkdtemp(dir='.')
505
self.assertFalse('\\' in tmpdir)
507
def test_rename(self):
515
osutils._win32_rename('b', 'a')
516
self.failUnlessExists('a')
517
self.failIfExists('b')
518
self.assertFileEqual('baz\n', 'a')
520
def test_rename_missing_file(self):
526
osutils._win32_rename('b', 'a')
527
except (IOError, OSError), e:
528
self.assertEqual(errno.ENOENT, e.errno)
529
self.assertFileEqual('foo\n', 'a')
531
def test_rename_missing_dir(self):
534
osutils._win32_rename('b', 'a')
535
except (IOError, OSError), e:
536
self.assertEqual(errno.ENOENT, e.errno)
538
def test_rename_current_dir(self):
541
# You can't rename the working directory
542
# doing rename non-existant . usually
543
# just raises ENOENT, since non-existant
546
osutils._win32_rename('b', '.')
547
except (IOError, OSError), e:
548
self.assertEqual(errno.ENOENT, e.errno)
550
def test_splitpath(self):
551
def check(expected, path):
552
self.assertEqual(expected, osutils.splitpath(path))
555
check(['a', 'b'], 'a/b')
556
check(['a', 'b'], 'a/./b')
557
check(['a', '.b'], 'a/.b')
558
check(['a', '.b'], 'a\\.b')
560
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
563
class TestMacFuncsDirs(TestCaseInTempDir):
564
"""Test mac special functions that require directories."""
566
def test_getcwd(self):
567
# On Mac, this will actually create Ba\u030agfors
568
# but chdir will still work, because it accepts both paths
570
os.mkdir(u'B\xe5gfors')
572
raise TestSkipped("Unable to create Unicode filename")
574
os.chdir(u'B\xe5gfors')
575
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
577
def test_getcwd_nonnorm(self):
578
# Test that _mac_getcwd() will normalize this path
580
os.mkdir(u'Ba\u030agfors')
582
raise TestSkipped("Unable to create Unicode filename")
584
os.chdir(u'Ba\u030agfors')
585
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
588
class TestSplitLines(TestCase):
590
def test_split_unicode(self):
591
self.assertEqual([u'foo\n', u'bar\xae'],
592
osutils.split_lines(u'foo\nbar\xae'))
593
self.assertEqual([u'foo\n', u'bar\xae\n'],
594
osutils.split_lines(u'foo\nbar\xae\n'))
596
def test_split_with_carriage_returns(self):
597
self.assertEqual(['foo\rbar\n'],
598
osutils.split_lines('foo\rbar\n'))
601
class TestWalkDirs(TestCaseInTempDir):
603
def test_walkdirs(self):
612
self.build_tree(tree)
613
expected_dirblocks = [
615
[('0file', '0file', 'file'),
616
('1dir', '1dir', 'directory'),
617
('2file', '2file', 'file'),
621
[('1dir/0file', '0file', 'file'),
622
('1dir/1dir', '1dir', 'directory'),
625
(('1dir/1dir', './1dir/1dir'),
632
for dirdetail, dirblock in osutils.walkdirs('.'):
633
if len(dirblock) and dirblock[0][1] == '.bzr':
634
# this tests the filtering of selected paths
637
result.append((dirdetail, dirblock))
639
self.assertTrue(found_bzrdir)
640
self.assertEqual(expected_dirblocks,
641
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
642
# you can search a subdir only, with a supplied prefix.
644
for dirblock in osutils.walkdirs('./1dir', '1dir'):
645
result.append(dirblock)
646
self.assertEqual(expected_dirblocks[1:],
647
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
649
def test__walkdirs_utf8(self):
658
self.build_tree(tree)
659
expected_dirblocks = [
661
[('0file', '0file', 'file'),
662
('1dir', '1dir', 'directory'),
663
('2file', '2file', 'file'),
667
[('1dir/0file', '0file', 'file'),
668
('1dir/1dir', '1dir', 'directory'),
671
(('1dir/1dir', './1dir/1dir'),
678
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
679
if len(dirblock) and dirblock[0][1] == '.bzr':
680
# this tests the filtering of selected paths
683
result.append((dirdetail, dirblock))
685
self.assertTrue(found_bzrdir)
686
self.assertEqual(expected_dirblocks,
687
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
688
# you can search a subdir only, with a supplied prefix.
690
for dirblock in osutils.walkdirs('./1dir', '1dir'):
691
result.append(dirblock)
692
self.assertEqual(expected_dirblocks[1:],
693
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
695
def _filter_out_stat(self, result):
696
"""Filter out the stat value from the walkdirs result"""
697
for dirdetail, dirblock in result:
699
for info in dirblock:
700
# Ignore info[3] which is the stat
701
new_dirblock.append((info[0], info[1], info[2], info[4]))
702
dirblock[:] = new_dirblock
704
def test_unicode_walkdirs(self):
705
"""Walkdirs should always return unicode paths."""
706
name0 = u'0file-\xb6'
707
name1 = u'1dir-\u062c\u0648'
708
name2 = u'2file-\u0633'
713
name1 + '/' + name1 + '/',
717
self.build_tree(tree)
719
raise TestSkipped('Could not represent Unicode chars'
720
' in current encoding.')
721
expected_dirblocks = [
723
[(name0, name0, 'file', './' + name0),
724
(name1, name1, 'directory', './' + name1),
725
(name2, name2, 'file', './' + name2),
728
((name1, './' + name1),
729
[(name1 + '/' + name0, name0, 'file', './' + name1
731
(name1 + '/' + name1, name1, 'directory', './' + name1
735
((name1 + '/' + name1, './' + name1 + '/' + name1),
740
result = list(osutils.walkdirs('.'))
741
self._filter_out_stat(result)
742
self.assertEqual(expected_dirblocks, result)
743
result = list(osutils.walkdirs(u'./'+name1, name1))
744
self._filter_out_stat(result)
745
self.assertEqual(expected_dirblocks[1:], result)
747
def test_unicode__walkdirs_utf8(self):
748
"""Walkdirs_utf8 should always return utf8 paths.
750
The abspath portion might be in unicode or utf-8
752
name0 = u'0file-\xb6'
753
name1 = u'1dir-\u062c\u0648'
754
name2 = u'2file-\u0633'
759
name1 + '/' + name1 + '/',
763
self.build_tree(tree)
765
raise TestSkipped('Could not represent Unicode chars'
766
' in current encoding.')
767
name0 = name0.encode('utf8')
768
name1 = name1.encode('utf8')
769
name2 = name2.encode('utf8')
771
expected_dirblocks = [
773
[(name0, name0, 'file', './' + name0),
774
(name1, name1, 'directory', './' + name1),
775
(name2, name2, 'file', './' + name2),
778
((name1, './' + name1),
779
[(name1 + '/' + name0, name0, 'file', './' + name1
781
(name1 + '/' + name1, name1, 'directory', './' + name1
785
((name1 + '/' + name1, './' + name1 + '/' + name1),
791
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
792
# all abspaths are Unicode, and encode them back into utf8.
793
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
794
self.assertIsInstance(dirdetail[0], str)
795
if isinstance(dirdetail[1], unicode):
796
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
797
dirblock = [list(info) for info in dirblock]
798
for info in dirblock:
799
self.assertIsInstance(info[4], unicode)
800
info[4] = info[4].encode('utf8')
802
for info in dirblock:
803
self.assertIsInstance(info[0], str)
804
self.assertIsInstance(info[1], str)
805
self.assertIsInstance(info[4], str)
806
# Remove the stat information
807
new_dirblock.append((info[0], info[1], info[2], info[4]))
808
result.append((dirdetail, new_dirblock))
809
self.assertEqual(expected_dirblocks, result)
811
def test_unicode__walkdirs_unicode_to_utf8(self):
812
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
814
The abspath portion should be in unicode
816
name0u = u'0file-\xb6'
817
name1u = u'1dir-\u062c\u0648'
818
name2u = u'2file-\u0633'
822
name1u + '/' + name0u,
823
name1u + '/' + name1u + '/',
827
self.build_tree(tree)
829
raise TestSkipped('Could not represent Unicode chars'
830
' in current encoding.')
831
name0 = name0u.encode('utf8')
832
name1 = name1u.encode('utf8')
833
name2 = name2u.encode('utf8')
835
# All of the abspaths should be in unicode, all of the relative paths
837
expected_dirblocks = [
839
[(name0, name0, 'file', './' + name0u),
840
(name1, name1, 'directory', './' + name1u),
841
(name2, name2, 'file', './' + name2u),
844
((name1, './' + name1u),
845
[(name1 + '/' + name0, name0, 'file', './' + name1u
847
(name1 + '/' + name1, name1, 'directory', './' + name1u
851
((name1 + '/' + name1, './' + name1u + '/' + name1u),
856
result = list(osutils._walkdirs_unicode_to_utf8('.'))
857
self._filter_out_stat(result)
858
self.assertEqual(expected_dirblocks, result)
860
def assertPathCompare(self, path_less, path_greater):
861
"""check that path_less and path_greater compare correctly."""
862
self.assertEqual(0, osutils.compare_paths_prefix_order(
863
path_less, path_less))
864
self.assertEqual(0, osutils.compare_paths_prefix_order(
865
path_greater, path_greater))
866
self.assertEqual(-1, osutils.compare_paths_prefix_order(
867
path_less, path_greater))
868
self.assertEqual(1, osutils.compare_paths_prefix_order(
869
path_greater, path_less))
871
def test_compare_paths_prefix_order(self):
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
# this should also be consistent for no leading / paths
886
# root before all else
887
self.assertPathCompare("", "a")
889
self.assertPathCompare("a", "b")
890
self.assertPathCompare("b", "z")
891
# high dirs before lower.
892
self.assertPathCompare("z", "a/a")
893
# except if the deeper dir should be output first
894
self.assertPathCompare("a/b/c", "d/g")
895
# lexical betwen dirs of the same height
896
self.assertPathCompare("a/z", "z/z")
897
self.assertPathCompare("a/c/z", "a/d/e")
899
def test_path_prefix_sorting(self):
900
"""Doing a sort on path prefix should match our sample data."""
931
sorted(original_paths, key=osutils.path_prefix_key))
932
# using the comparison routine shoudl work too:
935
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
938
class TestCopyTree(TestCaseInTempDir):
940
def test_copy_basic_tree(self):
941
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
942
osutils.copy_tree('source', 'target')
943
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
944
self.assertEqual(['c'], os.listdir('target/b'))
946
def test_copy_tree_target_exists(self):
947
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
949
osutils.copy_tree('source', 'target')
950
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
951
self.assertEqual(['c'], os.listdir('target/b'))
953
def test_copy_tree_symlinks(self):
954
self.requireFeature(SymlinkFeature)
955
self.build_tree(['source/'])
956
os.symlink('a/generic/path', 'source/lnk')
957
osutils.copy_tree('source', 'target')
958
self.assertEqual(['lnk'], os.listdir('target'))
959
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
961
def test_copy_tree_handlers(self):
964
def file_handler(from_path, to_path):
965
processed_files.append(('f', from_path, to_path))
966
def dir_handler(from_path, to_path):
967
processed_files.append(('d', from_path, to_path))
968
def link_handler(from_path, to_path):
969
processed_links.append((from_path, to_path))
970
handlers = {'file':file_handler,
971
'directory':dir_handler,
972
'symlink':link_handler,
975
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
976
if osutils.has_symlinks():
977
os.symlink('a/generic/path', 'source/lnk')
978
osutils.copy_tree('source', 'target', handlers=handlers)
980
self.assertEqual([('d', 'source', 'target'),
981
('f', 'source/a', 'target/a'),
982
('d', 'source/b', 'target/b'),
983
('f', 'source/b/c', 'target/b/c'),
985
self.failIfExists('target')
986
if osutils.has_symlinks():
987
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
990
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
991
# [bialix] 2006/12/26
994
class TestSetUnsetEnv(TestCase):
995
"""Test updating the environment"""
998
super(TestSetUnsetEnv, self).setUp()
1000
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
1001
'Environment was not cleaned up properly.'
1002
' Variable BZR_TEST_ENV_VAR should not exist.')
1004
if 'BZR_TEST_ENV_VAR' in os.environ:
1005
del os.environ['BZR_TEST_ENV_VAR']
1007
self.addCleanup(cleanup)
1010
"""Test that we can set an env variable"""
1011
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1012
self.assertEqual(None, old)
1013
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
1015
def test_double_set(self):
1016
"""Test that we get the old value out"""
1017
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1018
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
1019
self.assertEqual('foo', old)
1020
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1022
def test_unicode(self):
1023
"""Environment can only contain plain strings
1025
So Unicode strings must be encoded.
1027
uni_val, env_val = probe_unicode_in_user_encoding()
1029
raise TestSkipped('Cannot find a unicode character that works in'
1030
' encoding %s' % (bzrlib.user_encoding,))
1032
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1033
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1035
def test_unset(self):
1036
"""Test that passing None will remove the env var"""
1037
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1038
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1039
self.assertEqual('foo', old)
1040
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1041
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1044
class TestLocalTimeOffset(TestCase):
1046
def test_local_time_offset(self):
1047
"""Test that local_time_offset() returns a sane value."""
1048
offset = osutils.local_time_offset()
1049
self.assertTrue(isinstance(offset, int))
1050
# Test that the offset is no more than a eighteen hours in
1052
# Time zone handling is system specific, so it is difficult to
1053
# do more specific tests, but a value outside of this range is
1055
eighteen_hours = 18 * 3600
1056
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1058
def test_local_time_offset_with_timestamp(self):
1059
"""Test that local_time_offset() works with a timestamp."""
1060
offset = osutils.local_time_offset(1000000000.1234567)
1061
self.assertTrue(isinstance(offset, int))
1062
eighteen_hours = 18 * 3600
1063
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1066
class TestShaFileByName(TestCaseInTempDir):
1068
def test_sha_empty(self):
1069
self.build_tree_contents([('foo', '')])
1070
expected_sha = osutils.sha_string('')
1071
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1073
def test_sha_mixed_endings(self):
1074
text = 'test\r\nwith\nall\rpossible line endings\r\n'
1075
self.build_tree_contents([('foo', text)])
1076
expected_sha = osutils.sha_string(text)
1077
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1081
r'''# Copyright (C) 2005, 2006 Canonical Ltd
1083
# This program is free software; you can redistribute it and/or modify
1084
# it under the terms of the GNU General Public License as published by
1085
# the Free Software Foundation; either version 2 of the License, or
1086
# (at your option) any later version.
1088
# This program is distributed in the hope that it will be useful,
1089
# but WITHOUT ANY WARRANTY; without even the implied warranty of
1090
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1091
# GNU General Public License for more details.
1093
# You should have received a copy of the GNU General Public License
1094
# along with this program; if not, write to the Free Software
1095
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1098
# NOTE: If update these, please also update the help for global-options in
1099
# bzrlib/help_topics/__init__.py
1102
"""Set of flags that enable different debug behaviour.
1104
These are set with eg ``-Dlock`` on the bzr command line.
1108
* auth - show authentication sections used
1109
* error - show stack traces for all top level exceptions
1110
* evil - capture call sites that do expensive or badly-scaling operations.
1111
* fetch - trace history copying between repositories
1112
* hashcache - log every time a working file is read to determine its hash
1113
* hooks - trace hook execution
1114
* hpss - trace smart protocol requests and responses
1115
* http - trace http connections, requests and responses
1116
* index - trace major index operations
1117
* knit - trace knit operations
1118
* lock - trace when lockdir locks are taken or released
1119
* merge - emit information for debugging merges
1125
class TestResourceLoading(TestCaseInTempDir):
1127
def test_resource_string(self):
1128
# test resource in bzrlib
1129
text = osutils.resource_string('bzrlib', 'debug.py')
1130
self.assertEquals(_debug_text, text)
1131
# test resource under bzrlib
1132
text = osutils.resource_string('bzrlib.ui', 'text.py')
1133
self.assertContainsRe(text, "class TextUIFactory")
1134
# test unsupported package
1135
self.assertRaises(errors.BzrError, osutils.resource_string, 'zzzz',
1137
# test unknown resource
1138
self.assertRaises(IOError, osutils.resource_string, 'bzrlib', 'yyy.xx')