1
# Copyright (C) 2005, 2006 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.tests import (
40
class TestOSUtils(TestCaseInTempDir):
42
def test_contains_whitespace(self):
43
self.failUnless(osutils.contains_whitespace(u' '))
44
self.failUnless(osutils.contains_whitespace(u'hello there'))
45
self.failUnless(osutils.contains_whitespace(u'hellothere\n'))
46
self.failUnless(osutils.contains_whitespace(u'hello\nthere'))
47
self.failUnless(osutils.contains_whitespace(u'hello\rthere'))
48
self.failUnless(osutils.contains_whitespace(u'hello\tthere'))
50
# \xa0 is "Non-breaking-space" which on some python locales thinks it
51
# is whitespace, but we do not.
52
self.failIf(osutils.contains_whitespace(u''))
53
self.failIf(osutils.contains_whitespace(u'hellothere'))
54
self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
56
def test_fancy_rename(self):
57
# This should work everywhere
59
osutils.fancy_rename(a, b,
60
rename_func=os.rename,
61
unlink_func=os.unlink)
63
open('a', 'wb').write('something in a\n')
65
self.failIfExists('a')
66
self.failUnlessExists('b')
67
self.check_file_contents('b', 'something in a\n')
69
open('a', 'wb').write('new something in a\n')
72
self.check_file_contents('a', 'something in a\n')
74
def test_rename(self):
75
# Rename should be semi-atomic on all platforms
76
open('a', 'wb').write('something in a\n')
77
osutils.rename('a', 'b')
78
self.failIfExists('a')
79
self.failUnlessExists('b')
80
self.check_file_contents('b', 'something in a\n')
82
open('a', 'wb').write('new something in a\n')
83
osutils.rename('b', 'a')
85
self.check_file_contents('a', 'something in a\n')
87
# TODO: test fancy_rename using a MemoryTransport
89
def test_01_rand_chars_empty(self):
90
result = osutils.rand_chars(0)
91
self.assertEqual(result, '')
93
def test_02_rand_chars_100(self):
94
result = osutils.rand_chars(100)
95
self.assertEqual(len(result), 100)
96
self.assertEqual(type(result), str)
97
self.assertContainsRe(result, r'^[a-z0-9]{100}$')
99
def test_is_inside(self):
100
is_inside = osutils.is_inside
101
self.assertTrue(is_inside('src', 'src/foo.c'))
102
self.assertFalse(is_inside('src', 'srccontrol'))
103
self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
104
self.assertTrue(is_inside('foo.c', 'foo.c'))
105
self.assertFalse(is_inside('foo.c', ''))
106
self.assertTrue(is_inside('', 'foo.c'))
108
def test_rmtree(self):
109
# Check to remove tree with read-only files/dirs
111
f = file('dir/file', 'w')
114
# would like to also try making the directory readonly, but at the
115
# moment python shutil.rmtree doesn't handle that properly - it would
116
# need to chmod the directory before removing things inside it - deferred
117
# for now -- mbp 20060505
118
# osutils.make_readonly('dir')
119
osutils.make_readonly('dir/file')
121
osutils.rmtree('dir')
123
self.failIfExists('dir/file')
124
self.failIfExists('dir')
126
def test_file_kind(self):
127
self.build_tree(['file', 'dir/'])
128
self.assertEquals('file', osutils.file_kind('file'))
129
self.assertEquals('directory', osutils.file_kind('dir/'))
130
if osutils.has_symlinks():
131
os.symlink('symlink', 'symlink')
132
self.assertEquals('symlink', osutils.file_kind('symlink'))
134
# TODO: jam 20060529 Test a block device
136
os.lstat('/dev/null')
138
if e.errno not in (errno.ENOENT,):
141
self.assertEquals('chardev', osutils.file_kind('/dev/null'))
143
mkfifo = getattr(os, 'mkfifo', None)
147
self.assertEquals('fifo', osutils.file_kind('fifo'))
151
AF_UNIX = getattr(socket, 'AF_UNIX', None)
153
s = socket.socket(AF_UNIX)
156
self.assertEquals('socket', osutils.file_kind('socket'))
160
def test_kind_marker(self):
161
self.assertEqual(osutils.kind_marker('file'), '')
162
self.assertEqual(osutils.kind_marker('directory'), '/')
163
self.assertEqual(osutils.kind_marker('symlink'), '@')
164
self.assertEqual(osutils.kind_marker('tree-reference'), '+')
166
def test_get_umask(self):
167
if sys.platform == 'win32':
168
# umask always returns '0', no way to set it
169
self.assertEqual(0, osutils.get_umask())
172
orig_umask = osutils.get_umask()
175
self.assertEqual(0222, osutils.get_umask())
177
self.assertEqual(0022, osutils.get_umask())
179
self.assertEqual(0002, osutils.get_umask())
181
self.assertEqual(0027, osutils.get_umask())
185
def assertFormatedDelta(self, expected, seconds):
186
"""Assert osutils.format_delta formats as expected"""
187
actual = osutils.format_delta(seconds)
188
self.assertEqual(expected, actual)
190
def test_format_delta(self):
191
self.assertFormatedDelta('0 seconds ago', 0)
192
self.assertFormatedDelta('1 second ago', 1)
193
self.assertFormatedDelta('10 seconds ago', 10)
194
self.assertFormatedDelta('59 seconds ago', 59)
195
self.assertFormatedDelta('89 seconds ago', 89)
196
self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
197
self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
198
self.assertFormatedDelta('3 minutes, 1 second ago', 181)
199
self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
200
self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
201
self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
202
self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
203
self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
204
self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
205
self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
206
self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
207
self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
208
self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
209
self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
210
self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
211
self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
212
self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
213
self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
215
# We handle when time steps the wrong direction because computers
216
# don't have synchronized clocks.
217
self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
218
self.assertFormatedDelta('1 second in the future', -1)
219
self.assertFormatedDelta('2 seconds in the future', -2)
221
def test_dereference_path(self):
222
if not osutils.has_symlinks():
223
raise TestSkipped('Symlinks are not supported on this platform')
224
cwd = osutils.realpath('.')
226
bar_path = osutils.pathjoin(cwd, 'bar')
227
# Using './' to avoid bug #1213894 (first path component not
228
# dereferenced) in Python 2.4.1 and earlier
229
self.assertEqual(bar_path, osutils.realpath('./bar'))
230
os.symlink('bar', 'foo')
231
self.assertEqual(bar_path, osutils.realpath('./foo'))
233
# Does not dereference terminal symlinks
234
foo_path = osutils.pathjoin(cwd, 'foo')
235
self.assertEqual(foo_path, osutils.dereference_path('./foo'))
237
# Dereferences parent symlinks
239
baz_path = osutils.pathjoin(bar_path, 'baz')
240
self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
242
# Dereferences parent symlinks that are the first path element
243
self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
245
# Dereferences parent symlinks in absolute paths
246
foo_baz_path = osutils.pathjoin(foo_path, 'baz')
247
self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
250
def test_changing_access(self):
251
f = file('file', 'w')
255
# Make a file readonly
256
osutils.make_readonly('file')
257
mode = osutils.lstat('file').st_mode
258
self.assertEqual(mode, mode & 0777555)
260
# Make a file writable
261
osutils.make_writable('file')
262
mode = osutils.lstat('file').st_mode
263
self.assertEqual(mode, mode | 0200)
265
if osutils.has_symlinks():
266
# should not error when handed a symlink
267
os.symlink('nonexistent', 'dangling')
268
osutils.make_readonly('dangling')
269
osutils.make_writable('dangling')
272
def test_kind_marker(self):
273
self.assertEqual("", osutils.kind_marker("file"))
274
self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
275
self.assertEqual("@", osutils.kind_marker("symlink"))
276
self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
279
class TestSafeUnicode(TestCase):
281
def test_from_ascii_string(self):
282
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
284
def test_from_unicode_string_ascii_contents(self):
285
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
287
def test_from_unicode_string_unicode_contents(self):
288
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
290
def test_from_utf8_string(self):
291
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
293
def test_bad_utf8_string(self):
294
self.assertRaises(BzrBadParameterNotUnicode,
295
osutils.safe_unicode,
299
class TestSafeUtf8(TestCase):
301
def test_from_ascii_string(self):
303
self.assertEqual('foobar', osutils.safe_utf8(f))
305
def test_from_unicode_string_ascii_contents(self):
306
self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
308
def test_from_unicode_string_unicode_contents(self):
309
self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
311
def test_from_utf8_string(self):
312
self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
314
def test_bad_utf8_string(self):
315
self.assertRaises(BzrBadParameterNotUnicode,
316
osutils.safe_utf8, '\xbb\xbb')
319
class TestSafeRevisionId(TestCase):
321
def test_from_ascii_string(self):
322
self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
324
def test_from_unicode_string_ascii_contents(self):
325
self.assertEqual('bargam',
326
osutils.safe_revision_id(u'bargam', warn=False))
328
def test_from_unicode_deprecated(self):
329
self.assertEqual('bargam',
330
self.callDeprecated([osutils._revision_id_warning],
331
osutils.safe_revision_id, u'bargam'))
333
def test_from_unicode_string_unicode_contents(self):
334
self.assertEqual('bargam\xc2\xae',
335
osutils.safe_revision_id(u'bargam\xae', warn=False))
337
def test_from_utf8_string(self):
338
self.assertEqual('foo\xc2\xae',
339
osutils.safe_revision_id('foo\xc2\xae'))
342
"""Currently, None is a valid revision_id"""
343
self.assertEqual(None, osutils.safe_revision_id(None))
346
class TestSafeFileId(TestCase):
348
def test_from_ascii_string(self):
349
self.assertEqual('foobar', osutils.safe_file_id('foobar'))
351
def test_from_unicode_string_ascii_contents(self):
352
self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
354
def test_from_unicode_deprecated(self):
355
self.assertEqual('bargam',
356
self.callDeprecated([osutils._file_id_warning],
357
osutils.safe_file_id, u'bargam'))
359
def test_from_unicode_string_unicode_contents(self):
360
self.assertEqual('bargam\xc2\xae',
361
osutils.safe_file_id(u'bargam\xae', warn=False))
363
def test_from_utf8_string(self):
364
self.assertEqual('foo\xc2\xae',
365
osutils.safe_file_id('foo\xc2\xae'))
368
"""Currently, None is a valid revision_id"""
369
self.assertEqual(None, osutils.safe_file_id(None))
372
class TestWin32Funcs(TestCase):
373
"""Test that the _win32 versions of os utilities return appropriate paths."""
375
def test_abspath(self):
376
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
377
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
378
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
379
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
381
def test_realpath(self):
382
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
383
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
385
def test_pathjoin(self):
386
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
387
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
388
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
389
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
390
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
391
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
393
def test_normpath(self):
394
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
395
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
397
def test_getcwd(self):
398
cwd = osutils._win32_getcwd()
399
os_cwd = os.getcwdu()
400
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
401
# win32 is inconsistent whether it returns lower or upper case
402
# and even if it was consistent the user might type the other
403
# so we force it to uppercase
404
# running python.exe under cmd.exe return capital C:\\
405
# running win32 python inside a cygwin shell returns lowercase
406
self.assertEqual(os_cwd[0].upper(), cwd[0])
408
def test_fixdrive(self):
409
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
410
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
411
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
413
def test_win98_abspath(self):
415
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
416
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
418
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
419
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
421
cwd = osutils.getcwd().rstrip('/')
422
drive = osutils._nt_splitdrive(cwd)[0]
423
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
424
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
427
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
430
class TestWin32FuncsDirs(TestCaseInTempDir):
431
"""Test win32 functions that create files."""
433
def test_getcwd(self):
434
if win32utils.winver == 'Windows 98':
435
raise TestSkipped('Windows 98 cannot handle unicode filenames')
436
# Make sure getcwd can handle unicode filenames
440
raise TestSkipped("Unable to create Unicode filename")
443
# TODO: jam 20060427 This will probably fail on Mac OSX because
444
# it will change the normalization of B\xe5gfors
445
# Consider using a different unicode character, or make
446
# osutils.getcwd() renormalize the path.
447
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
449
def test_mkdtemp(self):
450
tmpdir = osutils._win32_mkdtemp(dir='.')
451
self.assertFalse('\\' in tmpdir)
453
def test_rename(self):
461
osutils._win32_rename('b', 'a')
462
self.failUnlessExists('a')
463
self.failIfExists('b')
464
self.assertFileEqual('baz\n', 'a')
466
def test_rename_missing_file(self):
472
osutils._win32_rename('b', 'a')
473
except (IOError, OSError), e:
474
self.assertEqual(errno.ENOENT, e.errno)
475
self.assertFileEqual('foo\n', 'a')
477
def test_rename_missing_dir(self):
480
osutils._win32_rename('b', 'a')
481
except (IOError, OSError), e:
482
self.assertEqual(errno.ENOENT, e.errno)
484
def test_rename_current_dir(self):
487
# You can't rename the working directory
488
# doing rename non-existant . usually
489
# just raises ENOENT, since non-existant
492
osutils._win32_rename('b', '.')
493
except (IOError, OSError), e:
494
self.assertEqual(errno.ENOENT, e.errno)
496
def test_splitpath(self):
497
def check(expected, path):
498
self.assertEqual(expected, osutils.splitpath(path))
501
check(['a', 'b'], 'a/b')
502
check(['a', 'b'], 'a/./b')
503
check(['a', '.b'], 'a/.b')
504
check(['a', '.b'], 'a\\.b')
506
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
509
class TestMacFuncsDirs(TestCaseInTempDir):
510
"""Test mac special functions that require directories."""
512
def test_getcwd(self):
513
# On Mac, this will actually create Ba\u030agfors
514
# but chdir will still work, because it accepts both paths
516
os.mkdir(u'B\xe5gfors')
518
raise TestSkipped("Unable to create Unicode filename")
520
os.chdir(u'B\xe5gfors')
521
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
523
def test_getcwd_nonnorm(self):
524
# Test that _mac_getcwd() will normalize this path
526
os.mkdir(u'Ba\u030agfors')
528
raise TestSkipped("Unable to create Unicode filename")
530
os.chdir(u'Ba\u030agfors')
531
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
534
class TestSplitLines(TestCase):
536
def test_split_unicode(self):
537
self.assertEqual([u'foo\n', u'bar\xae'],
538
osutils.split_lines(u'foo\nbar\xae'))
539
self.assertEqual([u'foo\n', u'bar\xae\n'],
540
osutils.split_lines(u'foo\nbar\xae\n'))
542
def test_split_with_carriage_returns(self):
543
self.assertEqual(['foo\rbar\n'],
544
osutils.split_lines('foo\rbar\n'))
547
class TestWalkDirs(TestCaseInTempDir):
549
def test_walkdirs(self):
558
self.build_tree(tree)
559
expected_dirblocks = [
561
[('0file', '0file', 'file'),
562
('1dir', '1dir', 'directory'),
563
('2file', '2file', 'file'),
567
[('1dir/0file', '0file', 'file'),
568
('1dir/1dir', '1dir', 'directory'),
571
(('1dir/1dir', './1dir/1dir'),
578
for dirdetail, dirblock in osutils.walkdirs('.'):
579
if len(dirblock) and dirblock[0][1] == '.bzr':
580
# this tests the filtering of selected paths
583
result.append((dirdetail, dirblock))
585
self.assertTrue(found_bzrdir)
586
self.assertEqual(expected_dirblocks,
587
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
588
# you can search a subdir only, with a supplied prefix.
590
for dirblock in osutils.walkdirs('./1dir', '1dir'):
591
result.append(dirblock)
592
self.assertEqual(expected_dirblocks[1:],
593
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
595
def test__walkdirs_utf8(self):
604
self.build_tree(tree)
605
expected_dirblocks = [
607
[('0file', '0file', 'file'),
608
('1dir', '1dir', 'directory'),
609
('2file', '2file', 'file'),
613
[('1dir/0file', '0file', 'file'),
614
('1dir/1dir', '1dir', 'directory'),
617
(('1dir/1dir', './1dir/1dir'),
624
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
625
if len(dirblock) and dirblock[0][1] == '.bzr':
626
# this tests the filtering of selected paths
629
result.append((dirdetail, dirblock))
631
self.assertTrue(found_bzrdir)
632
self.assertEqual(expected_dirblocks,
633
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
634
# you can search a subdir only, with a supplied prefix.
636
for dirblock in osutils.walkdirs('./1dir', '1dir'):
637
result.append(dirblock)
638
self.assertEqual(expected_dirblocks[1:],
639
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
641
def _filter_out_stat(self, result):
642
"""Filter out the stat value from the walkdirs result"""
643
for dirdetail, dirblock in result:
645
for info in dirblock:
646
# Ignore info[3] which is the stat
647
new_dirblock.append((info[0], info[1], info[2], info[4]))
648
dirblock[:] = new_dirblock
650
def test_unicode_walkdirs(self):
651
"""Walkdirs should always return unicode paths."""
652
name0 = u'0file-\xb6'
653
name1 = u'1dir-\u062c\u0648'
654
name2 = u'2file-\u0633'
659
name1 + '/' + name1 + '/',
663
self.build_tree(tree)
665
raise TestSkipped('Could not represent Unicode chars'
666
' in current encoding.')
667
expected_dirblocks = [
669
[(name0, name0, 'file', './' + name0),
670
(name1, name1, 'directory', './' + name1),
671
(name2, name2, 'file', './' + name2),
674
((name1, './' + name1),
675
[(name1 + '/' + name0, name0, 'file', './' + name1
677
(name1 + '/' + name1, name1, 'directory', './' + name1
681
((name1 + '/' + name1, './' + name1 + '/' + name1),
686
result = list(osutils.walkdirs('.'))
687
self._filter_out_stat(result)
688
self.assertEqual(expected_dirblocks, result)
689
result = list(osutils.walkdirs(u'./'+name1, name1))
690
self._filter_out_stat(result)
691
self.assertEqual(expected_dirblocks[1:], result)
693
def test_unicode__walkdirs_utf8(self):
694
"""Walkdirs_utf8 should always return utf8 paths.
696
The abspath portion might be in unicode or utf-8
698
name0 = u'0file-\xb6'
699
name1 = u'1dir-\u062c\u0648'
700
name2 = u'2file-\u0633'
705
name1 + '/' + name1 + '/',
709
self.build_tree(tree)
711
raise TestSkipped('Could not represent Unicode chars'
712
' in current encoding.')
713
name0 = name0.encode('utf8')
714
name1 = name1.encode('utf8')
715
name2 = name2.encode('utf8')
717
expected_dirblocks = [
719
[(name0, name0, 'file', './' + name0),
720
(name1, name1, 'directory', './' + name1),
721
(name2, name2, 'file', './' + name2),
724
((name1, './' + name1),
725
[(name1 + '/' + name0, name0, 'file', './' + name1
727
(name1 + '/' + name1, name1, 'directory', './' + name1
731
((name1 + '/' + name1, './' + name1 + '/' + name1),
737
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
738
# all abspaths are Unicode, and encode them back into utf8.
739
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
740
self.assertIsInstance(dirdetail[0], str)
741
if isinstance(dirdetail[1], unicode):
742
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
743
dirblock = [list(info) for info in dirblock]
744
for info in dirblock:
745
self.assertIsInstance(info[4], unicode)
746
info[4] = info[4].encode('utf8')
748
for info in dirblock:
749
self.assertIsInstance(info[0], str)
750
self.assertIsInstance(info[1], str)
751
self.assertIsInstance(info[4], str)
752
# Remove the stat information
753
new_dirblock.append((info[0], info[1], info[2], info[4]))
754
result.append((dirdetail, new_dirblock))
755
self.assertEqual(expected_dirblocks, result)
757
def test_unicode__walkdirs_unicode_to_utf8(self):
758
"""walkdirs_unicode_to_utf8 should be a safe fallback everywhere
760
The abspath portion should be in unicode
762
name0u = u'0file-\xb6'
763
name1u = u'1dir-\u062c\u0648'
764
name2u = u'2file-\u0633'
768
name1u + '/' + name0u,
769
name1u + '/' + name1u + '/',
773
self.build_tree(tree)
775
raise TestSkipped('Could not represent Unicode chars'
776
' in current encoding.')
777
name0 = name0u.encode('utf8')
778
name1 = name1u.encode('utf8')
779
name2 = name2u.encode('utf8')
781
# All of the abspaths should be in unicode, all of the relative paths
783
expected_dirblocks = [
785
[(name0, name0, 'file', './' + name0u),
786
(name1, name1, 'directory', './' + name1u),
787
(name2, name2, 'file', './' + name2u),
790
((name1, './' + name1u),
791
[(name1 + '/' + name0, name0, 'file', './' + name1u
793
(name1 + '/' + name1, name1, 'directory', './' + name1u
797
((name1 + '/' + name1, './' + name1u + '/' + name1u),
802
result = list(osutils._walkdirs_unicode_to_utf8('.'))
803
self._filter_out_stat(result)
804
self.assertEqual(expected_dirblocks, result)
806
def assertPathCompare(self, path_less, path_greater):
807
"""check that path_less and path_greater compare correctly."""
808
self.assertEqual(0, osutils.compare_paths_prefix_order(
809
path_less, path_less))
810
self.assertEqual(0, osutils.compare_paths_prefix_order(
811
path_greater, path_greater))
812
self.assertEqual(-1, osutils.compare_paths_prefix_order(
813
path_less, path_greater))
814
self.assertEqual(1, osutils.compare_paths_prefix_order(
815
path_greater, path_less))
817
def test_compare_paths_prefix_order(self):
818
# root before all else
819
self.assertPathCompare("/", "/a")
821
self.assertPathCompare("/a", "/b")
822
self.assertPathCompare("/b", "/z")
823
# high dirs before lower.
824
self.assertPathCompare("/z", "/a/a")
825
# except if the deeper dir should be output first
826
self.assertPathCompare("/a/b/c", "/d/g")
827
# lexical betwen dirs of the same height
828
self.assertPathCompare("/a/z", "/z/z")
829
self.assertPathCompare("/a/c/z", "/a/d/e")
831
# this should also be consistent for no leading / paths
832
# root before all else
833
self.assertPathCompare("", "a")
835
self.assertPathCompare("a", "b")
836
self.assertPathCompare("b", "z")
837
# high dirs before lower.
838
self.assertPathCompare("z", "a/a")
839
# except if the deeper dir should be output first
840
self.assertPathCompare("a/b/c", "d/g")
841
# lexical betwen dirs of the same height
842
self.assertPathCompare("a/z", "z/z")
843
self.assertPathCompare("a/c/z", "a/d/e")
845
def test_path_prefix_sorting(self):
846
"""Doing a sort on path prefix should match our sample data."""
877
sorted(original_paths, key=osutils.path_prefix_key))
878
# using the comparison routine shoudl work too:
881
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
884
class TestCopyTree(TestCaseInTempDir):
886
def test_copy_basic_tree(self):
887
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
888
osutils.copy_tree('source', 'target')
889
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
890
self.assertEqual(['c'], os.listdir('target/b'))
892
def test_copy_tree_target_exists(self):
893
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
895
osutils.copy_tree('source', 'target')
896
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
897
self.assertEqual(['c'], os.listdir('target/b'))
899
def test_copy_tree_symlinks(self):
900
if not osutils.has_symlinks():
902
self.build_tree(['source/'])
903
os.symlink('a/generic/path', 'source/lnk')
904
osutils.copy_tree('source', 'target')
905
self.assertEqual(['lnk'], os.listdir('target'))
906
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
908
def test_copy_tree_handlers(self):
911
def file_handler(from_path, to_path):
912
processed_files.append(('f', from_path, to_path))
913
def dir_handler(from_path, to_path):
914
processed_files.append(('d', from_path, to_path))
915
def link_handler(from_path, to_path):
916
processed_links.append((from_path, to_path))
917
handlers = {'file':file_handler,
918
'directory':dir_handler,
919
'symlink':link_handler,
922
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
923
if osutils.has_symlinks():
924
os.symlink('a/generic/path', 'source/lnk')
925
osutils.copy_tree('source', 'target', handlers=handlers)
927
self.assertEqual([('d', 'source', 'target'),
928
('f', 'source/a', 'target/a'),
929
('d', 'source/b', 'target/b'),
930
('f', 'source/b/c', 'target/b/c'),
932
self.failIfExists('target')
933
if osutils.has_symlinks():
934
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
937
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
938
# [bialix] 2006/12/26
941
class TestSetUnsetEnv(TestCase):
942
"""Test updating the environment"""
945
super(TestSetUnsetEnv, self).setUp()
947
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
948
'Environment was not cleaned up properly.'
949
' Variable BZR_TEST_ENV_VAR should not exist.')
951
if 'BZR_TEST_ENV_VAR' in os.environ:
952
del os.environ['BZR_TEST_ENV_VAR']
954
self.addCleanup(cleanup)
957
"""Test that we can set an env variable"""
958
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
959
self.assertEqual(None, old)
960
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
962
def test_double_set(self):
963
"""Test that we get the old value out"""
964
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
965
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
966
self.assertEqual('foo', old)
967
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
969
def test_unicode(self):
970
"""Environment can only contain plain strings
972
So Unicode strings must be encoded.
974
# Try a few different characters, to see if we can get
975
# one that will be valid in the user_encoding
976
possible_vals = [u'm\xb5', u'\xe1', u'\u0410']
977
for uni_val in possible_vals:
979
env_val = uni_val.encode(bzrlib.user_encoding)
980
except UnicodeEncodeError:
981
# Try a different character
986
raise TestSkipped('Cannot find a unicode character that works in'
987
' encoding %s' % (bzrlib.user_encoding,))
989
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
990
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
992
def test_unset(self):
993
"""Test that passing None will remove the env var"""
994
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
995
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
996
self.assertEqual('foo', old)
997
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
998
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1001
class TestLocalTimeOffset(TestCase):
1003
def test_local_time_offset(self):
1004
"""Test that local_time_offset() returns a sane value."""
1005
offset = osutils.local_time_offset()
1006
self.assertTrue(isinstance(offset, int))
1007
# Test that the offset is no more than a eighteen hours in
1009
# Time zone handling is system specific, so it is difficult to
1010
# do more specific tests, but a value outside of this range is
1012
eighteen_hours = 18 * 3600
1013
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1015
def test_local_time_offset_with_timestamp(self):
1016
"""Test that local_time_offset() works with a timestamp."""
1017
offset = osutils.local_time_offset(1000000000.1234567)
1018
self.assertTrue(isinstance(offset, int))
1019
eighteen_hours = 18 * 3600
1020
self.assertTrue(-eighteen_hours < offset < eighteen_hours)