~bzr-pqm/bzr/bzr.dev

2095.3.1 by Martin Pool
Tests shouldn't assume os.listdir returns sorted results
1
# Copyright (C) 2005, 2006 Canonical Ltd
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
2
#
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.
7
#
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.
12
#
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
16
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
17
"""Tests for the osutils wrapper."""
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
18
1732.1.28 by John Arbash Meinel
Add tests for fancy file types.
19
import errno
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
20
import os
1732.1.28 by John Arbash Meinel
Add tests for fancy file types.
21
import socket
22
import stat
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
23
import sys
24
25
import bzrlib
1996.3.14 by John Arbash Meinel
lazy_import osutils and sign_my_commits
26
from bzrlib import (
27
    errors,
28
    osutils,
29
    )
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
30
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
1711.4.10 by John Arbash Meinel
Pull out sys.stdout.encoding handling into a separate function so it can be tested, and used elsewhere.
31
from bzrlib.tests import (
32
        StringIOWrapper,
33
        TestCase, 
34
        TestCaseInTempDir, 
35
        TestSkipped,
36
        )
1532 by Robert Collins
Merge in John Meinels integration branch.
37
1185.31.47 by John Arbash Meinel
Added a fancy footwork rename to osutils, made SftpTransport use it.
38
39
class TestOSUtils(TestCaseInTempDir):
40
41
    def test_fancy_rename(self):
42
        # This should work everywhere
43
        def rename(a, b):
44
            osutils.fancy_rename(a, b,
45
                    rename_func=os.rename,
46
                    unlink_func=os.unlink)
47
48
        open('a', 'wb').write('something in a\n')
49
        rename('a', 'b')
50
        self.failIfExists('a')
51
        self.failUnlessExists('b')
52
        self.check_file_contents('b', 'something in a\n')
53
54
        open('a', 'wb').write('new something in a\n')
55
        rename('b', 'a')
56
57
        self.check_file_contents('a', 'something in a\n')
58
59
    def test_rename(self):
60
        # Rename should be semi-atomic on all platforms
61
        open('a', 'wb').write('something in a\n')
62
        osutils.rename('a', 'b')
63
        self.failIfExists('a')
64
        self.failUnlessExists('b')
65
        self.check_file_contents('b', 'something in a\n')
66
67
        open('a', 'wb').write('new something in a\n')
68
        osutils.rename('b', 'a')
69
70
        self.check_file_contents('a', 'something in a\n')
71
72
    # TODO: test fancy_rename using a MemoryTransport
73
1553.5.5 by Martin Pool
New utility routine rand_chars
74
    def test_01_rand_chars_empty(self):
75
        result = osutils.rand_chars(0)
76
        self.assertEqual(result, '')
77
78
    def test_02_rand_chars_100(self):
79
        result = osutils.rand_chars(100)
80
        self.assertEqual(len(result), 100)
81
        self.assertEqual(type(result), str)
82
        self.assertContainsRe(result, r'^[a-z0-9]{100}$')
83
1996.3.14 by John Arbash Meinel
lazy_import osutils and sign_my_commits
84
    def test_is_inside(self):
85
        is_inside = osutils.is_inside
86
        self.assertTrue(is_inside('src', 'src/foo.c'))
87
        self.assertFalse(is_inside('src', 'srccontrol'))
88
        self.assertTrue(is_inside('src', 'src/a/a/a/foo.c'))
89
        self.assertTrue(is_inside('foo.c', 'foo.c'))
90
        self.assertFalse(is_inside('foo.c', ''))
91
        self.assertTrue(is_inside('', 'foo.c'))
1534.3.1 by Robert Collins
* bzrlib.osutils.safe_unicode now exists to provide parameter coercion
92
1692.7.6 by Martin Pool
[patch] force deletion of trees containing readonly files (alexander)
93
    def test_rmtree(self):
94
        # Check to remove tree with read-only files/dirs
95
        os.mkdir('dir')
96
        f = file('dir/file', 'w')
97
        f.write('spam')
98
        f.close()
99
        # would like to also try making the directory readonly, but at the
100
        # moment python shutil.rmtree doesn't handle that properly - it would
101
        # need to chmod the directory before removing things inside it - deferred
102
        # for now -- mbp 20060505
