1
# Copyright (C) 2005 by 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."""
26
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
27
import bzrlib.osutils as osutils
28
from bzrlib.tests import (
36
class TestOSUtils(TestCaseInTempDir):
38
def test_fancy_rename(self):
39
# This should work everywhere
41
osutils.fancy_rename(a, b,
42
rename_func=os.rename,
43
unlink_func=os.unlink)
45
open('a', 'wb').write('something in a\n')
47
self.failIfExists('a')
48
self.failUnlessExists('b')
49
self.check_file_contents('b', 'something in a\n')
51
open('a', 'wb').write('new something in a\n')
54
self.check_file_contents('a', 'something in a\n')
56
def test_rename(self):
57
# Rename should be semi-atomic on all platforms
58
open('a', 'wb').write('something in a\n')
59
osutils.rename('a', 'b')
60
self.failIfExists('a')
61
self.failUnlessExists('b')
62
self.check_file_contents('b', 'something in a\n')
64
open('a', 'wb').write('new something in a\n')
65
osutils.rename('b', 'a')
67
self.check_file_contents('a', 'something in a\n')
69
# TODO: test fancy_rename using a MemoryTransport
71
def test_01_rand_chars_empty(self):
72
result = osutils.rand_chars(0)
73
self.assertEqual(result, '')
75
def test_02_rand_chars_100(self):
76
result = osutils.rand_chars(100)
77
self.assertEqual(len(result), 100)
78
self.assertEqual(type(result), str)
79
self.assertContainsRe(result, r'^[a-z0-9]{100}$')
82
def test_rmtree(self):
83
# Check to remove tree with read-only files/dirs
85
f = file('dir/file', 'w')
88
# would like to also try making the directory readonly, but at the
89
# moment python shutil.rmtree doesn't handle that properly - it would
90
# need to chmod the directory before removing things inside it - deferred
91
# for now -- mbp 20060505
92
# osutils.make_readonly('dir')
93
osutils.make_readonly('dir/file')
97
self.failIfExists('dir/file')
98
self.failIfExists('dir')
100
def test_file_kind(self):
101
self.build_tree(['file', 'dir/'])
102
self.assertEquals('file', osutils.file_kind('file'))
103
self.assertEquals('directory', osutils.file_kind('dir/'))
104
if osutils.has_symlinks():
105
os.symlink('symlink', 'symlink')
106
self.assertEquals('symlink', osutils.file_kind('symlink'))
108
# TODO: jam 20060529 Test a block device
110
os.lstat('/dev/null')
112
if e.errno not in (errno.ENOENT,):
115
self.assertEquals('chardev', osutils.file_kind('/dev/null'))
117
mkfifo = getattr(os, 'mkfifo', None)
121
self.assertEquals('fifo', osutils.file_kind('fifo'))
125
AF_UNIX = getattr(socket, 'AF_UNIX', None)
127
s = socket.socket(AF_UNIX)
130
self.assertEquals('socket', osutils.file_kind('socket'))
135
class TestSafeUnicode(TestCase):
137
def test_from_ascii_string(self):
138
self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
140
def test_from_unicode_string_ascii_contents(self):
141
self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
143
def test_from_unicode_string_unicode_contents(self):
144
self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
146
def test_from_utf8_string(self):
147
self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
149
def test_bad_utf8_string(self):
150
self.assertRaises(BzrBadParameterNotUnicode,
151
osutils.safe_unicode,
155
class TestWin32Funcs(TestCase):
156
"""Test that the _win32 versions of os utilities return appropriate paths."""
158
def test_abspath(self):
159
self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
160
self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
162
def test_realpath(self):
163
self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
164
self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
166
def test_pathjoin(self):
167
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
168
self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
169
self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
170
self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
171
self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
172
self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
174
def test_normpath(self):
175
self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
176
self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
178
def test_getcwd(self):
179
cwd = osutils._win32_getcwd()
180
os_cwd = os.getcwdu()
181
self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
182
# win32 is inconsistent whether it returns lower or upper case
183
# and even if it was consistent the user might type the other
184
# so we force it to uppercase
185
# running python.exe under cmd.exe return capital C:\\
186
# running win32 python inside a cygwin shell returns lowercase
187
self.assertEqual(os_cwd[0].upper(), cwd[0])
189
def test_fixdrive(self):
190
self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
191
self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
192
self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
195
class TestWin32FuncsDirs(TestCaseInTempDir):
196
"""Test win32 functions that create files."""
198
def test_getcwd(self):
199
# Make sure getcwd can handle unicode filenames
203
raise TestSkipped("Unable to create Unicode filename")
206
# TODO: jam 20060427 This will probably fail on Mac OSX because
207
# it will change the normalization of B\xe5gfors
208
# Consider using a different unicode character, or make
209
# osutils.getcwd() renormalize the path.
210
self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
212
def test_mkdtemp(self):
213
tmpdir = osutils._win32_mkdtemp(dir='.')
214
self.assertFalse('\\' in tmpdir)
216
def test_rename(self):
224
osutils._win32_rename('b', 'a')
225
self.failUnlessExists('a')
226
self.failIfExists('b')
227
self.assertFileEqual('baz\n', 'a')
229
def test_rename_missing_file(self):
235
osutils._win32_rename('b', 'a')
236
except (IOError, OSError), e:
237
self.assertEqual(errno.ENOENT, e.errno)
238
self.assertFileEqual('foo\n', 'a')
240
def test_rename_missing_dir(self):
243
osutils._win32_rename('b', 'a')
244
except (IOError, OSError), e:
245
self.assertEqual(errno.ENOENT, e.errno)
247
def test_rename_current_dir(self):
250
# You can't rename the working directory
251
# doing rename non-existant . usually
252
# just raises ENOENT, since non-existant
255
osutils._win32_rename('b', '.')
256
except (IOError, OSError), e:
257
self.assertEqual(errno.ENOENT, e.errno)
260
class TestMacFuncsDirs(TestCaseInTempDir):
261
"""Test mac special functions that require directories."""
263
def test_getcwd(self):
264
# On Mac, this will actually create Ba\u030agfors
265
# but chdir will still work, because it accepts both paths
267
os.mkdir(u'B\xe5gfors')
269
raise TestSkipped("Unable to create Unicode filename")
271
os.chdir(u'B\xe5gfors')
272
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
274
def test_getcwd_nonnorm(self):
275
# Test that _mac_getcwd() will normalize this path
277
os.mkdir(u'Ba\u030agfors')
279
raise TestSkipped("Unable to create Unicode filename")
281
os.chdir(u'Ba\u030agfors')
282
self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
284
class TestSplitLines(TestCase):
286
def test_split_unicode(self):
287
self.assertEqual([u'foo\n', u'bar\xae'],
288
osutils.split_lines(u'foo\nbar\xae'))
289
self.assertEqual([u'foo\n', u'bar\xae\n'],
290
osutils.split_lines(u'foo\nbar\xae\n'))
292
def test_split_with_carriage_returns(self):
293
self.assertEqual(['foo\rbar\n'],
294
osutils.split_lines('foo\rbar\n'))
297
class TestWalkDirs(TestCaseInTempDir):
299
def test_walkdirs(self):
308
self.build_tree(tree)
309
expected_dirblocks = [
311
[('0file', '0file', 'file'),
312
('1dir', '1dir', 'directory'),
313
('2file', '2file', 'file'),
317
[('1dir/0file', '0file', 'file'),
318
('1dir/1dir', '1dir', 'directory'),
321
(('1dir/1dir', './1dir/1dir'),
328
for dirdetail, dirblock in osutils.walkdirs('.'):
329
if len(dirblock) and dirblock[0][1] == '.bzr':
330
# this tests the filtering of selected paths
333
result.append((dirdetail, dirblock))
335
self.assertTrue(found_bzrdir)
336
self.assertEqual(expected_dirblocks,
337
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
338
# you can search a subdir only, with a supplied prefix.
340
for dirblock in osutils.walkdirs('./1dir', '1dir'):
341
result.append(dirblock)
342
self.assertEqual(expected_dirblocks[1:],
343
[(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
345
def assertPathCompare(self, path_less, path_greater):
346
"""check that path_less and path_greater compare correctly."""
347
self.assertEqual(0, osutils.compare_paths_prefix_order(
348
path_less, path_less))
349
self.assertEqual(0, osutils.compare_paths_prefix_order(
350
path_greater, path_greater))
351
self.assertEqual(-1, osutils.compare_paths_prefix_order(
352
path_less, path_greater))
353
self.assertEqual(1, osutils.compare_paths_prefix_order(
354
path_greater, path_less))
356
def test_compare_paths_prefix_order(self):
357
# root before all else
358
self.assertPathCompare("/", "/a")
360
self.assertPathCompare("/a", "/b")
361
self.assertPathCompare("/b", "/z")
362
# high dirs before lower.
363
self.assertPathCompare("/z", "/a/a")
364
# except if the deeper dir should be output first
365
self.assertPathCompare("/a/b/c", "/d/g")
366
# lexical betwen dirs of the same height
367
self.assertPathCompare("/a/z", "/z/z")
368
self.assertPathCompare("/a/c/z", "/a/d/e")
370
# this should also be consistent for no leading / paths
371
# root before all else
372
self.assertPathCompare("", "a")
374
self.assertPathCompare("a", "b")
375
self.assertPathCompare("b", "z")
376
# high dirs before lower.
377
self.assertPathCompare("z", "a/a")
378
# except if the deeper dir should be output first
379
self.assertPathCompare("a/b/c", "d/g")
380
# lexical betwen dirs of the same height
381
self.assertPathCompare("a/z", "z/z")
382
self.assertPathCompare("a/c/z", "a/d/e")
384
def test_path_prefix_sorting(self):
385
"""Doing a sort on path prefix should match our sample data."""
416
sorted(original_paths, key=osutils.path_prefix_key))
417
# using the comparison routine shoudl work too:
420
sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
423
class TestTerminalEncoding(TestCase):
424
"""Test the auto-detection of proper terminal encoding."""
427
self._stdout = sys.stdout
428
self._stderr = sys.stderr
429
self._stdin = sys.stdin
430
self._user_encoding = bzrlib.user_encoding
432
self.addCleanup(self._reset)
434
sys.stdout = StringIOWrapper()
435
sys.stdout.encoding = 'stdout_encoding'
436
sys.stderr = StringIOWrapper()
437
sys.stderr.encoding = 'stderr_encoding'
438
sys.stdin = StringIOWrapper()
439
sys.stdin.encoding = 'stdin_encoding'
440
bzrlib.user_encoding = 'user_encoding'
443
sys.stdout = self._stdout
444
sys.stderr = self._stderr
445
sys.stdin = self._stdin
446
bzrlib.user_encoding = self._user_encoding
448
def test_get_terminal_encoding(self):
449
# first preference is stdout encoding
450
self.assertEqual('stdout_encoding', osutils.get_terminal_encoding())
452
sys.stdout.encoding = None
453
# if sys.stdout is None, fall back to sys.stdin
454
self.assertEqual('stdin_encoding', osutils.get_terminal_encoding())
456
sys.stdin.encoding = None
457
# and in the worst case, use bzrlib.user_encoding
458
self.assertEqual('user_encoding', osutils.get_terminal_encoding())