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."""
30
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
31
from bzrlib.osutils import (
33
is_inside_or_parent_of_any,
36
from bzrlib.tests import (
37
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_rename_change_case(self):
96
# on Windows we should be able to change filename case by rename
97
self.build_tree(['a', 'b/'])
98
osutils.rename('a', 'A')
99
osutils.rename('b', 'B')
100
# we can't use failUnlessExists on case-insensitive filesystem
101
# so try to check shape of the tree
102
shape = sorted(os.listdir('.'))
103
self.assertEquals(['A', 'B'], shape)
105
def test_01_rand_chars_empty(self):
106
result = osutils.rand_chars(0)
107
self.assertEqual(result, '')
109
def test_02_rand_chars_100(self):
110
result = osutils.rand_chars(100)
111
self.assertEqual(len(result), 100)
112
self.assertEqual(type(result), str)
113
self.assertContainsRe(result, r'^[a-z0-9]{100}$')
115
def test_is_inside(self):
116
is_inside = osutils.is_inside
117
self.assertTrue(is_inside('src', 'src/foo.c'))
118
self.assertFalse(is_inside('src', 'srccontrol'))
119
self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
120
self.assertTrue(is_inside('foo.c', 'foo.c'))
121
self.assertFalse(is_inside('foo.c', ''))
122
self.assertTrue(is_inside('', 'foo.c'))
124
def test_is_inside_any(self):
125
SRC_FOO_C = pathjoin('src', 'foo.c')
126
for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
127
(['src'], SRC_FOO_C),
130
self.assert_(is_inside_any(dirs, fn))
131
for dirs, fn in [(['src'], 'srccontrol'),
132
(['src'], 'srccontrol/foo')]:
133
self.assertFalse(is_inside_any(dirs, fn))
135
def test_is_inside_or_parent_of_any(self):
136
for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
137
(['src'], 'src/foo.c'),
138
(['src/bar.c'], 'src'),
139
(['src/bar.c', 'bla/foo.c'], 'src'),
142
self.assert_(is_inside_or_parent_of_any(dirs, fn))
144
for dirs, fn in [(['src'], 'srccontrol'),
145
(['srccontrol/foo.c'], 'src'),
146
(['src'], 'srccontrol/foo')]:
147
self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
149
def test_rmtree(self):
150
# Check to remove tree with read-only files/dirs
152
f = file('dir/file', 'w')
155
# would like to also try making the directory readonly, but at the
156
# moment python shutil.rmtree doesn't handle that properly - it would
157
# need to chmod the directory before removing things inside it - deferred
158
# for now -- mbp 20060505
159
# osutils.make_readonly('dir')
160
osutils.make_readonly('dir/file')
162
osutils.rmtree('dir')
164
self.failIfExists('dir/file')
165
self.failIfExists('dir')
167
def test_file_kind(self):
168
self.build_tree(['file', 'dir/'])
169
self.assertEquals('file', osutils.file_kind('file'))
170
self.assertEquals('directory', osutils.file_kind('dir/'))
171
if osutils.has_symlinks():
172
os.symlink('symlink', 'symlink')
173
self.assertEquals('symlink', osutils.file_kind('symlink'))
175
# TODO: jam 20060529 Test a block device
177
os.lstat('/dev/null')
179
if e.errno not in (errno.ENOENT,):
182
self.assertEquals('chardev', osutils.file_kind('/dev/null'))
184
mkfifo = getattr(os, 'mkfifo', None)
188
self.assertEquals('fifo', osutils.file_kind('fifo'))
192
AF_UNIX = getattr(socket, 'AF_UNIX', None)
194
s = socket.socket(AF_UNIX)
197
self.assertEquals('socket', osutils.file_kind('socket'))
201
def test_kind_marker(self):
202
self.assertEqual(osutils.kind_marker('file'), '')
203
self.assertEqual(osutils.kind_marker('directory'), '/')
204
self.assertEqual(osutils.kind_marker('symlink'), '@')
205
self.assertEqual(osutils.kind_marker('tree-reference'), '+')
207
def test_get_umask(self):
208
if sys.platform == 'win32':
209
# umask always returns '0', no way to set it
210
self.assertEqual(0, osutils.get_umask())
213
orig_umask = osutils.get_umask()
216
self.assertEqual(0222, osutils.get_umask())
218
self.assertEqual(0022, osutils.get_umask())
220
self.assertEqual(0002, osutils.get_umask())
222
self.assertEqual(0027, osutils.get_umask())
226
def assertFormatedDelta(self, expected, seconds):
227
"""Assert osutils.format_delta formats as expected"""
228
actual = osutils.format_delta(seconds)
229
self.assertEqual(expected, actual)
231
def test_format_delta(self):
232
self.assertFormatedDelta('0 seconds ago', 0)
233
self.assertFormatedDelta('1 second ago', 1)
234
self.assertFormatedDelta('10 seconds ago', 10)
235
self.assertFormatedDelta('59 seconds ago', 59)
236
self.assertFormatedDelta('89 seconds ago', 89)
237
self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
238
self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
239
self.assertFormatedDelta('3 minutes, 1 second ago', 181)
240
self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
241
self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
242
self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
243
self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
244
self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
245
self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
246
self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
247
self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
248
self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
249
self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
250
self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
251
self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
252
self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
253
self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
254
self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
256
# We handle when time steps the wrong direction because computers
257
# don't have synchronized clocks.
258
self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
259
self.assertFormatedDelta('1 second in the future', -1)
260
self.assertFormatedDelta('2 seconds in the future', -2)
262
def test_format_date(self):
263
self.assertRaises(errors.UnsupportedTimezoneFormat,
264
osutils.format_date, 0, timezone='foo')
266
def test_dereference_path(self):
267
self.requireFeature(SymlinkFeature)
268
cwd = osutils.realpath('.')
270
bar_path = osutils.pathjoin(cwd, 'bar')
271
# Using './' to avoid bug #1213894 (first path component not
272
# dereferenced) in Python 2.4.1 and earlier
273
self.assertEqual(bar_path, osutils.realpath('./bar'))
274
os.symlink('bar', 'foo')
275
self.assertEqual(bar_path, osutils.realpath('./foo'))
277
# Does not dereference terminal symlinks
278
foo_path = osutils.pathjoin(cwd, 'foo')
279
self.assertEqual(foo_path, osutils.dereference_path('./foo'))
281
# Dereferences parent symlinks
283
baz_path = osutils.pathjoin(bar_path, 'baz')
284
self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
286
# Dereferences parent symlinks that are the first path element
287
self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
289
# Dereferences parent symlinks in absolute paths
290
foo_baz_path = osutils.pathjoin(foo_path, 'baz')
291
self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
293
def test_changing_access(self):
294
f = file('file', 'w')
298
# Make a file readonly
299
osutils.make_readonly('file')
300
mode = os.lstat('file').st_mode
301
self.assertEqual(mode, mode & 0777555)
303
# Make a file writable
304
osutils.make_writable('file')
305
mode = os.lstat('file').st_mode
306
self.assertEqual(mode, mode | 0200)
308
if osutils.has_symlinks():
309
# should not error when handed a symlink
310
os.symlink('nonexistent', 'dangling')
311
osutils.make_readonly('dangling')
312
osutils.make_writable('dangling')
314
def test_kind_marker(self):
315
self.assertEqual("", osutils.kind_marker("file"))
316
self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
317
self.assertEqual("@", osutils.kind_marker("symlink"))
318
self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
321
class TestSafeUnicode(TestCase):
323
def test_from_ascii_string(self):
324
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
326
def test_from_unicode_string_ascii_contents(self):
327
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
329
def test_from_unicode_string_unicode_contents(self):
330
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
332
def test_from_utf8_string(self):
333
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
335
def test_bad_utf8_string(self):
336
self.assertRaises(BzrBadParameterNotUnicode,
337
osutils.safe_unicode,
341
class TestSafeUtf8(TestCase):
343
def test_from_ascii_string(self):
345
self.assertEqual('foobar', osutils.safe_utf8(f))
347
def test_from_unicode_string_ascii_contents(self):
348
self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
350
def test_from_unicode_string_unicode_contents(self):
351
self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
353
def test_from_utf8_string(self):
354
self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
356
def test_bad_utf8_string(self):
357
self.assertRaises(BzrBadParameterNotUnicode,
358
osutils.safe_utf8, '\xbb\xbb')
361
class TestSafeRevisionId(TestCase):
363
def test_from_ascii_string(self):
364
# this shouldn't give a warning because it's getting an ascii string
365
self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
367
def test_from_unicode_string_ascii_contents(self):
368
self.assertEqual('bargam',
369
osutils.safe_revision_id(u'bargam', warn=False))
371
def test_from_unicode_deprecated(self):
372
self.assertEqual('bargam',
373
self.callDeprecated([osutils._revision_id_warning],
374
osutils.safe_revision_id, u'bargam'))
376
def test_from_unicode_string_unicode_contents(self):
377
self.assertEqual('bargam\xc2\xae',
378
osutils.safe_revision_id(u'bargam\xae', warn=False))
380
def test_from_utf8_string(self):
381
self.assertEqual('foo\xc2\xae',
382
osutils.safe_revision_id('foo\xc2\xae'))
385
"""Currently, None is a valid revision_id"""
386
self.assertEqual(None, osutils.safe_revision_id(None))
389
class TestSafeFileId(TestCase):
391
def test_from_ascii_string(self):
392
self.assertEqual('foobar', osutils.safe_file_id('foobar'))
394
def test_from_unicode_string_ascii_contents(self):
395
self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
397
def test_from_unicode_deprecated(self):
398
self.assertEqual('bargam',
399
self.callDeprecated([osutils._file_id_warning],
400
osutils.safe_file_id, u'bargam'))
402
def test_from_unicode_string_unicode_contents(self):
403
self.assertEqual('bargam\xc2\xae',
404
osutils.safe_file_id(u'bargam\xae', warn=False))
406
def test_from_utf8_string(self):
407
self.assertEqual('foo\xc2\xae',
408
osutils.safe_file_id('foo\xc2\xae'))
411
"""Currently, None is a valid revision_id"""
412
self.assertEqual(None, osutils.safe_file_id(None))
415
class TestWin32Funcs(TestCase):
416
"""Test that the _win32 versions of os utilities return appropriate paths."""
418
def test_abspath(self):
419
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
420
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
421
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
422
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
424
def test_realpath(self):
425
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
426
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
428
def test_pathjoin(self):
429
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
430
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
431
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
432
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
433
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
434
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
436
def test_normpath(self):
437
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
438
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
440
def test_getcwd(self):
441
cwd = osutils._win32_getcwd()
442
os_cwd = os.getcwdu()
443
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
444
# win32 is inconsistent whether it returns lower or upper case
445
# and even if it was consistent the user might type the other
446
# so we force it to uppercase
447
# running python.exe under cmd.exe return capital C:\\
448
# running win32 python inside a cygwin shell returns lowercase
449
self.assertEqual(os_cwd[0].upper(), cwd[0])
451
def test_fixdrive(self):
452
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
453
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
454
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
456
def test_win98_abspath(self):
458
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
459
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
461
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
462
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
464
cwd = osutils.getcwd().rstrip('/')
465
drive = osutils._nt_splitdrive(cwd)[0]
466
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
467
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
470
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
473
class TestWin32FuncsDirs(TestCaseInTempDir):
474
"""Test win32 functions that create files."""
476
def test_getcwd(self):
477
if win32utils.winver == 'Windows 98':
478
raise TestSkipped('Windows 98 cannot handle unicode filenames')
479
# Make sure getcwd can handle unicode filenames
483
raise TestSkipped("Unable to create Unicode filename")
486
# TODO: jam 20060427 This will probably fail on Mac OSX because
487
# it will change the normalization of B\xe5gfors
488
# Consider using a different unicode character, or make
489
# osutils.getcwd() renormalize the path.
490
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
492
def test_minimum_path_selection(self):
493
self.assertEqual(set(),
494
osutils.minimum_path_selection([]))
495
self.assertEqual(set(['a', 'b']),
496
osutils.minimum_path_selection(['a', 'b']))
497
self.assertEqual(set(['a/', 'b']),
498
osutils.minimum_path_selection(['a/', 'b']))
499
self.assertEqual(set(['a/', 'b']),
500
osutils.minimum_path_selection(['a/c', 'a/', 'b']))
502
def test_mkdtemp(self):
503
tmpdir = osutils._win32_mkdtemp(dir='.')
504
self.assertFalse('\\' in tmpdir)
506
def test_rename(self):
514
osutils._win32_rename('b', 'a')
515
self.failUnlessExists('a')
516
self.failIfExists('b')
517
self.assertFileEqual('baz\n', 'a')
519
def test_rename_missing_file(self):
525
osutils._win32_rename('b', 'a')
526
except (IOError, OSError), e:
527
self.assertEqual(errno.ENOENT, e.errno)
528
self.assertFileEqual('foo\n', 'a')
530
def test_rename_missing_dir(self):
533
osutils._win32_rename('b', 'a')
534
except (IOError, OSError), e:
535
self.assertEqual(errno.ENOENT, e.errno)
537
def test_rename_current_dir(self):
540
# You can't rename the working directory
541
# doing rename non-existant . usually
542
# just raises ENOENT, since non-existant
545
osutils._win32_rename('b', '.')
546
except (IOError, OSError), e:
547
self.assertEqual(errno.ENOENT, e.errno)
549
def test_splitpath(self):
550
def check(expected, path):
551
self.assertEqual(expected, osutils.splitpath(path))
554
check(['a', 'b'], 'a/b')
555
check(['a', 'b'], 'a/./b')
556
check(['a', '.b'], 'a/.b')
557
check(['a', '.b'], 'a\\.b')
559
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
562
class TestMacFuncsDirs(TestCaseInTempDir):
563
"""Test mac special functions that require directories."""
565
def test_getcwd(self):
566
# On Mac, this will actually create Ba\u030agfors
567
# but chdir will still work, because it accepts both paths
569
os.mkdir(u'B\xe5gfors')
571
raise TestSkipped("Unable to create Unicode filename")
573
os.chdir(u'B\xe5gfors')
574
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
576
def test_getcwd_nonnorm(self):
577
# Test that _mac_getcwd() will normalize this path
579
os.mkdir(u'Ba\u030agfors')
581
raise TestSkipped("Unable to create Unicode filename")
583
os.chdir(u'Ba\u030agfors')
584
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
587
class TestSplitLines(TestCase):
589
def test_split_unicode(self):
590
self.assertEqual([u'foo\n', u'bar\xae'],
591
osutils.split_lines(u'foo\nbar\xae'))
592
self.assertEqual([u'foo\n', u'bar\xae\n'],
593
osutils.split_lines(u'foo\nbar\xae\n'))
595
def test_split_with_carriage_returns(self):
596
self.assertEqual(['foo\rbar\n'],
597
osutils.split_lines('foo\rbar\n'))
600
class TestWalkDirs(TestCaseInTempDir):
602
def test_walkdirs(self):
611
self.build_tree(tree)
612
expected_dirblocks = [
614
[('0file', '0file', 'file'),
615
('1dir', '1dir', 'directory'),
616
('2file', '2file', 'file'),
620
[('1dir/0file', '0file', 'file'),
621
('1dir/1dir', '1dir', 'directory'),
624
(('1dir/1dir', './1dir/1dir'),
631
for dirdetail, dirblock in osutils.walkdirs('.'):
632
if len(dirblock) and dirblock[0][1] == '.bzr':
633
# this tests the filtering of selected paths
636
result.append((dirdetail, dirblock))
638
self.assertTrue(found_bzrdir)
639
self.assertEqual(expected_dirblocks,
640
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
641
# you can search a subdir only, with a supplied prefix.
643
for dirblock in osutils.walkdirs('./1dir', '1dir'):
644
result.append(dirblock)
645
self.assertEqual(expected_dirblocks[1:],
646
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
648
def test__walkdirs_utf8(self):
657
self.build_tree(tree)
658
expected_dirblocks = [
660
[('0file', '0file', 'file'),
661
('1dir', '1dir', 'directory'),
662
('2file', '2file', 'file'),
666
[('1dir/0file', '0file', 'file'),
667
('1dir/1dir', '1dir', 'directory'),
670
(('1dir/1dir', './1dir/1dir'),
677
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
678
if len(dirblock) and dirblock[0][1] == '.bzr':
679
# this tests the filtering of selected paths
682
result.append((dirdetail, dirblock))
684
self.assertTrue(found_bzrdir)
685
self.assertEqual(expected_dirblocks,
686
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
687
# you can search a subdir only, with a supplied prefix.
689
for dirblock in osutils.walkdirs('./1dir', '1dir'):
690
result.append(dirblock)
691
self.assertEqual(expected_dirblocks[1:],
692
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
694
def _filter_out_stat(self, result):
695
"""Filter out the stat value from the walkdirs result"""
696
for dirdetail, dirblock in result:
698
for info in dirblock:
699
# Ignore info[3] which is the stat
700
new_dirblock.append((info[0], info[1], info[2], info[4]))
701
dirblock[:] = new_dirblock
703
def test_unicode_walkdirs(self):
704
"""Walkdirs should always return unicode paths."""
705
name0 = u'0file-\xb6'
706
name1 = u'1dir-\u062c\u0648'
707
name2 = u'2file-\u0633'
712
name1 + '/' + name1 + '/',
716
self.build_tree(tree)
718
raise TestSkipped('Could not represent Unicode chars'
719
' in current encoding.')
720
expected_dirblocks = [
722
[(name0, name0, 'file', './' + name0),
723
(name1, name1, 'directory', './' + name1),
724
(name2, name2, 'file', './' + name2),
727
((name1, './' + name1),
728
[(name1 + '/' + name0, name0, 'file', './' + name1
730
(name1 + '/' + name1, name1, 'directory', './' + name1
734
((name1 + '/' + name1, './' + name1 + '/' + name1),
739
result = list(osutils.walkdirs('.'))
740
self._filter_out_stat(result)
741
self.assertEqual(expected_dirblocks, result)
742
result = list(osutils.walkdirs(u'./'+name1, name1))
743
self._filter_out_stat(result)
744
self.assertEqual(expected_dirblocks[1:], result)
746
def test_unicode__walkdirs_utf8(self):
747
"""Walkdirs_utf8 should always return utf8 paths.
749
The abspath portion might be in unicode or utf-8
751
name0 = u'0file-\xb6'
752
name1 = u'1dir-\u062c\u0648'
753
name2 = u'2file-\u0633'
758
name1 + '/' + name1 + '/',
762
self.build_tree(tree)
764
raise TestSkipped('Could not represent Unicode chars'
765
' in current encoding.')
766
name0 = name0.encode('utf8')
767
name1 = name1.encode('utf8')
768
name2 = name2.encode('utf8')
770
expected_dirblocks = [
772
[(name0, name0, 'file', './' + name0),
773
(name1, name1, 'directory', './' + name1),
774
(name2, name2, 'file', './' + name2),
777
((name1, './' + name1),
778
[(name1 + '/' + name0, name0, 'file', './' + name1
780
(name1 + '/' + name1, name1, 'directory', './' + name1
784
((name1 + '/' + name1, './' + name1 + '/' + name1),
790
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
791
# all abspaths are Unicode, and encode them back into utf8.
792
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
793
self.assertIsInstance(dirdetail[0], str)
794
if isinstance(dirdetail[1], unicode):
795
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
796
dirblock = [list(info) for info in dirblock]
797
for info in dirblock:
798
self.assertIsInstance(info[4], unicode)
799
info[4] = info[4].encode('utf8')
801
for info in dirblock:
802
self.assertIsInstance(info[0], str)
803
self.assertIsInstance(info[1], str)
804
self.assertIsInstance(info[4], str)
805
# Remove the stat information
806
new_dirblock.append((info[0], info[1], info[2], info[4]))
807
result.append((dirdetail, new_dirblock))
808
self.assertEqual(expected_dirblocks, result)
810
def test_unicode__walkdirs_unicode_to_utf8(self):
811
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
813
The abspath portion should be in unicode
815
name0u = u'0file-\xb6'
816
name1u = u'1dir-\u062c\u0648'
817
name2u = u'2file-\u0633'
821
name1u + '/' + name0u,
822
name1u + '/' + name1u + '/',
826
self.build_tree(tree)
828
raise TestSkipped('Could not represent Unicode chars'
829
' in current encoding.')
830
name0 = name0u.encode('utf8')
831
name1 = name1u.encode('utf8')
832
name2 = name2u.encode('utf8')
834
# All of the abspaths should be in unicode, all of the relative paths
836
expected_dirblocks = [
838
[(name0, name0, 'file', './' + name0u),
839
(name1, name1, 'directory', './' + name1u),
840
(name2, name2, 'file', './' + name2u),
843
((name1, './' + name1u),
844
[(name1 + '/' + name0, name0, 'file', './' + name1u
846
(name1 + '/' + name1, name1, 'directory', './' + name1u
850
((name1 + '/' + name1, './' + name1u + '/' + name1u),
855
result = list(osutils._walkdirs_unicode_to_utf8('.'))
856
self._filter_out_stat(result)
857
self.assertEqual(expected_dirblocks, result)
859
def assertPathCompare(self, path_less, path_greater):
860
"""check that path_less and path_greater compare correctly."""
861
self.assertEqual(0, osutils.compare_paths_prefix_order(
862
path_less, path_less))
863
self.assertEqual(0, osutils.compare_paths_prefix_order(
864
path_greater, path_greater))
865
self.assertEqual(-1, osutils.compare_paths_prefix_order(
866
path_less, path_greater))
867
self.assertEqual(1, osutils.compare_paths_prefix_order(
868
path_greater, path_less))
870
def test_compare_paths_prefix_order(self):
871
# root before all else
872
self.assertPathCompare("/", "/a")
874
self.assertPathCompare("/a", "/b")
875
self.assertPathCompare("/b", "/z")
876
# high dirs before lower.
877
self.assertPathCompare("/z", "/a/a")
878
# except if the deeper dir should be output first
879
self.assertPathCompare("/a/b/c", "/d/g")
880
# lexical betwen dirs of the same height
881
self.assertPathCompare("/a/z", "/z/z")
882
self.assertPathCompare("/a/c/z", "/a/d/e")
884
# this should also be consistent for no leading / paths
885
# root before all else
886
self.assertPathCompare("", "a")
888
self.assertPathCompare("a", "b")
889
self.assertPathCompare("b", "z")
890
# high dirs before lower.
891
self.assertPathCompare("z", "a/a")
892
# except if the deeper dir should be output first
893
self.assertPathCompare("a/b/c", "d/g")
894
# lexical betwen dirs of the same height
895
self.assertPathCompare("a/z", "z/z")
896
self.assertPathCompare("a/c/z", "a/d/e")
898
def test_path_prefix_sorting(self):
899
"""Doing a sort on path prefix should match our sample data."""
930
sorted(original_paths, key=osutils.path_prefix_key))
931
# using the comparison routine shoudl work too:
934
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
937
class TestCopyTree(TestCaseInTempDir):
939
def test_copy_basic_tree(self):
940
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
941
osutils.copy_tree('source', 'target')
942
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
943
self.assertEqual(['c'], os.listdir('target/b'))
945
def test_copy_tree_target_exists(self):
946
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
948
osutils.copy_tree('source', 'target')
949
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
950
self.assertEqual(['c'], os.listdir('target/b'))
952
def test_copy_tree_symlinks(self):
953
self.requireFeature(SymlinkFeature)
954
self.build_tree(['source/'])
955
os.symlink('a/generic/path', 'source/lnk')
956
osutils.copy_tree('source', 'target')
957
self.assertEqual(['lnk'], os.listdir('target'))
958
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
960
def test_copy_tree_handlers(self):
963
def file_handler(from_path, to_path):
964
processed_files.append(('f', from_path, to_path))
965
def dir_handler(from_path, to_path):
966
processed_files.append(('d', from_path, to_path))
967
def link_handler(from_path, to_path):
968
processed_links.append((from_path, to_path))
969
handlers = {'file':file_handler,
970
'directory':dir_handler,
971
'symlink':link_handler,
974
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
975
if osutils.has_symlinks():
976
os.symlink('a/generic/path', 'source/lnk')
977
osutils.copy_tree('source', 'target', handlers=handlers)
979
self.assertEqual([('d', 'source', 'target'),
980
('f', 'source/a', 'target/a'),
981
('d', 'source/b', 'target/b'),
982
('f', 'source/b/c', 'target/b/c'),
984
self.failIfExists('target')
985
if osutils.has_symlinks():
986
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
989
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
990
# [bialix] 2006/12/26
993
class TestSetUnsetEnv(TestCase):
994
"""Test updating the environment"""
997
super(TestSetUnsetEnv, self).setUp()
999
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
1000
'Environment was not cleaned up properly.'
1001
' Variable BZR_TEST_ENV_VAR should not exist.')
1003
if 'BZR_TEST_ENV_VAR' in os.environ:
1004
del os.environ['BZR_TEST_ENV_VAR']
1006
self.addCleanup(cleanup)
1009
"""Test that we can set an env variable"""
1010
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1011
self.assertEqual(None, old)
1012
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
1014
def test_double_set(self):
1015
"""Test that we get the old value out"""
1016
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1017
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
1018
self.assertEqual('foo', old)
1019
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1021
def test_unicode(self):
1022
"""Environment can only contain plain strings
1024
So Unicode strings must be encoded.
1026
uni_val, env_val = probe_unicode_in_user_encoding()
1028
raise TestSkipped('Cannot find a unicode character that works in'
1029
' encoding %s' % (osutils.get_user_encoding(),))
1031
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1032
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1034
def test_unset(self):
1035
"""Test that passing None will remove the env var"""
1036
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1037
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1038
self.assertEqual('foo', old)
1039
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1040
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1043
class TestLocalTimeOffset(TestCase):
1045
def test_local_time_offset(self):
1046
"""Test that local_time_offset() returns a sane value."""
1047
offset = osutils.local_time_offset()
1048
self.assertTrue(isinstance(offset, int))
1049
# Test that the offset is no more than a eighteen hours in
1051
# Time zone handling is system specific, so it is difficult to
1052
# do more specific tests, but a value outside of this range is
1054
eighteen_hours = 18 * 3600
1055
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1057
def test_local_time_offset_with_timestamp(self):
1058
"""Test that local_time_offset() works with a timestamp."""
1059
offset = osutils.local_time_offset(1000000000.1234567)
1060
self.assertTrue(isinstance(offset, int))
1061
eighteen_hours = 18 * 3600
1062
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1065
class TestShaFileByName(TestCaseInTempDir):
1067
def test_sha_empty(self):
1068
self.build_tree_contents([('foo', '')])
1069
expected_sha = osutils.sha_string('')
1070
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1072
def test_sha_mixed_endings(self):
1073
text = 'test\r\nwith\nall\rpossible line endings\r\n'
1074
self.build_tree_contents([('foo', text)])
1075
expected_sha = osutils.sha_string(text)
1076
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1080
r'''# Copyright (C) 2005, 2006 Canonical Ltd
1082
# This program is free software; you can redistribute it and/or modify
1083
# it under the terms of the GNU General Public License as published by
1084
# the Free Software Foundation; either version 2 of the License, or
1085
# (at your option) any later version.
1087
# This program is distributed in the hope that it will be useful,
1088
# but WITHOUT ANY WARRANTY; without even the implied warranty of
1089
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1090
# GNU General Public License for more details.
1092
# You should have received a copy of the GNU General Public License
1093
# along with this program; if not, write to the Free Software
1094
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1097
# NOTE: If update these, please also update the help for global-options in
1098
# bzrlib/help_topics/__init__.py
1101
"""Set of flags that enable different debug behaviour.
1103
These are set with eg ``-Dlock`` on the bzr command line.
1107
* auth - show authentication sections used
1108
* error - show stack traces for all top level exceptions
1109
* evil - capture call sites that do expensive or badly-scaling operations.
1110
* fetch - trace history copying between repositories
1111
* hashcache - log every time a working file is read to determine its hash
1112
* hooks - trace hook execution
1113
* hpss - trace smart protocol requests and responses
1114
* http - trace http connections, requests and responses
1115
* index - trace major index operations
1116
* knit - trace knit operations
1117
* lock - trace when lockdir locks are taken or released
1118
* merge - emit information for debugging merges
1119
* pack - emit information about pack operations
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')