103
        # osutils.make_readonly('dir')
104
        osutils.make_readonly('dir/file')
105
106
        osutils.rmtree('dir')
107
108
        self.failIfExists('dir/file')
109
        self.failIfExists('dir')
110
1732.1.10 by John Arbash Meinel
Updated version of file_kind. Rather than multiple function calls, one mask + dictionary lookup
111
    def test_file_kind(self):
112
        self.build_tree(['file', 'dir/'])
113
        self.assertEquals('file', osutils.file_kind('file'))
114
        self.assertEquals('directory', osutils.file_kind('dir/'))
115
        if osutils.has_symlinks():
116
            os.symlink('symlink', 'symlink')
117
            self.assertEquals('symlink', osutils.file_kind('symlink'))
1732.1.28 by John Arbash Meinel
Add tests for fancy file types.
118
        
119
        # TODO: jam 20060529 Test a block device
120
        try:
121
            os.lstat('/dev/null')
122
        except OSError, e:
123
            if e.errno not in (errno.ENOENT,):
124
                raise
125
        else:
126
            self.assertEquals('chardev', osutils.file_kind('/dev/null'))
127
128
        mkfifo = getattr(os, 'mkfifo', None)
129
        if mkfifo:
130
            mkfifo('fifo')
131
            try:
132
                self.assertEquals('fifo', osutils.file_kind('fifo'))
133
            finally:
134
                os.remove('fifo')
135
136
        AF_UNIX = getattr(socket, 'AF_UNIX', None)
137
        if AF_UNIX:
138
            s = socket.socket(AF_UNIX)
139
            s.bind('socket')
140
            try:
141
                self.assertEquals('socket', osutils.file_kind('socket'))
142
            finally:
143
                os.remove('socket')
1732.1.10 by John Arbash Meinel
Updated version of file_kind. Rather than multiple function calls, one mask + dictionary lookup
144
1755.3.7 by John Arbash Meinel
Clean up and write tests for permissions. Now we use fstat which should be cheap, and lets us check the permissions and the file size
145
    def test_get_umask(self):
146
        if sys.platform == 'win32':
147
            # umask always returns '0', no way to set it
148
            self.assertEqual(0, osutils.get_umask())
149
            return
150
151
        orig_umask = osutils.get_umask()
152
        try:
153
            os.umask(0222)
154
            self.assertEqual(0222, osutils.get_umask())
155
            os.umask(0022)
156
            self.assertEqual(0022, osutils.get_umask())
157
            os.umask(0002)
158
            self.assertEqual(0002, osutils.get_umask())
159
            os.umask(0027)
160
            self.assertEqual(0027, osutils.get_umask())
161
        finally:
162
            os.umask(orig_umask)
163
1957.1.15 by John Arbash Meinel
Review feedback from Robert
164
    def assertFormatedDelta(self, expected, seconds):
165
        """Assert osutils.format_delta formats as expected"""
166
        actual = osutils.format_delta(seconds)
167
        self.assertEqual(expected, actual)
168
1957.1.4 by John Arbash Meinel
create a helper for formatting a time delta
169
    def test_format_delta(self):
1957.1.15 by John Arbash Meinel
Review feedback from Robert
170
        self.assertFormatedDelta('0 seconds ago', 0)
171
        self.assertFormatedDelta('1 second ago', 1)
172
        self.assertFormatedDelta('10 seconds ago', 10)
173
        self.assertFormatedDelta('59 seconds ago', 59)
174
        self.assertFormatedDelta('89 seconds ago', 89)
175
        self.assertFormatedDelta('1 minute, 30 seconds ago', 90)
176
        self.assertFormatedDelta('3 minutes, 0 seconds ago', 180)
177
        self.assertFormatedDelta('3 minutes, 1 second ago', 181)
178
        self.assertFormatedDelta('10 minutes, 15 seconds ago', 615)
179
        self.assertFormatedDelta('30 minutes, 59 seconds ago', 1859)
180
        self.assertFormatedDelta('31 minutes, 0 seconds ago', 1860)
181
        self.assertFormatedDelta('60 minutes, 0 seconds ago', 3600)
182
        self.assertFormatedDelta('89 minutes, 59 seconds ago', 5399)
