1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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."""
19
from cStringIO import StringIO
33
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
34
from bzrlib.osutils import (
36
is_inside_or_parent_of_any,
42
from bzrlib.tests import (
44
probe_unicode_in_user_encoding,
47
CaseInsCasePresFilenameFeature,
52
from bzrlib.tests.file_utils import (
55
from bzrlib.tests.test__walkdirs_win32 import Win32ReadDirFeature
58
class _UTF8DirReaderFeature(Feature):
62
from bzrlib import _readdir_pyx
63
self.reader = _readdir_pyx.UTF8DirReader
68
def feature_name(self):
69
return 'bzrlib._readdir_pyx'
71
UTF8DirReaderFeature = _UTF8DirReaderFeature()
74
class TestOSUtils(TestCaseInTempDir):
76
def test_contains_whitespace(self):
77
self.failUnless(osutils.contains_whitespace(u' '))
78
self.failUnless(osutils.contains_whitespace(u'hello there'))
79
self.failUnless(osutils.contains_whitespace(u'hellothere\n'))
80
self.failUnless(osutils.contains_whitespace(u'hello\nthere'))
81
self.failUnless(osutils.contains_whitespace(u'hello\rthere'))
82
self.failUnless(osutils.contains_whitespace(u'hello\tthere'))
84
# \xa0 is "Non-breaking-space" which on some python locales thinks it
85
# is whitespace, but we do not.
86
self.failIf(osutils.contains_whitespace(u''))
87
self.failIf(osutils.contains_whitespace(u'hellothere'))
88
self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
90
def test_fancy_rename(self):
91
# This should work everywhere
93
osutils.fancy_rename(a, b,
94
rename_func=os.rename,
95
unlink_func=os.unlink)
97
open('a', 'wb').write('something in a\n')
99
self.failIfExists('a')
100
self.failUnlessExists('b')
101
self.check_file_contents('b', 'something in a\n')
103
open('a', 'wb').write('new something in a\n')
106
self.check_file_contents('a', 'something in a\n')
108
def test_rename(self):
109
# Rename should be semi-atomic on all platforms
110
open('a', 'wb').write('something in a\n')
111
osutils.rename('a', 'b')
112
self.failIfExists('a')
113
self.failUnlessExists('b')
114
self.check_file_contents('b', 'something in a\n')
116
open('a', 'wb').write('new something in a\n')
117
osutils.rename('b', 'a')
119
self.check_file_contents('a', 'something in a\n')
121
# TODO: test fancy_rename using a MemoryTransport
123
def test_rename_change_case(self):
124
# on Windows we should be able to change filename case by rename
125
self.build_tree(['a', 'b/'])
126
osutils.rename('a', 'A')
127
osutils.rename('b', 'B')
128
# we can't use failUnlessExists on case-insensitive filesystem
129
# so try to check shape of the tree
130
shape = sorted(os.listdir('.'))
131
self.assertEquals(['A', 'B'], shape)
133
def test_01_rand_chars_empty(self):
134
result = osutils.rand_chars(0)
135
self.assertEqual(result, '')
137
def test_02_rand_chars_100(self):
138
result = osutils.rand_chars(100)
139
self.assertEqual(len(result), 100)
140
self.assertEqual(type(result), str)
141
self.assertContainsRe(result, r'^[a-z0-9]{100}$')
143
def test_is_inside(self):
144
is_inside = osutils.is_inside
145
self.assertTrue(is_inside('src', 'src/foo.c'))
146
self.assertFalse(is_inside('src', 'srccontrol'))
147
self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
148
self.assertTrue(is_inside('foo.c', 'foo.c'))
149
self.assertFalse(is_inside('foo.c', ''))
150
self.assertTrue(is_inside('', 'foo.c'))
152
def test_is_inside_any(self):
153
SRC_FOO_C = pathjoin('src', 'foo.c')
154
for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
155
(['src'], SRC_FOO_C),
158
self.assert_(is_inside_any(dirs, fn))
159
for dirs, fn in [(['src'], 'srccontrol'),
160
(['src'], 'srccontrol/foo')]:
161
self.assertFalse(is_inside_any(dirs, fn))
163
def test_is_inside_or_parent_of_any(self):
164
for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
165
(['src'], 'src/foo.c'),
166
(['src/bar.c'], 'src'),
167
(['src/bar.c', 'bla/foo.c'], 'src'),
170
self.assert_(is_inside_or_parent_of_any(dirs, fn))
172
for dirs, fn in [(['src'], 'srccontrol'),
173
(['srccontrol/foo.c'], 'src'),
174
(['src'], 'srccontrol/foo')]:
175
self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
177
def test_rmtree(self):
178
# Check to remove tree with read-only files/dirs
180
f = file('dir/file', 'w')
183
# would like to also try making the directory readonly, but at the
184
# moment python shutil.rmtree doesn't handle that properly - it would
185
# need to chmod the directory before removing things inside it - deferred
186
# for now -- mbp 20060505
187
# osutils.make_readonly('dir')
188
osutils.make_readonly('dir/file')
190
osutils.rmtree('dir')
192
self.failIfExists('dir/file')
193
self.failIfExists('dir')
195
def test_file_kind(self):
196
self.build_tree(['file', 'dir/'])
197
self.assertEquals('file', osutils.file_kind('file'))
198
self.assertEquals('directory', osutils.file_kind('dir/'))
199
if osutils.has_symlinks():
200
os.symlink('symlink', 'symlink')
201
self.assertEquals('symlink', osutils.file_kind('symlink'))
203
# TODO: jam 20060529 Test a block device
205
os.lstat('/dev/null')
207
if e.errno not in (errno.ENOENT,):
210
self.assertEquals('chardev', osutils.file_kind('/dev/null'))
212
mkfifo = getattr(os, 'mkfifo', None)
216
self.assertEquals('fifo', osutils.file_kind('fifo'))
220
AF_UNIX = getattr(socket, 'AF_UNIX', None)
222
s = socket.socket(AF_UNIX)
225
self.assertEquals('socket', osutils.file_kind('socket'))
229
def test_kind_marker(self):
230
self.assertEqual(osutils.kind_marker('file'), '')
231
self.assertEqual(osutils.kind_marker('directory'), '/')
232
self.assertEqual(osutils.kind_marker('symlink'), '@')
233
self.assertEqual(osutils.kind_marker('tree-reference'), '+')
235
def test_get_umask(self):
236
if sys.platform == 'win32':
237
# umask always returns '0', no way to set it
238
self.assertEqual(0, osutils.get_umask())
241
orig_umask = osutils.get_umask()
244
self.assertEqual(0222, osutils.get_umask())
246
self.assertEqual(0022, osutils.get_umask())
248
self.assertEqual(0002, osutils.get_umask())
250
self.assertEqual(0027, osutils.get_umask())
254
def assertFormatedDelta(self, expected, seconds):
255
"""Assert osutils.format_delta formats as expected"""
256
actual = osutils.format_delta(seconds)
257
self.assertEqual(expected, actual)
259
def test_format_delta(self):
260
self.assertFormatedDelta('0 seconds ago', 0)
261
self.assertFormatedDelta('1 second ago', 1)
262
self.assertFormatedDelta('10 seconds ago', 10)
263
self.assertFormatedDelta('59 seconds ago', 59)
264
self.assertFormatedDelta('89 seconds ago', 89)
265
self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
266
self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
267
self.assertFormatedDelta('3 minutes, 1 second ago', 181)
268
self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
269
self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
270
self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
271
self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
272
self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
273
self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
274
self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
275
self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
276
self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
277
self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
278
self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
279
self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
280
self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
281
self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
282
self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
284
# We handle when time steps the wrong direction because computers
285
# don't have synchronized clocks.
286
self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
287
self.assertFormatedDelta('1 second in the future', -1)
288
self.assertFormatedDelta('2 seconds in the future', -2)
290
def test_format_date(self):
291
self.assertRaises(errors.UnsupportedTimezoneFormat,
292
osutils.format_date, 0, timezone='foo')
293
self.assertIsInstance(osutils.format_date(0), str)
294
self.assertIsInstance(osutils.format_local_date(0), unicode)
295
# Testing for the actual value of the local weekday without
296
# duplicating the code from format_date is difficult.
297
# Instead blackbox.test_locale should check for localized
298
# dates once they do occur in output strings.
300
def test_dereference_path(self):
301
self.requireFeature(SymlinkFeature)
302
cwd = osutils.realpath('.')
304
bar_path = osutils.pathjoin(cwd, 'bar')
305
# Using './' to avoid bug #1213894 (first path component not
306
# dereferenced) in Python 2.4.1 and earlier
307
self.assertEqual(bar_path, osutils.realpath('./bar'))
308
os.symlink('bar', 'foo')
309
self.assertEqual(bar_path, osutils.realpath('./foo'))
311
# Does not dereference terminal symlinks
312
foo_path = osutils.pathjoin(cwd, 'foo')
313
self.assertEqual(foo_path, osutils.dereference_path('./foo'))
315
# Dereferences parent symlinks
317
baz_path = osutils.pathjoin(bar_path, 'baz')
318
self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
320
# Dereferences parent symlinks that are the first path element
321
self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
323
# Dereferences parent symlinks in absolute paths
324
foo_baz_path = osutils.pathjoin(foo_path, 'baz')
325
self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
327
def test_changing_access(self):
328
f = file('file', 'w')
332
# Make a file readonly
333
osutils.make_readonly('file')
334
mode = os.lstat('file').st_mode
335
self.assertEqual(mode, mode & 0777555)
337
# Make a file writable
338
osutils.make_writable('file')
339
mode = os.lstat('file').st_mode
340
self.assertEqual(mode, mode | 0200)
342
if osutils.has_symlinks():
343
# should not error when handed a symlink
344
os.symlink('nonexistent', 'dangling')
345
osutils.make_readonly('dangling')
346
osutils.make_writable('dangling')
348
def test_kind_marker(self):
349
self.assertEqual("", osutils.kind_marker("file"))
350
self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
351
self.assertEqual("@", osutils.kind_marker("symlink"))
352
self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
354
def test_host_os_dereferences_symlinks(self):
355
osutils.host_os_dereferences_symlinks()
358
class TestCanonicalRelPath(TestCaseInTempDir):
360
_test_needs_features = [CaseInsCasePresFilenameFeature]
362
def test_canonical_relpath_simple(self):
363
f = file('MixedCaseName', 'w')
365
self.failUnlessEqual(
366
canonical_relpath(self.test_base_dir, 'mixedcasename'),
367
'work/MixedCaseName')
369
def test_canonical_relpath_missing_tail(self):
370
os.mkdir('MixedCaseParent')
371
self.failUnlessEqual(
372
canonical_relpath(self.test_base_dir, 'mixedcaseparent/nochild'),
373
'work/MixedCaseParent/nochild')
376
class TestPumpFile(TestCase):
377
"""Test pumpfile method."""
379
# create a test datablock
380
self.block_size = 512
381
pattern = '0123456789ABCDEF'
382
self.test_data = pattern * (3 * self.block_size / len(pattern))
383
self.test_data_len = len(self.test_data)
385
def test_bracket_block_size(self):
386
"""Read data in blocks with the requested read size bracketing the
388
# make sure test data is larger than max read size
389
self.assertTrue(self.test_data_len > self.block_size)
391
from_file = FakeReadFile(self.test_data)
394
# read (max / 2) bytes and verify read size wasn't affected
395
num_bytes_to_read = self.block_size / 2
396
pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
397
self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
398
self.assertEqual(from_file.get_read_count(), 1)
400
# read (max) bytes and verify read size wasn't affected
401
num_bytes_to_read = self.block_size
402
from_file.reset_read_count()
403
pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
404
self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
405
self.assertEqual(from_file.get_read_count(), 1)
407
# read (max + 1) bytes and verify read size was limited
408
num_bytes_to_read = self.block_size + 1
409
from_file.reset_read_count()
410
pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
411
self.assertEqual(from_file.get_max_read_size(), self.block_size)
412
self.assertEqual(from_file.get_read_count(), 2)
414
# finish reading the rest of the data
415
num_bytes_to_read = self.test_data_len - to_file.tell()
416
pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
418
# report error if the data wasn't equal (we only report the size due
419
# to the length of the data)
420
response_data = to_file.getvalue()
421
if response_data != self.test_data:
422
message = "Data not equal. Expected %d bytes, received %d."
423
self.fail(message % (len(response_data), self.test_data_len))
425
def test_specified_size(self):
426
"""Request a transfer larger than the maximum block size and verify
427
that the maximum read doesn't exceed the block_size."""
428
# make sure test data is larger than max read size
429
self.assertTrue(self.test_data_len > self.block_size)
431
# retrieve data in blocks
432
from_file = FakeReadFile(self.test_data)
434
pumpfile(from_file, to_file, self.test_data_len, self.block_size)
436
# verify read size was equal to the maximum read size
437
self.assertTrue(from_file.get_max_read_size() > 0)
438
self.assertEqual(from_file.get_max_read_size(), self.block_size)
439
self.assertEqual(from_file.get_read_count(), 3)
441
# report error if the data wasn't equal (we only report the size due
442
# to the length of the data)
443
response_data = to_file.getvalue()
444
if response_data != self.test_data:
445
message = "Data not equal. Expected %d bytes, received %d."
446
self.fail(message % (len(response_data), self.test_data_len))
448
def test_to_eof(self):
449
"""Read to end-of-file and verify that the reads are not larger than
450
the maximum read size."""
451
# make sure test data is larger than max read size
452
self.assertTrue(self.test_data_len > self.block_size)
454
# retrieve data to EOF
455
from_file = FakeReadFile(self.test_data)
457
pumpfile(from_file, to_file, -1, self.block_size)
459
# verify read size was equal to the maximum read size
460
self.assertEqual(from_file.get_max_read_size(), self.block_size)
461
self.assertEqual(from_file.get_read_count(), 4)
463
# report error if the data wasn't equal (we only report the size due
464
# to the length of the data)
465
response_data = to_file.getvalue()
466
if response_data != self.test_data:
467
message = "Data not equal. Expected %d bytes, received %d."
468
self.fail(message % (len(response_data), self.test_data_len))
470
def test_defaults(self):
471
"""Verifies that the default arguments will read to EOF -- this
472
test verifies that any existing usages of pumpfile will not be broken
473
with this new version."""
474
# retrieve data using default (old) pumpfile method
475
from_file = FakeReadFile(self.test_data)
477
pumpfile(from_file, to_file)
479
# report error if the data wasn't equal (we only report the size due
480
# to the length of the data)
481
response_data = to_file.getvalue()
482
if response_data != self.test_data:
483
message = "Data not equal. Expected %d bytes, received %d."
484
self.fail(message % (len(response_data), self.test_data_len))
486
def test_report_activity(self):
488
def log_activity(length, direction):
489
activity.append((length, direction))
490
from_file = StringIO(self.test_data)
492
pumpfile(from_file, to_file, buff_size=500,
493
report_activity=log_activity, direction='read')
494
self.assertEqual([(500, 'read'), (500, 'read'), (500, 'read'),
495
(36, 'read')], activity)
497
from_file = StringIO(self.test_data)
500
pumpfile(from_file, to_file, buff_size=500,
501
report_activity=log_activity, direction='write')
502
self.assertEqual([(500, 'write'), (500, 'write'), (500, 'write'),
503
(36, 'write')], activity)
505
# And with a limited amount of data
506
from_file = StringIO(self.test_data)
509
pumpfile(from_file, to_file, buff_size=500, read_length=1028,
510
report_activity=log_activity, direction='read')
511
self.assertEqual([(500, 'read'), (500, 'read'), (28, 'read')], activity)
515
class TestPumpStringFile(TestCase):
517
def test_empty(self):
519
pump_string_file("", output)
520
self.assertEqual("", output.getvalue())
522
def test_more_than_segment_size(self):
524
pump_string_file("123456789", output, 2)
525
self.assertEqual("123456789", output.getvalue())
527
def test_segment_size(self):
529
pump_string_file("12", output, 2)
530
self.assertEqual("12", output.getvalue())
532
def test_segment_size_multiple(self):
534
pump_string_file("1234", output, 2)
535
self.assertEqual("1234", output.getvalue())
538
class TestSafeUnicode(TestCase):
540
def test_from_ascii_string(self):
541
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
543
def test_from_unicode_string_ascii_contents(self):
544
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
546
def test_from_unicode_string_unicode_contents(self):
547
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
549
def test_from_utf8_string(self):
550
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
552
def test_bad_utf8_string(self):
553
self.assertRaises(BzrBadParameterNotUnicode,
554
osutils.safe_unicode,
558
class TestSafeUtf8(TestCase):
560
def test_from_ascii_string(self):
562
self.assertEqual('foobar', osutils.safe_utf8(f))
564
def test_from_unicode_string_ascii_contents(self):
565
self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
567
def test_from_unicode_string_unicode_contents(self):
568
self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
570
def test_from_utf8_string(self):
571
self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
573
def test_bad_utf8_string(self):
574
self.assertRaises(BzrBadParameterNotUnicode,
575
osutils.safe_utf8, '\xbb\xbb')
578
class TestSafeRevisionId(TestCase):
580
def test_from_ascii_string(self):
581
# this shouldn't give a warning because it's getting an ascii string
582
self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
584
def test_from_unicode_string_ascii_contents(self):
585
self.assertEqual('bargam',
586
osutils.safe_revision_id(u'bargam', warn=False))
588
def test_from_unicode_deprecated(self):
589
self.assertEqual('bargam',
590
self.callDeprecated([osutils._revision_id_warning],
591
osutils.safe_revision_id, u'bargam'))
593
def test_from_unicode_string_unicode_contents(self):
594
self.assertEqual('bargam\xc2\xae',
595
osutils.safe_revision_id(u'bargam\xae', warn=False))
597
def test_from_utf8_string(self):
598
self.assertEqual('foo\xc2\xae',
599
osutils.safe_revision_id('foo\xc2\xae'))
602
"""Currently, None is a valid revision_id"""
603
self.assertEqual(None, osutils.safe_revision_id(None))
606
class TestSafeFileId(TestCase):
608
def test_from_ascii_string(self):
609
self.assertEqual('foobar', osutils.safe_file_id('foobar'))
611
def test_from_unicode_string_ascii_contents(self):
612
self.assertEqual('bargam', osutils.safe_file_id(u'bargam', warn=False))
614
def test_from_unicode_deprecated(self):
615
self.assertEqual('bargam',
616
self.callDeprecated([osutils._file_id_warning],
617
osutils.safe_file_id, u'bargam'))
619
def test_from_unicode_string_unicode_contents(self):
620
self.assertEqual('bargam\xc2\xae',
621
osutils.safe_file_id(u'bargam\xae', warn=False))
623
def test_from_utf8_string(self):
624
self.assertEqual('foo\xc2\xae',
625
osutils.safe_file_id('foo\xc2\xae'))
628
"""Currently, None is a valid revision_id"""
629
self.assertEqual(None, osutils.safe_file_id(None))
632
class TestWin32Funcs(TestCase):
633
"""Test that the _win32 versions of os utilities return appropriate paths."""
635
def test_abspath(self):
636
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
637
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
638
self.assertEqual('//HOST/path', osutils._win32_abspath(r'\\HOST\path'))
639
self.assertEqual('//HOST/path', osutils._win32_abspath('//HOST/path'))
641
def test_realpath(self):
642
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
643
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
645
def test_pathjoin(self):
646
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
647
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
648
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
649
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
650
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
651
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
653
def test_normpath(self):
654
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
655
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
657
def test_getcwd(self):
658
cwd = osutils._win32_getcwd()
659
os_cwd = os.getcwdu()
660
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
661
# win32 is inconsistent whether it returns lower or upper case
662
# and even if it was consistent the user might type the other
663
# so we force it to uppercase
664
# running python.exe under cmd.exe return capital C:\\
665
# running win32 python inside a cygwin shell returns lowercase
666
self.assertEqual(os_cwd[0].upper(), cwd[0])
668
def test_fixdrive(self):
669
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
670
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
671
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
673
def test_win98_abspath(self):
675
self.assertEqual('C:/foo', osutils._win98_abspath('C:\\foo'))
676
self.assertEqual('C:/foo', osutils._win98_abspath('C:/foo'))
678
self.assertEqual('//HOST/path', osutils._win98_abspath(r'\\HOST\path'))
679
self.assertEqual('//HOST/path', osutils._win98_abspath('//HOST/path'))
681
cwd = osutils.getcwd().rstrip('/')
682
drive = osutils._nt_splitdrive(cwd)[0]
683
self.assertEqual(cwd+'/path', osutils._win98_abspath('path'))
684
self.assertEqual(drive+'/path', osutils._win98_abspath('/path'))
687
self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
690
class TestWin32FuncsDirs(TestCaseInTempDir):
691
"""Test win32 functions that create files."""
693
def test_getcwd(self):
694
if win32utils.winver == 'Windows 98':
695
raise TestSkipped('Windows 98 cannot handle unicode filenames')
696
# Make sure getcwd can handle unicode filenames
700
raise TestSkipped("Unable to create Unicode filename")
703
# TODO: jam 20060427 This will probably fail on Mac OSX because
704
# it will change the normalization of B\xe5gfors
705
# Consider using a different unicode character, or make
706
# osutils.getcwd() renormalize the path.
707
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
709
def test_minimum_path_selection(self):
710
self.assertEqual(set(),
711
osutils.minimum_path_selection([]))
712
self.assertEqual(set(['a', 'b']),
713
osutils.minimum_path_selection(['a', 'b']))
714
self.assertEqual(set(['a/', 'b']),
715
osutils.minimum_path_selection(['a/', 'b']))
716
self.assertEqual(set(['a/', 'b']),
717
osutils.minimum_path_selection(['a/c', 'a/', 'b']))
719
def test_mkdtemp(self):
720
tmpdir = osutils._win32_mkdtemp(dir='.')
721
self.assertFalse('\\' in tmpdir)
723
def test_rename(self):
731
osutils._win32_rename('b', 'a')
732
self.failUnlessExists('a')
733
self.failIfExists('b')
734
self.assertFileEqual('baz\n', 'a')
736
def test_rename_missing_file(self):
742
osutils._win32_rename('b', 'a')
743
except (IOError, OSError), e:
744
self.assertEqual(errno.ENOENT, e.errno)
745
self.assertFileEqual('foo\n', 'a')
747
def test_rename_missing_dir(self):
750
osutils._win32_rename('b', 'a')
751
except (IOError, OSError), e:
752
self.assertEqual(errno.ENOENT, e.errno)
754
def test_rename_current_dir(self):
757
# You can't rename the working directory
758
# doing rename non-existant . usually
759
# just raises ENOENT, since non-existant
762
osutils._win32_rename('b', '.')
763
except (IOError, OSError), e:
764
self.assertEqual(errno.ENOENT, e.errno)
766
def test_splitpath(self):
767
def check(expected, path):
768
self.assertEqual(expected, osutils.splitpath(path))
771
check(['a', 'b'], 'a/b')
772
check(['a', 'b'], 'a/./b')
773
check(['a', '.b'], 'a/.b')
774
check(['a', '.b'], 'a\\.b')
776
self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
779
class TestMacFuncsDirs(TestCaseInTempDir):
780
"""Test mac special functions that require directories."""
782
def test_getcwd(self):
783
# On Mac, this will actually create Ba\u030agfors
784
# but chdir will still work, because it accepts both paths
786
os.mkdir(u'B\xe5gfors')
788
raise TestSkipped("Unable to create Unicode filename")
790
os.chdir(u'B\xe5gfors')
791
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
793
def test_getcwd_nonnorm(self):
794
# Test that _mac_getcwd() will normalize this path
796
os.mkdir(u'Ba\u030agfors')
798
raise TestSkipped("Unable to create Unicode filename")
800
os.chdir(u'Ba\u030agfors')
801
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
804
class TestChunksToLines(TestCase):
806
def test_smoketest(self):
807
self.assertEqual(['foo\n', 'bar\n', 'baz\n'],
808
osutils.chunks_to_lines(['foo\nbar', '\nbaz\n']))
809
self.assertEqual(['foo\n', 'bar\n', 'baz\n'],
810
osutils.chunks_to_lines(['foo\n', 'bar\n', 'baz\n']))
812
def test_osutils_binding(self):
813
from bzrlib.tests import test__chunks_to_lines
814
if test__chunks_to_lines.CompiledChunksToLinesFeature.available():
815
from bzrlib._chunks_to_lines_pyx import chunks_to_lines
817
from bzrlib._chunks_to_lines_py import chunks_to_lines
818
self.assertIs(chunks_to_lines, osutils.chunks_to_lines)
821
class TestSplitLines(TestCase):
823
def test_split_unicode(self):
824
self.assertEqual([u'foo\n', u'bar\xae'],
825
osutils.split_lines(u'foo\nbar\xae'))
826
self.assertEqual([u'foo\n', u'bar\xae\n'],
827
osutils.split_lines(u'foo\nbar\xae\n'))
829
def test_split_with_carriage_returns(self):
830
self.assertEqual(['foo\rbar\n'],
831
osutils.split_lines('foo\rbar\n'))
834
class TestWalkDirs(TestCaseInTempDir):
836
def test_walkdirs(self):
845
self.build_tree(tree)
846
expected_dirblocks = [
848
[('0file', '0file', 'file'),
849
('1dir', '1dir', 'directory'),
850
('2file', '2file', 'file'),
854
[('1dir/0file', '0file', 'file'),
855
('1dir/1dir', '1dir', 'directory'),
858
(('1dir/1dir', './1dir/1dir'),
865
for dirdetail, dirblock in osutils.walkdirs('.'):
866
if len(dirblock) and dirblock[0][1] == '.bzr':
867
# this tests the filtering of selected paths
870
result.append((dirdetail, dirblock))
872
self.assertTrue(found_bzrdir)
873
self.assertEqual(expected_dirblocks,
874
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
875
# you can search a subdir only, with a supplied prefix.
877
for dirblock in osutils.walkdirs('./1dir', '1dir'):
878
result.append(dirblock)
879
self.assertEqual(expected_dirblocks[1:],
880
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
882
def test_walkdirs_os_error(self):
883
# <https://bugs.edge.launchpad.net/bzr/+bug/338653>
884
# Pyrex readdir didn't raise useful messages if it had an error
885
# reading the directory
886
if sys.platform == 'win32':
887
raise tests.TestNotApplicable(
888
"readdir IOError not tested on win32")
889
os.mkdir("test-unreadable")
890
os.chmod("test-unreadable", 0000)
891
# must chmod it back so that it can be removed
892
self.addCleanup(lambda: os.chmod("test-unreadable", 0700))
893
# The error is not raised until the generator is actually evaluated.
894
# (It would be ok if it happened earlier but at the moment it
896
e = self.assertRaises(OSError, list,
897
osutils._walkdirs_utf8("."))
898
self.assertEquals(e.filename, './test-unreadable')
899
self.assertEquals(str(e),
900
"[Errno 13] chdir: Permission denied: './test-unreadable'")
902
def test__walkdirs_utf8(self):
911
self.build_tree(tree)
912
expected_dirblocks = [
914
[('0file', '0file', 'file'),
915
('1dir', '1dir', 'directory'),
916
('2file', '2file', 'file'),
920
[('1dir/0file', '0file', 'file'),
921
('1dir/1dir', '1dir', 'directory'),
924
(('1dir/1dir', './1dir/1dir'),
931
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
932
if len(dirblock) and dirblock[0][1] == '.bzr':
933
# this tests the filtering of selected paths
936
result.append((dirdetail, dirblock))
938
self.assertTrue(found_bzrdir)
939
self.assertEqual(expected_dirblocks,
940
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
941
# you can search a subdir only, with a supplied prefix.
943
for dirblock in osutils.walkdirs('./1dir', '1dir'):
944
result.append(dirblock)
945
self.assertEqual(expected_dirblocks[1:],
946
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
948
def _filter_out_stat(self, result):
949
"""Filter out the stat value from the walkdirs result"""
950
for dirdetail, dirblock in result:
952
for info in dirblock:
953
# Ignore info[3] which is the stat
954
new_dirblock.append((info[0], info[1], info[2], info[4]))
955
dirblock[:] = new_dirblock
957
def _save_platform_info(self):
958
cur_winver = win32utils.winver
959
cur_fs_enc = osutils._fs_enc
960
cur_dir_reader = osutils._selected_dir_reader
962
win32utils.winver = cur_winver
963
osutils._fs_enc = cur_fs_enc
964
osutils._selected_dir_reader = cur_dir_reader
965
self.addCleanup(restore)
967
def assertReadFSDirIs(self, expected):
968
"""Assert the right implementation for _walkdirs_utf8 is chosen."""
969
# Force it to redetect
970
osutils._selected_dir_reader = None
971
# Nothing to list, but should still trigger the selection logic
972
self.assertEqual([(('', '.'), [])], list(osutils._walkdirs_utf8('.')))
973
self.assertIsInstance(osutils._selected_dir_reader, expected)
975
def test_force_walkdirs_utf8_fs_utf8(self):
976
self.requireFeature(UTF8DirReaderFeature)
977
self._save_platform_info()
978
win32utils.winver = None # Avoid the win32 detection code
979
osutils._fs_enc = 'UTF-8'
980
self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
982
def test_force_walkdirs_utf8_fs_ascii(self):
983
self.requireFeature(UTF8DirReaderFeature)
984
self._save_platform_info()
985
win32utils.winver = None # Avoid the win32 detection code
986
osutils._fs_enc = 'US-ASCII'
987
self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
989
def test_force_walkdirs_utf8_fs_ANSI(self):
990
self.requireFeature(UTF8DirReaderFeature)
991
self._save_platform_info()
992
win32utils.winver = None # Avoid the win32 detection code
993
osutils._fs_enc = 'ANSI_X3.4-1968'
994
self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
996
def test_force_walkdirs_utf8_fs_latin1(self):
997
self._save_platform_info()
998
win32utils.winver = None # Avoid the win32 detection code
999
osutils._fs_enc = 'latin1'
1000
self.assertReadFSDirIs(osutils.UnicodeDirReader)
1002
def test_force_walkdirs_utf8_nt(self):
1003
# Disabled because the thunk of the whole walkdirs api is disabled.
1004
self.requireFeature(Win32ReadDirFeature)
1005
self._save_platform_info()
1006
win32utils.winver = 'Windows NT'
1007
from bzrlib._walkdirs_win32 import Win32ReadDir
1008
self.assertReadFSDirIs(Win32ReadDir)
1010
def test_force_walkdirs_utf8_98(self):
1011
self.requireFeature(Win32ReadDirFeature)
1012
self._save_platform_info()
1013
win32utils.winver = 'Windows 98'
1014
self.assertReadFSDirIs(osutils.UnicodeDirReader)
1016
def test_unicode_walkdirs(self):
1017
"""Walkdirs should always return unicode paths."""
1018
name0 = u'0file-\xb6'
1019
name1 = u'1dir-\u062c\u0648'
1020
name2 = u'2file-\u0633'
1024
name1 + '/' + name0,
1025
name1 + '/' + name1 + '/',
1029
self.build_tree(tree)
1030
except UnicodeError:
1031
raise TestSkipped('Could not represent Unicode chars'
1032
' in current encoding.')
1033
expected_dirblocks = [
1035
[(name0, name0, 'file', './' + name0),
1036
(name1, name1, 'directory', './' + name1),
1037
(name2, name2, 'file', './' + name2),
1040
((name1, './' + name1),
1041
[(name1 + '/' + name0, name0, 'file', './' + name1
1043
(name1 + '/' + name1, name1, 'directory', './' + name1
1047
((name1 + '/' + name1, './' + name1 + '/' + name1),
1052
result = list(osutils.walkdirs('.'))
1053
self._filter_out_stat(result)
1054
self.assertEqual(expected_dirblocks, result)
1055
result = list(osutils.walkdirs(u'./'+name1, name1))
1056
self._filter_out_stat(result)
1057
self.assertEqual(expected_dirblocks[1:], result)
1059
def test_unicode__walkdirs_utf8(self):
1060
"""Walkdirs_utf8 should always return utf8 paths.
1062
The abspath portion might be in unicode or utf-8
1064
name0 = u'0file-\xb6'
1065
name1 = u'1dir-\u062c\u0648'
1066
name2 = u'2file-\u0633'
1070
name1 + '/' + name0,
1071
name1 + '/' + name1 + '/',
1075
self.build_tree(tree)
1076
except UnicodeError:
1077
raise TestSkipped('Could not represent Unicode chars'
1078
' in current encoding.')
1079
name0 = name0.encode('utf8')
1080
name1 = name1.encode('utf8')
1081
name2 = name2.encode('utf8')
1083
expected_dirblocks = [
1085
[(name0, name0, 'file', './' + name0),
1086
(name1, name1, 'directory', './' + name1),
1087
(name2, name2, 'file', './' + name2),
1090
((name1, './' + name1),
1091
[(name1 + '/' + name0, name0, 'file', './' + name1
1093
(name1 + '/' + name1, name1, 'directory', './' + name1
1097
((name1 + '/' + name1, './' + name1 + '/' + name1),
1103
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
1104
# all abspaths are Unicode, and encode them back into utf8.
1105
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
1106
self.assertIsInstance(dirdetail[0], str)
1107
if isinstance(dirdetail[1], unicode):
1108
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
1109
dirblock = [list(info) for info in dirblock]
1110
for info in dirblock:
1111
self.assertIsInstance(info[4], unicode)
1112
info[4] = info[4].encode('utf8')
1114
for info in dirblock:
1115
self.assertIsInstance(info[0], str)
1116
self.assertIsInstance(info[1], str)
1117
self.assertIsInstance(info[4], str)
1118
# Remove the stat information
1119
new_dirblock.append((info[0], info[1], info[2], info[4]))
1120
result.append((dirdetail, new_dirblock))
1121
self.assertEqual(expected_dirblocks, result)
1123
def test__walkdirs_utf8_with_unicode_fs(self):
1124
"""UnicodeDirReader should be a safe fallback everywhere
1126
The abspath portion should be in unicode
1128
# Use the unicode reader. TODO: split into driver-and-driven unit
1130
self._save_platform_info()
1131
osutils._selected_dir_reader = osutils.UnicodeDirReader()
1132
name0u = u'0file-\xb6'
1133
name1u = u'1dir-\u062c\u0648'
1134
name2u = u'2file-\u0633'
1138
name1u + '/' + name0u,
1139
name1u + '/' + name1u + '/',
1143
self.build_tree(tree)
1144
except UnicodeError:
1145
raise TestSkipped('Could not represent Unicode chars'
1146
' in current encoding.')
1147
name0 = name0u.encode('utf8')
1148
name1 = name1u.encode('utf8')
1149
name2 = name2u.encode('utf8')
1151
# All of the abspaths should be in unicode, all of the relative paths
1153
expected_dirblocks = [
1155
[(name0, name0, 'file', './' + name0u),
1156
(name1, name1, 'directory', './' + name1u),
1157
(name2, name2, 'file', './' + name2u),
1160
((name1, './' + name1u),
1161
[(name1 + '/' + name0, name0, 'file', './' + name1u
1163
(name1 + '/' + name1, name1, 'directory', './' + name1u
1167
((name1 + '/' + name1, './' + name1u + '/' + name1u),
1172
result = list(osutils._walkdirs_utf8('.'))
1173
self._filter_out_stat(result)
1174
self.assertEqual(expected_dirblocks, result)
1176
def test__walkdirs_utf8_win32readdir(self):
1177
self.requireFeature(Win32ReadDirFeature)
1178
self.requireFeature(tests.UnicodeFilenameFeature)
1179
from bzrlib._walkdirs_win32 import Win32ReadDir
1180
self._save_platform_info()
1181
osutils._selected_dir_reader = Win32ReadDir()
1182
name0u = u'0file-\xb6'
1183
name1u = u'1dir-\u062c\u0648'
1184
name2u = u'2file-\u0633'
1188
name1u + '/' + name0u,
1189
name1u + '/' + name1u + '/',
1192
self.build_tree(tree)
1193
name0 = name0u.encode('utf8')
1194
name1 = name1u.encode('utf8')
1195
name2 = name2u.encode('utf8')
1197
# All of the abspaths should be in unicode, all of the relative paths
1199
expected_dirblocks = [
1201
[(name0, name0, 'file', './' + name0u),
1202
(name1, name1, 'directory', './' + name1u),
1203
(name2, name2, 'file', './' + name2u),
1206
((name1, './' + name1u),
1207
[(name1 + '/' + name0, name0, 'file', './' + name1u
1209
(name1 + '/' + name1, name1, 'directory', './' + name1u
1213
((name1 + '/' + name1, './' + name1u + '/' + name1u),
1218
result = list(osutils._walkdirs_utf8(u'.'))
1219
self._filter_out_stat(result)
1220
self.assertEqual(expected_dirblocks, result)
1222
def assertStatIsCorrect(self, path, win32stat):
1223
os_stat = os.stat(path)
1224
self.assertEqual(os_stat.st_size, win32stat.st_size)
1225
self.assertAlmostEqual(os_stat.st_mtime, win32stat.st_mtime, places=4)
1226
self.assertAlmostEqual(os_stat.st_ctime, win32stat.st_ctime, places=4)
1227
self.assertAlmostEqual(os_stat.st_atime, win32stat.st_atime, places=4)
1228
self.assertEqual(os_stat.st_dev, win32stat.st_dev)
1229
self.assertEqual(os_stat.st_ino, win32stat.st_ino)
1230
self.assertEqual(os_stat.st_mode, win32stat.st_mode)
1232
def test__walkdirs_utf_win32_find_file_stat_file(self):
1233
"""make sure our Stat values are valid"""
1234
self.requireFeature(Win32ReadDirFeature)
1235
self.requireFeature(tests.UnicodeFilenameFeature)
1236
from bzrlib._walkdirs_win32 import Win32ReadDir
1237
name0u = u'0file-\xb6'
1238
name0 = name0u.encode('utf8')
1239
self.build_tree([name0u])
1240
# I hate to sleep() here, but I'm trying to make the ctime different
1243
f = open(name0u, 'ab')
1245
f.write('just a small update')
1249
result = Win32ReadDir().read_dir('', u'.')
1251
self.assertEqual((name0, name0, 'file'), entry[:3])
1252
self.assertEqual(u'./' + name0u, entry[4])
1253
self.assertStatIsCorrect(entry[4], entry[3])
1254
self.assertNotEqual(entry[3].st_mtime, entry[3].st_ctime)
1256
def test__walkdirs_utf_win32_find_file_stat_directory(self):
1257
"""make sure our Stat values are valid"""
1258
self.requireFeature(Win32ReadDirFeature)
1259
self.requireFeature(tests.UnicodeFilenameFeature)
1260
from bzrlib._walkdirs_win32 import Win32ReadDir
1261
name0u = u'0dir-\u062c\u0648'
1262
name0 = name0u.encode('utf8')
1263
self.build_tree([name0u + '/'])
1265
result = Win32ReadDir().read_dir('', u'.')
1267
self.assertEqual((name0, name0, 'directory'), entry[:3])
1268
self.assertEqual(u'./' + name0u, entry[4])
1269
self.assertStatIsCorrect(entry[4], entry[3])
1271
def assertPathCompare(self, path_less, path_greater):
1272
"""check that path_less and path_greater compare correctly."""
1273
self.assertEqual(0, osutils.compare_paths_prefix_order(
1274
path_less, path_less))
1275
self.assertEqual(0, osutils.compare_paths_prefix_order(
1276
path_greater, path_greater))
1277
self.assertEqual(-1, osutils.compare_paths_prefix_order(
1278
path_less, path_greater))
1279
self.assertEqual(1, osutils.compare_paths_prefix_order(
1280
path_greater, path_less))
1282
def test_compare_paths_prefix_order(self):
1283
# root before all else
1284
self.assertPathCompare("/", "/a")
1285
# alpha within a dir
1286
self.assertPathCompare("/a", "/b")
1287
self.assertPathCompare("/b", "/z")
1288
# high dirs before lower.
1289
self.assertPathCompare("/z", "/a/a")
1290
# except if the deeper dir should be output first
1291
self.assertPathCompare("/a/b/c", "/d/g")
1292
# lexical betwen dirs of the same height
1293
self.assertPathCompare("/a/z", "/z/z")
1294
self.assertPathCompare("/a/c/z", "/a/d/e")
1296
# this should also be consistent for no leading / paths
1297
# root before all else
1298
self.assertPathCompare("", "a")
1299
# alpha within a dir
1300
self.assertPathCompare("a", "b")
1301
self.assertPathCompare("b", "z")
1302
# high dirs before lower.
1303
self.assertPathCompare("z", "a/a")
1304
# except if the deeper dir should be output first
1305
self.assertPathCompare("a/b/c", "d/g")
1306
# lexical betwen dirs of the same height
1307
self.assertPathCompare("a/z", "z/z")
1308
self.assertPathCompare("a/c/z", "a/d/e")
1310
def test_path_prefix_sorting(self):
1311
"""Doing a sort on path prefix should match our sample data."""
1326
dir_sorted_paths = [
1342
sorted(original_paths, key=osutils.path_prefix_key))
1343
# using the comparison routine shoudl work too:
1346
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
1349
class TestCopyTree(TestCaseInTempDir):
1351
def test_copy_basic_tree(self):
1352
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
1353
osutils.copy_tree('source', 'target')
1354
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
1355
self.assertEqual(['c'], os.listdir('target/b'))
1357
def test_copy_tree_target_exists(self):
1358
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
1360
osutils.copy_tree('source', 'target')
1361
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
1362
self.assertEqual(['c'], os.listdir('target/b'))
1364
def test_copy_tree_symlinks(self):
1365
self.requireFeature(SymlinkFeature)
1366
self.build_tree(['source/'])
1367
os.symlink('a/generic/path', 'source/lnk')
1368
osutils.copy_tree('source', 'target')
1369
self.assertEqual(['lnk'], os.listdir('target'))
1370
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
1372
def test_copy_tree_handlers(self):
1373
processed_files = []
1374
processed_links = []
1375
def file_handler(from_path, to_path):
1376
processed_files.append(('f', from_path, to_path))
1377
def dir_handler(from_path, to_path):
1378
processed_files.append(('d', from_path, to_path))
1379
def link_handler(from_path, to_path):
1380
processed_links.append((from_path, to_path))
1381
handlers = {'file':file_handler,
1382
'directory':dir_handler,
1383
'symlink':link_handler,
1386
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
1387
if osutils.has_symlinks():
1388
os.symlink('a/generic/path', 'source/lnk')
1389
osutils.copy_tree('source', 'target', handlers=handlers)
1391
self.assertEqual([('d', 'source', 'target'),
1392
('f', 'source/a', 'target/a'),
1393
('d', 'source/b', 'target/b'),
1394
('f', 'source/b/c', 'target/b/c'),
1396
self.failIfExists('target')
1397
if osutils.has_symlinks():
1398
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
1401
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
1402
# [bialix] 2006/12/26
1405
class TestSetUnsetEnv(TestCase):
1406
"""Test updating the environment"""
1409
super(TestSetUnsetEnv, self).setUp()
1411
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
1412
'Environment was not cleaned up properly.'
1413
' Variable BZR_TEST_ENV_VAR should not exist.')
1415
if 'BZR_TEST_ENV_VAR' in os.environ:
1416
del os.environ['BZR_TEST_ENV_VAR']
1418
self.addCleanup(cleanup)
1421
"""Test that we can set an env variable"""
1422
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1423
self.assertEqual(None, old)
1424
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
1426
def test_double_set(self):
1427
"""Test that we get the old value out"""
1428
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1429
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
1430
self.assertEqual('foo', old)
1431
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1433
def test_unicode(self):
1434
"""Environment can only contain plain strings
1436
So Unicode strings must be encoded.
1438
uni_val, env_val = probe_unicode_in_user_encoding()
1440
raise TestSkipped('Cannot find a unicode character that works in'
1441
' encoding %s' % (osutils.get_user_encoding(),))
1443
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1444
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1446
def test_unset(self):
1447
"""Test that passing None will remove the env var"""
1448
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1449
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1450
self.assertEqual('foo', old)
1451
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1452
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1455
class TestLocalTimeOffset(TestCase):
1457
def test_local_time_offset(self):
1458
"""Test that local_time_offset() returns a sane value."""
1459
offset = osutils.local_time_offset()
1460
self.assertTrue(isinstance(offset, int))
1461
# Test that the offset is no more than a eighteen hours in
1463
# Time zone handling is system specific, so it is difficult to
1464
# do more specific tests, but a value outside of this range is
1466
eighteen_hours = 18 * 3600
1467
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1469
def test_local_time_offset_with_timestamp(self):
1470
"""Test that local_time_offset() works with a timestamp."""
1471
offset = osutils.local_time_offset(1000000000.1234567)
1472
self.assertTrue(isinstance(offset, int))
1473
eighteen_hours = 18 * 3600
1474
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1477
class TestShaFileByName(TestCaseInTempDir):
1479
def test_sha_empty(self):
1480
self.build_tree_contents([('foo', '')])
1481
expected_sha = osutils.sha_string('')
1482
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1484
def test_sha_mixed_endings(self):
1485
text = 'test\r\nwith\nall\rpossible line endings\r\n'
1486
self.build_tree_contents([('foo', text)])
1487
expected_sha = osutils.sha_string(text)
1488
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1491
class TestResourceLoading(TestCaseInTempDir):
1493
def test_resource_string(self):
1494
# test resource in bzrlib
1495
text = osutils.resource_string('bzrlib', 'debug.py')
1496
self.assertContainsRe(text, "debug_flags = set()")
1497
# test resource under bzrlib
1498
text = osutils.resource_string('bzrlib.ui', 'text.py')
1499
self.assertContainsRe(text, "class TextUIFactory")
1500
# test unsupported package
1501
self.assertRaises(errors.BzrError, osutils.resource_string, 'zzzz',
1503
# test unknown resource
1504
self.assertRaises(IOError, osutils.resource_string, 'bzrlib', 'yyy.xx')