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, osutils._walkdirs_utf8("."))
897
self.assertEquals('./test-unreadable', e.filename)
898
self.assertEquals(errno.EACCES, e.errno)
900
def test__walkdirs_utf8(self):
909
self.build_tree(tree)
910
expected_dirblocks = [
912
[('0file', '0file', 'file'),
913
('1dir', '1dir', 'directory'),
914
('2file', '2file', 'file'),
918
[('1dir/0file', '0file', 'file'),
919
('1dir/1dir', '1dir', 'directory'),
922
(('1dir/1dir', './1dir/1dir'),
929
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
930
if len(dirblock) and dirblock[0][1] == '.bzr':
931
# this tests the filtering of selected paths
934
result.append((dirdetail, dirblock))
936
self.assertTrue(found_bzrdir)
937
self.assertEqual(expected_dirblocks,
938
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
939
# you can search a subdir only, with a supplied prefix.
941
for dirblock in osutils.walkdirs('./1dir', '1dir'):
942
result.append(dirblock)
943
self.assertEqual(expected_dirblocks[1:],
944
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
946
def _filter_out_stat(self, result):
947
"""Filter out the stat value from the walkdirs result"""
948
for dirdetail, dirblock in result:
950
for info in dirblock:
951
# Ignore info[3] which is the stat
952
new_dirblock.append((info[0], info[1], info[2], info[4]))
953
dirblock[:] = new_dirblock
955
def _save_platform_info(self):
956
cur_winver = win32utils.winver
957
cur_fs_enc = osutils._fs_enc
958
cur_dir_reader = osutils._selected_dir_reader
960
win32utils.winver = cur_winver
961
osutils._fs_enc = cur_fs_enc
962
osutils._selected_dir_reader = cur_dir_reader
963
self.addCleanup(restore)
965
def assertReadFSDirIs(self, expected):
966
"""Assert the right implementation for _walkdirs_utf8 is chosen."""
967
# Force it to redetect
968
osutils._selected_dir_reader = None
969
# Nothing to list, but should still trigger the selection logic
970
self.assertEqual([(('', '.'), [])], list(osutils._walkdirs_utf8('.')))
971
self.assertIsInstance(osutils._selected_dir_reader, expected)
973
def test_force_walkdirs_utf8_fs_utf8(self):
974
self.requireFeature(UTF8DirReaderFeature)
975
self._save_platform_info()
976
win32utils.winver = None # Avoid the win32 detection code
977
osutils._fs_enc = 'UTF-8'
978
self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
980
def test_force_walkdirs_utf8_fs_ascii(self):
981
self.requireFeature(UTF8DirReaderFeature)
982
self._save_platform_info()
983
win32utils.winver = None # Avoid the win32 detection code
984
osutils._fs_enc = 'US-ASCII'
985
self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
987
def test_force_walkdirs_utf8_fs_ANSI(self):
988
self.requireFeature(UTF8DirReaderFeature)
989
self._save_platform_info()
990
win32utils.winver = None # Avoid the win32 detection code
991
osutils._fs_enc = 'ANSI_X3.4-1968'
992
self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
994
def test_force_walkdirs_utf8_fs_latin1(self):
995
self._save_platform_info()
996
win32utils.winver = None # Avoid the win32 detection code
997
osutils._fs_enc = 'latin1'
998
self.assertReadFSDirIs(osutils.UnicodeDirReader)
1000
def test_force_walkdirs_utf8_nt(self):
1001
# Disabled because the thunk of the whole walkdirs api is disabled.
1002
self.requireFeature(Win32ReadDirFeature)
1003
self._save_platform_info()
1004
win32utils.winver = 'Windows NT'
1005
from bzrlib._walkdirs_win32 import Win32ReadDir
1006
self.assertReadFSDirIs(Win32ReadDir)
1008
def test_force_walkdirs_utf8_98(self):
1009
self.requireFeature(Win32ReadDirFeature)
1010
self._save_platform_info()
1011
win32utils.winver = 'Windows 98'
1012
self.assertReadFSDirIs(osutils.UnicodeDirReader)
1014
def test_unicode_walkdirs(self):
1015
"""Walkdirs should always return unicode paths."""
1016
name0 = u'0file-\xb6'
1017
name1 = u'1dir-\u062c\u0648'
1018
name2 = u'2file-\u0633'
1022
name1 + '/' + name0,
1023
name1 + '/' + name1 + '/',
1027
self.build_tree(tree)
1028
except UnicodeError:
1029
raise TestSkipped('Could not represent Unicode chars'
1030
' in current encoding.')
1031
expected_dirblocks = [
1033
[(name0, name0, 'file', './' + name0),
1034
(name1, name1, 'directory', './' + name1),
1035
(name2, name2, 'file', './' + name2),
1038
((name1, './' + name1),
1039
[(name1 + '/' + name0, name0, 'file', './' + name1
1041
(name1 + '/' + name1, name1, 'directory', './' + name1
1045
((name1 + '/' + name1, './' + name1 + '/' + name1),
1050
result = list(osutils.walkdirs('.'))
1051
self._filter_out_stat(result)
1052
self.assertEqual(expected_dirblocks, result)
1053
result = list(osutils.walkdirs(u'./'+name1, name1))
1054
self._filter_out_stat(result)
1055
self.assertEqual(expected_dirblocks[1:], result)
1057
def test_unicode__walkdirs_utf8(self):
1058
"""Walkdirs_utf8 should always return utf8 paths.
1060
The abspath portion might be in unicode or utf-8
1062
name0 = u'0file-\xb6'
1063
name1 = u'1dir-\u062c\u0648'
1064
name2 = u'2file-\u0633'
1068
name1 + '/' + name0,
1069
name1 + '/' + name1 + '/',
1073
self.build_tree(tree)
1074
except UnicodeError:
1075
raise TestSkipped('Could not represent Unicode chars'
1076
' in current encoding.')
1077
name0 = name0.encode('utf8')
1078
name1 = name1.encode('utf8')
1079
name2 = name2.encode('utf8')
1081
expected_dirblocks = [
1083
[(name0, name0, 'file', './' + name0),
1084
(name1, name1, 'directory', './' + name1),
1085
(name2, name2, 'file', './' + name2),
1088
((name1, './' + name1),
1089
[(name1 + '/' + name0, name0, 'file', './' + name1
1091
(name1 + '/' + name1, name1, 'directory', './' + name1
1095
((name1 + '/' + name1, './' + name1 + '/' + name1),
1101
# For ease in testing, if walkdirs_utf8 returns Unicode, assert that
1102
# all abspaths are Unicode, and encode them back into utf8.
1103
for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
1104
self.assertIsInstance(dirdetail[0], str)
1105
if isinstance(dirdetail[1], unicode):
1106
dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
1107
dirblock = [list(info) for info in dirblock]
1108
for info in dirblock:
1109
self.assertIsInstance(info[4], unicode)
1110
info[4] = info[4].encode('utf8')
1112
for info in dirblock:
1113
self.assertIsInstance(info[0], str)
1114
self.assertIsInstance(info[1], str)
1115
self.assertIsInstance(info[4], str)
1116
# Remove the stat information
1117
new_dirblock.append((info[0], info[1], info[2], info[4]))
1118
result.append((dirdetail, new_dirblock))
1119
self.assertEqual(expected_dirblocks, result)
1121
def test__walkdirs_utf8_with_unicode_fs(self):
1122
"""UnicodeDirReader should be a safe fallback everywhere
1124
The abspath portion should be in unicode
1126
# Use the unicode reader. TODO: split into driver-and-driven unit
1128
self._save_platform_info()
1129
osutils._selected_dir_reader = osutils.UnicodeDirReader()
1130
name0u = u'0file-\xb6'
1131
name1u = u'1dir-\u062c\u0648'
1132
name2u = u'2file-\u0633'
1136
name1u + '/' + name0u,
1137
name1u + '/' + name1u + '/',
1141
self.build_tree(tree)
1142
except UnicodeError:
1143
raise TestSkipped('Could not represent Unicode chars'
1144
' in current encoding.')
1145
name0 = name0u.encode('utf8')
1146
name1 = name1u.encode('utf8')
1147
name2 = name2u.encode('utf8')
1149
# All of the abspaths should be in unicode, all of the relative paths
1151
expected_dirblocks = [
1153
[(name0, name0, 'file', './' + name0u),
1154
(name1, name1, 'directory', './' + name1u),
1155
(name2, name2, 'file', './' + name2u),
1158
((name1, './' + name1u),
1159
[(name1 + '/' + name0, name0, 'file', './' + name1u
1161
(name1 + '/' + name1, name1, 'directory', './' + name1u
1165
((name1 + '/' + name1, './' + name1u + '/' + name1u),
1170
result = list(osutils._walkdirs_utf8('.'))
1171
self._filter_out_stat(result)
1172
self.assertEqual(expected_dirblocks, result)
1174
def test__walkdirs_utf8_win32readdir(self):
1175
self.requireFeature(Win32ReadDirFeature)
1176
self.requireFeature(tests.UnicodeFilenameFeature)
1177
from bzrlib._walkdirs_win32 import Win32ReadDir
1178
self._save_platform_info()
1179
osutils._selected_dir_reader = Win32ReadDir()
1180
name0u = u'0file-\xb6'
1181
name1u = u'1dir-\u062c\u0648'
1182
name2u = u'2file-\u0633'
1186
name1u + '/' + name0u,
1187
name1u + '/' + name1u + '/',
1190
self.build_tree(tree)
1191
name0 = name0u.encode('utf8')
1192
name1 = name1u.encode('utf8')
1193
name2 = name2u.encode('utf8')
1195
# All of the abspaths should be in unicode, all of the relative paths
1197
expected_dirblocks = [
1199
[(name0, name0, 'file', './' + name0u),
1200
(name1, name1, 'directory', './' + name1u),
1201
(name2, name2, 'file', './' + name2u),
1204
((name1, './' + name1u),
1205
[(name1 + '/' + name0, name0, 'file', './' + name1u
1207
(name1 + '/' + name1, name1, 'directory', './' + name1u
1211
((name1 + '/' + name1, './' + name1u + '/' + name1u),
1216
result = list(osutils._walkdirs_utf8(u'.'))
1217
self._filter_out_stat(result)
1218
self.assertEqual(expected_dirblocks, result)
1220
def assertStatIsCorrect(self, path, win32stat):
1221
os_stat = os.stat(path)
1222
self.assertEqual(os_stat.st_size, win32stat.st_size)
1223
self.assertAlmostEqual(os_stat.st_mtime, win32stat.st_mtime, places=4)
1224
self.assertAlmostEqual(os_stat.st_ctime, win32stat.st_ctime, places=4)
1225
self.assertAlmostEqual(os_stat.st_atime, win32stat.st_atime, places=4)
1226
self.assertEqual(os_stat.st_dev, win32stat.st_dev)
1227
self.assertEqual(os_stat.st_ino, win32stat.st_ino)
1228
self.assertEqual(os_stat.st_mode, win32stat.st_mode)
1230
def test__walkdirs_utf_win32_find_file_stat_file(self):
1231
"""make sure our Stat values are valid"""
1232
self.requireFeature(Win32ReadDirFeature)
1233
self.requireFeature(tests.UnicodeFilenameFeature)
1234
from bzrlib._walkdirs_win32 import Win32ReadDir
1235
name0u = u'0file-\xb6'
1236
name0 = name0u.encode('utf8')
1237
self.build_tree([name0u])
1238
# I hate to sleep() here, but I'm trying to make the ctime different
1241
f = open(name0u, 'ab')
1243
f.write('just a small update')
1247
result = Win32ReadDir().read_dir('', u'.')
1249
self.assertEqual((name0, name0, 'file'), entry[:3])
1250
self.assertEqual(u'./' + name0u, entry[4])
1251
self.assertStatIsCorrect(entry[4], entry[3])
1252
self.assertNotEqual(entry[3].st_mtime, entry[3].st_ctime)
1254
def test__walkdirs_utf_win32_find_file_stat_directory(self):
1255
"""make sure our Stat values are valid"""
1256
self.requireFeature(Win32ReadDirFeature)
1257
self.requireFeature(tests.UnicodeFilenameFeature)
1258
from bzrlib._walkdirs_win32 import Win32ReadDir
1259
name0u = u'0dir-\u062c\u0648'
1260
name0 = name0u.encode('utf8')
1261
self.build_tree([name0u + '/'])
1263
result = Win32ReadDir().read_dir('', u'.')
1265
self.assertEqual((name0, name0, 'directory'), entry[:3])
1266
self.assertEqual(u'./' + name0u, entry[4])
1267
self.assertStatIsCorrect(entry[4], entry[3])
1269
def assertPathCompare(self, path_less, path_greater):
1270
"""check that path_less and path_greater compare correctly."""
1271
self.assertEqual(0, osutils.compare_paths_prefix_order(
1272
path_less, path_less))
1273
self.assertEqual(0, osutils.compare_paths_prefix_order(
1274
path_greater, path_greater))
1275
self.assertEqual(-1, osutils.compare_paths_prefix_order(
1276
path_less, path_greater))
1277
self.assertEqual(1, osutils.compare_paths_prefix_order(
1278
path_greater, path_less))
1280
def test_compare_paths_prefix_order(self):
1281
# root before all else
1282
self.assertPathCompare("/", "/a")
1283
# alpha within a dir
1284
self.assertPathCompare("/a", "/b")
1285
self.assertPathCompare("/b", "/z")
1286
# high dirs before lower.
1287
self.assertPathCompare("/z", "/a/a")
1288
# except if the deeper dir should be output first
1289
self.assertPathCompare("/a/b/c", "/d/g")
1290
# lexical betwen dirs of the same height
1291
self.assertPathCompare("/a/z", "/z/z")
1292
self.assertPathCompare("/a/c/z", "/a/d/e")
1294
# this should also be consistent for no leading / paths
1295
# root before all else
1296
self.assertPathCompare("", "a")
1297
# alpha within a dir
1298
self.assertPathCompare("a", "b")
1299
self.assertPathCompare("b", "z")
1300
# high dirs before lower.
1301
self.assertPathCompare("z", "a/a")
1302
# except if the deeper dir should be output first
1303
self.assertPathCompare("a/b/c", "d/g")
1304
# lexical betwen dirs of the same height
1305
self.assertPathCompare("a/z", "z/z")
1306
self.assertPathCompare("a/c/z", "a/d/e")
1308
def test_path_prefix_sorting(self):
1309
"""Doing a sort on path prefix should match our sample data."""
1324
dir_sorted_paths = [
1340
sorted(original_paths, key=osutils.path_prefix_key))
1341
# using the comparison routine shoudl work too:
1344
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
1347
class TestCopyTree(TestCaseInTempDir):
1349
def test_copy_basic_tree(self):
1350
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
1351
osutils.copy_tree('source', 'target')
1352
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
1353
self.assertEqual(['c'], os.listdir('target/b'))
1355
def test_copy_tree_target_exists(self):
1356
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
1358
osutils.copy_tree('source', 'target')
1359
self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
1360
self.assertEqual(['c'], os.listdir('target/b'))
1362
def test_copy_tree_symlinks(self):
1363
self.requireFeature(SymlinkFeature)
1364
self.build_tree(['source/'])
1365
os.symlink('a/generic/path', 'source/lnk')
1366
osutils.copy_tree('source', 'target')
1367
self.assertEqual(['lnk'], os.listdir('target'))
1368
self.assertEqual('a/generic/path', os.readlink('target/lnk'))
1370
def test_copy_tree_handlers(self):
1371
processed_files = []
1372
processed_links = []
1373
def file_handler(from_path, to_path):
1374
processed_files.append(('f', from_path, to_path))
1375
def dir_handler(from_path, to_path):
1376
processed_files.append(('d', from_path, to_path))
1377
def link_handler(from_path, to_path):
1378
processed_links.append((from_path, to_path))
1379
handlers = {'file':file_handler,
1380
'directory':dir_handler,
1381
'symlink':link_handler,
1384
self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
1385
if osutils.has_symlinks():
1386
os.symlink('a/generic/path', 'source/lnk')
1387
osutils.copy_tree('source', 'target', handlers=handlers)
1389
self.assertEqual([('d', 'source', 'target'),
1390
('f', 'source/a', 'target/a'),
1391
('d', 'source/b', 'target/b'),
1392
('f', 'source/b/c', 'target/b/c'),
1394
self.failIfExists('target')
1395
if osutils.has_symlinks():
1396
self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
1399
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
1400
# [bialix] 2006/12/26
1403
class TestSetUnsetEnv(TestCase):
1404
"""Test updating the environment"""
1407
super(TestSetUnsetEnv, self).setUp()
1409
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
1410
'Environment was not cleaned up properly.'
1411
' Variable BZR_TEST_ENV_VAR should not exist.')
1413
if 'BZR_TEST_ENV_VAR' in os.environ:
1414
del os.environ['BZR_TEST_ENV_VAR']
1416
self.addCleanup(cleanup)
1419
"""Test that we can set an env variable"""
1420
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1421
self.assertEqual(None, old)
1422
self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
1424
def test_double_set(self):
1425
"""Test that we get the old value out"""
1426
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1427
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
1428
self.assertEqual('foo', old)
1429
self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
1431
def test_unicode(self):
1432
"""Environment can only contain plain strings
1434
So Unicode strings must be encoded.
1436
uni_val, env_val = probe_unicode_in_user_encoding()
1438
raise TestSkipped('Cannot find a unicode character that works in'
1439
' encoding %s' % (osutils.get_user_encoding(),))
1441
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1442
self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1444
def test_unset(self):
1445
"""Test that passing None will remove the env var"""
1446
osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
1447
old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
1448
self.assertEqual('foo', old)
1449
self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
1450
self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1453
class TestLocalTimeOffset(TestCase):
1455
def test_local_time_offset(self):
1456
"""Test that local_time_offset() returns a sane value."""
1457
offset = osutils.local_time_offset()
1458
self.assertTrue(isinstance(offset, int))
1459
# Test that the offset is no more than a eighteen hours in
1461
# Time zone handling is system specific, so it is difficult to
1462
# do more specific tests, but a value outside of this range is
1464
eighteen_hours = 18 * 3600
1465
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1467
def test_local_time_offset_with_timestamp(self):
1468
"""Test that local_time_offset() works with a timestamp."""
1469
offset = osutils.local_time_offset(1000000000.1234567)
1470
self.assertTrue(isinstance(offset, int))
1471
eighteen_hours = 18 * 3600
1472
self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1475
class TestShaFileByName(TestCaseInTempDir):
1477
def test_sha_empty(self):
1478
self.build_tree_contents([('foo', '')])
1479
expected_sha = osutils.sha_string('')
1480
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1482
def test_sha_mixed_endings(self):
1483
text = 'test\r\nwith\nall\rpossible line endings\r\n'
1484
self.build_tree_contents([('foo', text)])
1485
expected_sha = osutils.sha_string(text)
1486
self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1489
class TestResourceLoading(TestCaseInTempDir):
1491
def test_resource_string(self):
1492
# test resource in bzrlib
1493
text = osutils.resource_string('bzrlib', 'debug.py')
1494
self.assertContainsRe(text, "debug_flags = set()")
1495
# test resource under bzrlib
1496
text = osutils.resource_string('bzrlib.ui', 'text.py')
1497
self.assertContainsRe(text, "class TextUIFactory")
1498
# test unsupported package
1499
self.assertRaises(errors.BzrError, osutils.resource_string, 'zzzz',
1501
# test unknown resource
1502
self.assertRaises(IOError, osutils.resource_string, 'bzrlib', 'yyy.xx')