183
        self.assertFormatedDelta('1 hour, 30 minutes ago', 5400)
184
        self.assertFormatedDelta('2 hours, 30 minutes ago', 9017)
185
        self.assertFormatedDelta('10 hours, 0 minutes ago', 36000)
186
        self.assertFormatedDelta('24 hours, 0 minutes ago', 86400)
187
        self.assertFormatedDelta('35 hours, 59 minutes ago', 129599)
188
        self.assertFormatedDelta('36 hours, 0 minutes ago', 129600)
189
        self.assertFormatedDelta('36 hours, 0 minutes ago', 129601)
190
        self.assertFormatedDelta('36 hours, 1 minute ago', 129660)
191
        self.assertFormatedDelta('36 hours, 1 minute ago', 129661)
192
        self.assertFormatedDelta('84 hours, 10 minutes ago', 303002)
1957.1.4 by John Arbash Meinel
create a helper for formatting a time delta
193
194
        # We handle when time steps the wrong direction because computers
195
        # don't have synchronized clocks.
1957.1.15 by John Arbash Meinel
Review feedback from Robert
196
        self.assertFormatedDelta('84 hours, 10 minutes in the future', -303002)
197
        self.assertFormatedDelta('1 second in the future', -1)
198
        self.assertFormatedDelta('2 seconds in the future', -2)
1957.1.4 by John Arbash Meinel
create a helper for formatting a time delta
199
2091.3.7 by Aaron Bentley
Rename real_parent to dereferenced_path
200
    def test_dereference_path(self):
2091.3.6 by Aaron Bentley
Add symlink test guards
201
        if not osutils.has_symlinks():
202
            raise TestSkipped('Symlinks are not supported on this platform')
2091.3.5 by Aaron Bentley
Move realpath functionality into osutils
203
        cwd = osutils.realpath('.')
204
        os.mkdir('bar')
205
        bar_path = osutils.pathjoin(cwd, 'bar')
206
        # Using './' to avoid bug #1213894 (first path component not
207
        # dereferenced) in Python 2.4.1 and earlier
208
        self.assertEqual(bar_path, osutils.realpath('./bar'))
209
        os.symlink('bar', 'foo')
210
        self.assertEqual(bar_path, osutils.realpath('./foo'))
211
        
212
        # Does not dereference terminal symlinks
213
        foo_path = osutils.pathjoin(cwd, 'foo')
2091.3.7 by Aaron Bentley
Rename real_parent to dereferenced_path
214
        self.assertEqual(foo_path, osutils.dereference_path('./foo'))
2091.3.5 by Aaron Bentley
Move realpath functionality into osutils
215
216
        # Dereferences parent symlinks
217
        os.mkdir('bar/baz')
218
        baz_path = osutils.pathjoin(bar_path, 'baz')
2091.3.7 by Aaron Bentley
Rename real_parent to dereferenced_path
219
        self.assertEqual(baz_path, osutils.dereference_path('./foo/baz'))
2091.3.5 by Aaron Bentley
Move realpath functionality into osutils
220
221
        # Dereferences parent symlinks that are the first path element
2091.3.7 by Aaron Bentley
Rename real_parent to dereferenced_path
222
        self.assertEqual(baz_path, osutils.dereference_path('foo/baz'))
2091.3.5 by Aaron Bentley
Move realpath functionality into osutils
223
224
        # Dereferences parent symlinks in absolute paths
225
        foo_baz_path = osutils.pathjoin(foo_path, 'baz')
2091.3.7 by Aaron Bentley
Rename real_parent to dereferenced_path
226
        self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
2091.3.5 by Aaron Bentley
Move realpath functionality into osutils
227
1692.7.6 by Martin Pool
[patch] force deletion of trees containing readonly files (alexander)
228
1534.3.1 by Robert Collins
* bzrlib.osutils.safe_unicode now exists to provide parameter coercion
229
class TestSafeUnicode(TestCase):
230
231
    def test_from_ascii_string(self):
232
        self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
233
1534.3.2 by Robert Collins
An extra test for John.
234
    def test_from_unicode_string_ascii_contents(self):
1534.3.1 by Robert Collins
* bzrlib.osutils.safe_unicode now exists to provide parameter coercion
235
        self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
236
1534.3.2 by Robert Collins
An extra test for John.
237
    def test_from_unicode_string_unicode_contents(self):
238
        self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
239
1534.3.1 by Robert Collins
* bzrlib.osutils.safe_unicode now exists to provide parameter coercion
240
    def test_from_utf8_string(self):
241
        self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
242
243
    def test_bad_utf8_string(self):
1185.65.29 by Robert Collins
Implement final review suggestions.
244
        self.assertRaises(BzrBadParameterNotUnicode,
245
                          osutils.safe_unicode,
246
                          '\xbb\xbb')
1666.1.6 by Robert Collins
Make knit the default format.
247
248
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
249
class TestWin32Funcs(TestCase):
250
    """Test that the _win32 versions of os utilities return appropriate paths."""
251
252
    def test_abspath(self):
253
        self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
254
        self.assertEqual('C:/foo', osutils._win32_abspath('C:/foo'))
255
256
    def test_realpath(self):
257
        self.assertEqual('C:/foo', osutils._win32_realpath('C:\\foo'))
258
        self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
259
260
    def test_pathjoin(self):
261
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
262
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
263
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
264
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
265
        self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
266
        self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
267
268
    def test_normpath(self):
269
        self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
270
        self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
271
272
    def test_getcwd(self):
1711.5.2 by John Arbash Meinel
win32 likes to return lowercase drive letters sometimes, and uppercase at other times. normalize this
273
        cwd = osutils._win32_getcwd()
274
        os_cwd = os.getcwdu()
275
        self.assertEqual(os_cwd[1:].replace('\\', '/'), cwd[1:])
276
        # win32 is inconsistent whether it returns lower or upper case
277
        # and even if it was consistent the user might type the other
278
        # so we force it to uppercase
279
        # running python.exe under cmd.exe return capital C:\\
280
        # running win32 python inside a cygwin shell returns lowercase
281
        self.assertEqual(os_cwd[0].upper(), cwd[0])
282
283
    def test_fixdrive(self):
284
        self.assertEqual('H:/foo', osutils._win32_fixdrive('h:/foo'))
285
        self.assertEqual('H:/foo', osutils._win32_fixdrive('H:/foo'))
286
        self.assertEqual('C:\\foo', osutils._win32_fixdrive('c:\\foo'))
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
287
288
289
class TestWin32FuncsDirs(TestCaseInTempDir):
290
    """Test win32 functions that create files."""
291
    
292
    def test_getcwd(self):
293
        # Make sure getcwd can handle unicode filenames
294
        try:
1830.3.9 by John Arbash Meinel
Use a directory name that doesn't get messed up on Mac for getcwd() test.
295
            os.mkdir(u'mu-\xb5')
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
296
        except UnicodeError:
297
            raise TestSkipped("Unable to create Unicode filename")
298
1830.3.9 by John Arbash Meinel
Use a directory name that doesn't get messed up on Mac for getcwd() test.
299
        os.chdir(u'mu-\xb5')
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
300
        # TODO: jam 20060427 This will probably fail on Mac OSX because
301
        #       it will change the normalization of B\xe5gfors
302
        #       Consider using a different unicode character, or make
303
        #       osutils.getcwd() renormalize the path.
1830.3.9 by John Arbash Meinel
Use a directory name that doesn't get messed up on Mac for getcwd() test.
304
        self.assertEndsWith(osutils._win32_getcwd(), u'mu-\xb5')
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
305
306
    def test_mkdtemp(self):
307
        tmpdir = osutils._win32_mkdtemp(dir='.')
308
        self.assertFalse('\\' in tmpdir)
309
310
    def test_rename(self):
311
        a = open('a', 'wb')
312
        a.write('foo\n')
313
        a.close()
314
        b = open('b', 'wb')
315
        b.write('baz\n')
316
        b.close()
317
318
        osutils._win32_rename('b', 'a')
319
        self.failUnlessExists('a')
320
        self.failIfExists('b')
321
        self.assertFileEqual('baz\n', 'a')
322
1711.7.6 by John Arbash Meinel
Change _win32_rename() so that it raises ENOENT *before* it tries any renaming.
323
    def test_rename_missing_file(self):
324
        a = open('a', 'wb')
325
        a.write('foo\n')
326
        a.close()
327
328
        try:
329
            osutils._win32_rename('b', 'a')
330
        except (IOError, OSError), e:
331
            self.assertEqual(errno.ENOENT, e.errno)
332
        self.assertFileEqual('foo\n', 'a')
333
334
    def test_rename_missing_dir(self):
335
        os.mkdir('a')
336
        try:
337
            osutils._win32_rename('b', 'a')
338
        except (IOError, OSError), e:
339
            self.assertEqual(errno.ENOENT, e.errno)
340
341
    def test_rename_current_dir(self):
342
        os.mkdir('a')
343
        os.chdir('a')
344
        # You can't rename the working directory
345
        # doing rename non-existant . usually
346
        # just raises ENOENT, since non-existant
347
        # doesn't exist.
348
        try:
349
            osutils._win32_rename('b', '.')
350
        except (IOError, OSError), e:
351
            self.assertEqual(errno.ENOENT, e.errno)
352
1996.3.14 by John Arbash Meinel
lazy_import osutils and sign_my_commits
353
    def test_splitpath(self):
354
        def check(expected, path):
355
            self.assertEqual(expected, osutils.splitpath(path))
356
357
        check(['a'], 'a')
358
        check(['a', 'b'], 'a/b')
359
        check(['a', 'b'], 'a/./b')
360
        check(['a', '.b'], 'a/.b')
361
        check(['a', '.b'], 'a\\.b')
362
363
        self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
364
1685.1.31 by John Arbash Meinel
Adding tests for the rest of the _win32 functions.
365
1830.3.11 by John Arbash Meinel
Create a mac version of 'getcwd()' which normalizes the path.
366
class TestMacFuncsDirs(TestCaseInTempDir):
367
    """Test mac special functions that require directories."""
368
369
    def test_getcwd(self):
370
        # On Mac, this will actually create Ba\u030agfors
371
        # but chdir will still work, because it accepts both paths
372
        try:
373
            os.mkdir(u'B\xe5gfors')
374
        except UnicodeError:
375
            raise TestSkipped("Unable to create Unicode filename")
376
377
        os.chdir(u'B\xe5gfors')
378
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
379
380
    def test_getcwd_nonnorm(self):
381
        # Test that _mac_getcwd() will normalize this path
382
        try:
383
            os.mkdir(u'Ba\u030agfors')
384
        except UnicodeError:
385
            raise TestSkipped("Unable to create Unicode filename")
386
387
        os.chdir(u'Ba\u030agfors')
388
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
389
1996.3.14 by John Arbash Meinel
lazy_import osutils and sign_my_commits
390
1666.1.6 by Robert Collins
Make knit the default format.
391
class TestSplitLines(TestCase):
392
393
    def test_split_unicode(self):
394
        self.assertEqual([u'foo\n', u'bar\xae'],
395
                         osutils.split_lines(u'foo\nbar\xae'))
396
        self.assertEqual([u'foo\n', u'bar\xae\n'],
397
                         osutils.split_lines(u'foo\nbar\xae\n'))
398
399
    def test_split_with_carriage_returns(self):
400
        self.assertEqual(['foo\rbar\n'],
401
                         osutils.split_lines('foo\rbar\n'))
1753.1.1 by Robert Collins
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.
402
403
404
class TestWalkDirs(TestCaseInTempDir):
405
406
    def test_walkdirs(self):
407
        tree = [
408
            '.bzr',
409
            '0file',
410
            '1dir/',
411
            '1dir/0file',
412
            '1dir/1dir/',
413
            '2file'
414
            ]
415
        self.build_tree(tree)
416
        expected_dirblocks = [
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
417
                (('', '.'),
418
                 [('0file', '0file', 'file'),
419
                  ('1dir', '1dir', 'directory'),
420
                  ('2file', '2file', 'file'),
421
                 ]
422
                ),
423
                (('1dir', './1dir'),
424
                 [('1dir/0file', '0file', 'file'),
425
                  ('1dir/1dir', '1dir', 'directory'),
426
                 ]
427
                ),
428
                (('1dir/1dir', './1dir/1dir'),
429
                 [
430
                 ]
431
                ),
1753.1.1 by Robert Collins
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.
432
            ]
433
        result = []
434
        found_bzrdir = False
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
435
        for dirdetail, dirblock in osutils.walkdirs('.'):
1753.1.1 by Robert Collins
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.
436
            if len(dirblock) and dirblock[0][1] == '.bzr':
437
                # this tests the filtering of selected paths
438
                found_bzrdir = True
439
                del dirblock[0]
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
440
            result.append((dirdetail, dirblock))
1753.1.1 by Robert Collins
(rbc, jam, mbp)Add bzrlib.osutils.walkdirs, an optimised walk-and-stat routine.
441
442
        self.assertTrue(found_bzrdir)
443
        self.assertEqual(expected_dirblocks,
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
444
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
1757.2.8 by Robert Collins
Teach walkdirs to walk a subdir of a tree.
445
        # you can search a subdir only, with a supplied prefix.
446
        result = []
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
447
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
1757.2.8 by Robert Collins
Teach walkdirs to walk a subdir of a tree.
448
            result.append(dirblock)
449
        self.assertEqual(expected_dirblocks[1:],
1897.1.1 by Robert Collins
Add some useful summary data to osutils.walkdirs output.
450
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
1757.2.8 by Robert Collins
Teach walkdirs to walk a subdir of a tree.
451
1773.3.1 by Robert Collins
Add path_prefix_key and compare_paths_prefix_order utility functions.
452
    def assertPathCompare(self, path_less, path_greater):
453
        """check that path_less and path_greater compare correctly."""
454
        self.assertEqual(0, osutils.compare_paths_prefix_order(
455
            path_less, path_less))
456
        self.assertEqual(0, osutils.compare_paths_prefix_order(
457
            path_greater, path_greater))
458
        self.assertEqual(-1, osutils.compare_paths_prefix_order(
459
            path_less, path_greater))
460
        self.assertEqual(1, osutils.compare_paths_prefix_order(
461
            path_greater, path_less))
462
463
    def test_compare_paths_prefix_order(self):
464
        # root before all else
465
        self.assertPathCompare("/", "/a")
466
        # alpha within a dir
467
        self.assertPathCompare("/a", "/b")
468
        self.assertPathCompare("/b", "/z")
469
        # high dirs before lower.
470
        self.assertPathCompare("/z", "/a/a")
1773.3.2 by Robert Collins
New corner case from John Meinel, showing up the need to check the directory lexographically outside of a single tree's root. Fixed.
471
        # except if the deeper dir should be output first
472
        self.assertPathCompare("/a/b/c", "/d/g")
1773.3.1 by Robert Collins
Add path_prefix_key and compare_paths_prefix_order utility functions.
473
        # lexical betwen dirs of the same height
474
        self.assertPathCompare("/a/z", "/z/z")
475
        self.assertPathCompare("/a/c/z", "/a/d/e")
476
477
        # this should also be consistent for no leading / paths
478
        # root before all else
479
        self.assertPathCompare("", "a")
480
        # alpha within a dir
481
        self.assertPathCompare("a", "b")
482
        self.assertPathCompare("b", "z")
483
        # high dirs before lower.
484
        self.assertPathCompare("z", "a/a")
1773.3.2 by Robert Collins
New corner case from John Meinel, showing up the need to check the directory lexographically outside of a single tree's root. Fixed.
485
        # except if the deeper dir should be output first
486
        self.assertPathCompare("a/b/c", "d/g")
1773.3.1 by Robert Collins
Add path_prefix_key and compare_paths_prefix_order utility functions.
487
        # lexical betwen dirs of the same height
488
        self.assertPathCompare("a/z", "z/z")
489
        self.assertPathCompare("a/c/z", "a/d/e")
490
1773.3.3 by Robert Collins
Add new tests John Meinel asked for.
491
    def test_path_prefix_sorting(self):
492
        """Doing a sort on path prefix should match our sample data."""
493
        original_paths = [
494
            'a',
495
            'a/b',
496
            'a/b/c',
497
            'b',
498
            'b/c',
499
            'd',
500
            'd/e',
501
            'd/e/f',
502
            'd/f',
503
            'd/g',
504
            'g',
505
            ]
506
507
        dir_sorted_paths = [
508
            'a',
509
            'b',
510
            'd',
511
            'g',
512
            'a/b',
513
            'a/b/c',
514
            'b/c',
515
            'd/e',
516
            'd/f',
517
            'd/g',
518
            'd/e/f',
519
            ]
520
521
        self.assertEqual(
522
            dir_sorted_paths,
523
            sorted(original_paths, key=osutils.path_prefix_key))
524
        # using the comparison routine shoudl work too:
525
        self.assertEqual(
526
            dir_sorted_paths,
527
            sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
1711.4.10 by John Arbash Meinel
Pull out sys.stdout.encoding handling into a separate function so it can be tested, and used elsewhere.
528
529
1907.3.1 by John Arbash Meinel
create a copy_tree wrapper around walkdirs()
530
class TestCopyTree(TestCaseInTempDir):
531
    
532
    def test_copy_basic_tree(self):
533
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
534
        osutils.copy_tree('source', 'target')
2095.3.1 by Martin Pool
Tests shouldn't assume os.listdir returns sorted results
535
        self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
1907.3.1 by John Arbash Meinel
create a copy_tree wrapper around walkdirs()
536
        self.assertEqual(['c'], os.listdir('target/b'))
537
538
    def test_copy_tree_target_exists(self):
539
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c',
540
                         'target/'])
541
        osutils.copy_tree('source', 'target')
2095.3.1 by Martin Pool
Tests shouldn't assume os.listdir returns sorted results
542
        self.assertEqual(['a', 'b'], sorted(os.listdir('target')))
1907.3.1 by John Arbash Meinel
create a copy_tree wrapper around walkdirs()
543
        self.assertEqual(['c'], os.listdir('target/b'))
544
1907.3.2 by John Arbash Meinel
Updated the copy_tree function to allow overriding functionality.
545
    def test_copy_tree_symlinks(self):
546
        if not osutils.has_symlinks():
547
            return
548
        self.build_tree(['source/'])
549
        os.symlink('a/generic/path', 'source/lnk')
550
        osutils.copy_tree('source', 'target')
551
        self.assertEqual(['lnk'], os.listdir('target'))
552
        self.assertEqual('a/generic/path', os.readlink('target/lnk'))
553
554
    def test_copy_tree_handlers(self):
555
        processed_files = []
556
        processed_links = []
557
        def file_handler(from_path, to_path):
558
            processed_files.append(('f', from_path, to_path))
559
        def dir_handler(from_path, to_path):
560
            processed_files.append(('d', from_path, to_path))
561
        def link_handler(from_path, to_path):
562
            processed_links.append((from_path, to_path))
563
        handlers = {'file':file_handler,
564
                    'directory':dir_handler,
565
                    'symlink':link_handler,
566
                   }
567
568
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
569
        if osutils.has_symlinks():
570
            os.symlink('a/generic/path', 'source/lnk')
571
        osutils.copy_tree('source', 'target', handlers=handlers)
572
573
        self.assertEqual([('d', 'source', 'target'),
574
                          ('f', 'source/a', 'target/a'),
575
                          ('d', 'source/b', 'target/b'),
576
                          ('f', 'source/b/c', 'target/b/c'),
577
                         ], processed_files)
578
        self.failIfExists('target')
579
        if osutils.has_symlinks():
580
            self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
581
1907.3.1 by John Arbash Meinel
create a copy_tree wrapper around walkdirs()
582
1711.4.10 by John Arbash Meinel
Pull out sys.stdout.encoding handling into a separate function so it can be tested, and used elsewhere.
583
class TestTerminalEncoding(TestCase):
584
    """Test the auto-detection of proper terminal encoding."""
585
586
    def setUp(self):
587
        self._stdout = sys.stdout
588
        self._stderr = sys.stderr
589
        self._stdin = sys.stdin
590
        self._user_encoding = bzrlib.user_encoding
591
592
        self.addCleanup(self._reset)
593
594
        sys.stdout = StringIOWrapper()
595
        sys.stdout.encoding = 'stdout_encoding'
596
        sys.stderr = StringIOWrapper()
597
        sys.stderr.encoding = 'stderr_encoding'
598
        sys.stdin = StringIOWrapper()
599
        sys.stdin.encoding = 'stdin_encoding'
600
        bzrlib.user_encoding = 'user_encoding'
601
602
    def _reset(self):
603
        sys.stdout = self._stdout
604
        sys.stderr = self._stderr
605
        sys.stdin = self._stdin
606
        bzrlib.user_encoding = self._user_encoding
607
608
    def test_get_terminal_encoding(self):
609
        # first preference is stdout encoding
610
        self.assertEqual('stdout_encoding', osutils.get_terminal_encoding())
611
612
        sys.stdout.encoding = None
613
        # if sys.stdout is None, fall back to sys.stdin
614
        self.assertEqual('stdin_encoding', osutils.get_terminal_encoding())
615
616
        sys.stdin.encoding = None
617
        # and in the worst case, use bzrlib.user_encoding
618
        self.assertEqual('user_encoding', osutils.get_terminal_encoding())
619
1963.1.5 by John Arbash Meinel
Create an osutils helper function for modifying the environment
620
621
class TestSetUnsetEnv(TestCase):
622
    """Test updating the environment"""
623
624
    def setUp(self):
625
        super(TestSetUnsetEnv, self).setUp()
626
627
        self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'),
628
                         'Environment was not cleaned up properly.'
629
                         ' Variable BZR_TEST_ENV_VAR should not exist.')
630
        def cleanup():
631
            if 'BZR_TEST_ENV_VAR' in os.environ:
632
                del os.environ['BZR_TEST_ENV_VAR']
633
634
        self.addCleanup(cleanup)
635
636
    def test_set(self):
637
        """Test that we can set an env variable"""
638
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
639
        self.assertEqual(None, old)
640
        self.assertEqual('foo', os.environ.get('BZR_TEST_ENV_VAR'))
641
642
    def test_double_set(self):
643
        """Test that we get the old value out"""
644
        osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
645
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'bar')
646
        self.assertEqual('foo', old)
647
        self.assertEqual('bar', os.environ.get('BZR_TEST_ENV_VAR'))
648
649
    def test_unicode(self):
650
        """Environment can only contain plain strings
651
        
652
        So Unicode strings must be encoded.
653
        """
654
        # Try a few different characters, to see if we can get
655
        # one that will be valid in the user_encoding
656
        possible_vals = [u'm\xb5', u'\xe1', u'\u0410']
657
        for uni_val in possible_vals:
658
            try:
659
                env_val = uni_val.encode(bzrlib.user_encoding)
660
            except UnicodeEncodeError:
661
                # Try a different character
662
                pass
663
            else:
664
                break
665
        else:
666
            raise TestSkipped('Cannot find a unicode character that works in'
667
                              ' encoding %s' % (bzrlib.user_encoding,))
668
669
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
670
        self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
671
672
    def test_unset(self):
673
        """Test that passing None will remove the env var"""
674
        osutils.set_or_unset_env('BZR_TEST_ENV_VAR', 'foo')
675
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', None)
676
        self.assertEqual('foo', old)
677
        self.assertEqual(None, os.environ.get('BZR_TEST_ENV_VAR'))
678
        self.failIf('BZR_TEST_ENV_VAR' in os.environ)
679
2215.6.2 by James Henstridge
add some simple tests for local_time_offset()
680
681
class TestLocalTimeOffset(TestCase):
682
683
    def test_local_time_offset(self):
684
        """Test that local_time_offset() returns a sane value."""
685
        offset = osutils.local_time_offset()
686
        self.assertTrue(isinstance(offset, int))
2215.6.3 by James Henstridge
narrow the range that the local_time_offset() test uses
687
        # Test that the offset is no more than a eighteen hours in
688
        # either direction.
689
        # Time zone handling is system specific, so it is difficult to
690
        # do more specific tests, but a value outside of this range is
691
        # probably wrong.
692
        eighteen_hours = 18 * 3600
693
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
2215.6.2 by James Henstridge
add some simple tests for local_time_offset()
694
695
    def test_local_time_offset_with_timestamp(self):
696
        """Test that local_time_offset() works with a timestamp."""
697
        offset = osutils.local_time_offset(1000000000.1234567)
698
        self.assertTrue(isinstance(offset, int))
2215.6.3 by James Henstridge
narrow the range that the local_time_offset() test uses
699
        eighteen_hours = 18 * 3600
700
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)