~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_osutils.py

  • Committer: Ian Clatworthy
  • Date: 2010-05-26 04:26:59 UTC
  • mto: (5255.2.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5256.
  • Revision ID: ian.clatworthy@canonical.com-20100526042659-2e3p4qdjr0sby0bt
Fix PDF generation of User Reference

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
29
29
    errors,
30
30
    osutils,
31
31
    tests,
 
32
    trace,
32
33
    win32utils,
33
34
    )
34
 
from bzrlib.errors import BzrBadParameterNotUnicode, InvalidURL
35
 
from bzrlib.osutils import (
36
 
        is_inside_any,
37
 
        is_inside_or_parent_of_any,
38
 
        pathjoin,
39
 
        pumpfile,
40
 
        pump_string_file,
41
 
        canonical_relpath,
42
 
        )
43
35
from bzrlib.tests import (
44
 
        Feature,
45
 
        probe_unicode_in_user_encoding,
46
 
        StringIOWrapper,
47
 
        SymlinkFeature,
48
 
        CaseInsCasePresFilenameFeature,
49
 
        TestCase,
50
 
        TestCaseInTempDir,
51
 
        TestSkipped,
52
 
        )
53
 
from bzrlib.tests.file_utils import (
54
 
    FakeReadFile,
 
36
    features,
 
37
    file_utils,
 
38
    test__walkdirs_win32,
55
39
    )
56
 
from bzrlib.tests.test__walkdirs_win32 import Win32ReadDirFeature
57
 
 
58
 
 
59
 
class _UTF8DirReaderFeature(Feature):
 
40
 
 
41
 
 
42
class _UTF8DirReaderFeature(tests.Feature):
60
43
 
61
44
    def _probe(self):
62
45
        try:
71
54
 
72
55
UTF8DirReaderFeature = _UTF8DirReaderFeature()
73
56
 
74
 
 
75
 
class TestOSUtils(TestCaseInTempDir):
 
57
term_ios_feature = tests.ModuleAvailableFeature('termios')
 
58
 
 
59
 
 
60
def _already_unicode(s):
 
61
    return s
 
62
 
 
63
 
 
64
def _utf8_to_unicode(s):
 
65
    return s.decode('UTF-8')
 
66
 
 
67
 
 
68
def dir_reader_scenarios():
 
69
    # For each dir reader we define:
 
70
 
 
71
    # - native_to_unicode: a function converting the native_abspath as returned
 
72
    #   by DirReader.read_dir to its unicode representation
 
73
 
 
74
    # UnicodeDirReader is the fallback, it should be tested on all platforms.
 
75
    scenarios = [('unicode',
 
76
                  dict(_dir_reader_class=osutils.UnicodeDirReader,
 
77
                       _native_to_unicode=_already_unicode))]
 
78
    # Some DirReaders are platform specific and even there they may not be
 
79
    # available.
 
80
    if UTF8DirReaderFeature.available():
 
81
        from bzrlib import _readdir_pyx
 
82
        scenarios.append(('utf8',
 
83
                          dict(_dir_reader_class=_readdir_pyx.UTF8DirReader,
 
84
                               _native_to_unicode=_utf8_to_unicode)))
 
85
 
 
86
    if test__walkdirs_win32.win32_readdir_feature.available():
 
87
        try:
 
88
            from bzrlib import _walkdirs_win32
 
89
            scenarios.append(
 
90
                ('win32',
 
91
                 dict(_dir_reader_class=_walkdirs_win32.Win32ReadDir,
 
92
                      _native_to_unicode=_already_unicode)))
 
93
        except ImportError:
 
94
            pass
 
95
    return scenarios
 
96
 
 
97
 
 
98
def load_tests(basic_tests, module, loader):
 
99
    suite = loader.suiteClass()
 
100
    dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
 
101
        basic_tests, tests.condition_isinstance(TestDirReader))
 
102
    tests.multiply_tests(dir_reader_tests, dir_reader_scenarios(), suite)
 
103
    suite.addTest(remaining_tests)
 
104
    return suite
 
105
 
 
106
 
 
107
class TestContainsWhitespace(tests.TestCase):
76
108
 
77
109
    def test_contains_whitespace(self):
78
110
        self.failUnless(osutils.contains_whitespace(u' '))
88
120
        self.failIf(osutils.contains_whitespace(u'hellothere'))
89
121
        self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
90
122
 
 
123
 
 
124
class TestRename(tests.TestCaseInTempDir):
 
125
 
 
126
    def create_file(self, filename, content):
 
127
        f = open(filename, 'wb')
 
128
        try:
 
129
            f.write(content)
 
130
        finally:
 
131
            f.close()
 
132
 
 
133
    def _fancy_rename(self, a, b):
 
134
        osutils.fancy_rename(a, b, rename_func=os.rename,
 
135
                             unlink_func=os.unlink)
 
136
 
91
137
    def test_fancy_rename(self):
92
138
        # This should work everywhere
93
 
        def rename(a, b):
94
 
            osutils.fancy_rename(a, b,
95
 
                    rename_func=os.rename,
96
 
                    unlink_func=os.unlink)
97
 
 
98
 
        open('a', 'wb').write('something in a\n')
99
 
        rename('a', 'b')
 
139
        self.create_file('a', 'something in a\n')
 
140
        self._fancy_rename('a', 'b')
100
141
        self.failIfExists('a')
101
142
        self.failUnlessExists('b')
102
143
        self.check_file_contents('b', 'something in a\n')
103
144
 
104
 
        open('a', 'wb').write('new something in a\n')
105
 
        rename('b', 'a')
 
145
        self.create_file('a', 'new something in a\n')
 
146
        self._fancy_rename('b', 'a')
106
147
 
107
148
        self.check_file_contents('a', 'something in a\n')
108
149
 
 
150
    def test_fancy_rename_fails_source_missing(self):
 
151
        # An exception should be raised, and the target should be left in place
 
152
        self.create_file('target', 'data in target\n')
 
153
        self.assertRaises((IOError, OSError), self._fancy_rename,
 
154
                          'missingsource', 'target')
 
155
        self.failUnlessExists('target')
 
156
        self.check_file_contents('target', 'data in target\n')
 
157
 
 
158
    def test_fancy_rename_fails_if_source_and_target_missing(self):
 
159
        self.assertRaises((IOError, OSError), self._fancy_rename,
 
160
                          'missingsource', 'missingtarget')
 
161
 
109
162
    def test_rename(self):
110
163
        # Rename should be semi-atomic on all platforms
111
 
        open('a', 'wb').write('something in a\n')
 
164
        self.create_file('a', 'something in a\n')
112
165
        osutils.rename('a', 'b')
113
166
        self.failIfExists('a')
114
167
        self.failUnlessExists('b')
115
168
        self.check_file_contents('b', 'something in a\n')
116
169
 
117
 
        open('a', 'wb').write('new something in a\n')
 
170
        self.create_file('a', 'new something in a\n')
118
171
        osutils.rename('b', 'a')
119
172
 
120
173
        self.check_file_contents('a', 'something in a\n')
131
184
        shape = sorted(os.listdir('.'))
132
185
        self.assertEquals(['A', 'B'], shape)
133
186
 
 
187
 
 
188
class TestRandChars(tests.TestCase):
 
189
 
134
190
    def test_01_rand_chars_empty(self):
135
191
        result = osutils.rand_chars(0)
136
192
        self.assertEqual(result, '')
141
197
        self.assertEqual(type(result), str)
142
198
        self.assertContainsRe(result, r'^[a-z0-9]{100}$')
143
199
 
 
200
 
 
201
class TestIsInside(tests.TestCase):
 
202
 
144
203
    def test_is_inside(self):
145
204
        is_inside = osutils.is_inside
146
205
        self.assertTrue(is_inside('src', 'src/foo.c'))
151
210
        self.assertTrue(is_inside('', 'foo.c'))
152
211
 
153
212
    def test_is_inside_any(self):
154
 
        SRC_FOO_C = pathjoin('src', 'foo.c')
 
213
        SRC_FOO_C = osutils.pathjoin('src', 'foo.c')
155
214
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
156
215
                         (['src'], SRC_FOO_C),
157
216
                         (['src'], 'src'),
158
217
                         ]:
159
 
            self.assert_(is_inside_any(dirs, fn))
 
218
            self.assert_(osutils.is_inside_any(dirs, fn))
160
219
        for dirs, fn in [(['src'], 'srccontrol'),
161
220
                         (['src'], 'srccontrol/foo')]:
162
 
            self.assertFalse(is_inside_any(dirs, fn))
 
221
            self.assertFalse(osutils.is_inside_any(dirs, fn))
163
222
 
164
223
    def test_is_inside_or_parent_of_any(self):
165
224
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
168
227
                         (['src/bar.c', 'bla/foo.c'], 'src'),
169
228
                         (['src'], 'src'),
170
229
                         ]:
171
 
            self.assert_(is_inside_or_parent_of_any(dirs, fn))
 
230
            self.assert_(osutils.is_inside_or_parent_of_any(dirs, fn))
172
231
 
173
232
        for dirs, fn in [(['src'], 'srccontrol'),
174
233
                         (['srccontrol/foo.c'], 'src'),
175
234
                         (['src'], 'srccontrol/foo')]:
176
 
            self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
 
235
            self.assertFalse(osutils.is_inside_or_parent_of_any(dirs, fn))
 
236
 
 
237
 
 
238
class TestRmTree(tests.TestCaseInTempDir):
177
239
 
178
240
    def test_rmtree(self):
179
241
        # Check to remove tree with read-only files/dirs
193
255
        self.failIfExists('dir/file')
194
256
        self.failIfExists('dir')
195
257
 
 
258
 
 
259
class TestDeleteAny(tests.TestCaseInTempDir):
 
260
 
 
261
    def test_delete_any_readonly(self):
 
262
        # from <https://bugs.launchpad.net/bzr/+bug/218206>
 
263
        self.build_tree(['d/', 'f'])
 
264
        osutils.make_readonly('d')
 
265
        osutils.make_readonly('f')
 
266
 
 
267
        osutils.delete_any('f')
 
268
        osutils.delete_any('d')
 
269
 
 
270
 
 
271
class TestKind(tests.TestCaseInTempDir):
 
272
 
196
273
    def test_file_kind(self):
197
274
        self.build_tree(['file', 'dir/'])
198
275
        self.assertEquals('file', osutils.file_kind('file'))
228
305
                os.remove('socket')
229
306
 
230
307
    def test_kind_marker(self):
231
 
        self.assertEqual(osutils.kind_marker('file'), '')
232
 
        self.assertEqual(osutils.kind_marker('directory'), '/')
233
 
        self.assertEqual(osutils.kind_marker('symlink'), '@')
234
 
        self.assertEqual(osutils.kind_marker('tree-reference'), '+')
 
308
        self.assertEqual("", osutils.kind_marker("file"))
 
309
        self.assertEqual("/", osutils.kind_marker('directory'))
 
310
        self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
 
311
        self.assertEqual("@", osutils.kind_marker("symlink"))
 
312
        self.assertEqual("+", osutils.kind_marker("tree-reference"))
 
313
        self.assertEqual("", osutils.kind_marker("fifo"))
 
314
        self.assertEqual("", osutils.kind_marker("socket"))
 
315
        self.assertEqual("", osutils.kind_marker("unknown"))
 
316
 
 
317
 
 
318
class TestUmask(tests.TestCaseInTempDir):
235
319
 
236
320
    def test_get_umask(self):
237
321
        if sys.platform == 'win32':
240
324
            return
241
325
 
242
326
        orig_umask = osutils.get_umask()
243
 
        try:
244
 
            os.umask(0222)
245
 
            self.assertEqual(0222, osutils.get_umask())
246
 
            os.umask(0022)
247
 
            self.assertEqual(0022, osutils.get_umask())
248
 
            os.umask(0002)
249
 
            self.assertEqual(0002, osutils.get_umask())
250
 
            os.umask(0027)
251
 
            self.assertEqual(0027, osutils.get_umask())
252
 
        finally:
253
 
            os.umask(orig_umask)
 
327
        self.addCleanup(os.umask, orig_umask)
 
328
        os.umask(0222)
 
329
        self.assertEqual(0222, osutils.get_umask())
 
330
        os.umask(0022)
 
331
        self.assertEqual(0022, osutils.get_umask())
 
332
        os.umask(0002)
 
333
        self.assertEqual(0002, osutils.get_umask())
 
334
        os.umask(0027)
 
335
        self.assertEqual(0027, osutils.get_umask())
 
336
 
 
337
 
 
338
class TestDateTime(tests.TestCase):
254
339
 
255
340
    def assertFormatedDelta(self, expected, seconds):
256
341
        """Assert osutils.format_delta formats as expected"""
298
383
        # Instead blackbox.test_locale should check for localized
299
384
        # dates once they do occur in output strings.
300
385
 
 
386
    def test_format_date_with_offset_in_original_timezone(self):
 
387
        self.assertEqual("Thu 1970-01-01 00:00:00 +0000",
 
388
            osutils.format_date_with_offset_in_original_timezone(0))
 
389
        self.assertEqual("Fri 1970-01-02 03:46:40 +0000",
 
390
            osutils.format_date_with_offset_in_original_timezone(100000))
 
391
        self.assertEqual("Fri 1970-01-02 05:46:40 +0200",
 
392
            osutils.format_date_with_offset_in_original_timezone(100000, 7200))
 
393
 
 
394
    def test_local_time_offset(self):
 
395
        """Test that local_time_offset() returns a sane value."""
 
396
        offset = osutils.local_time_offset()
 
397
        self.assertTrue(isinstance(offset, int))
 
398
        # Test that the offset is no more than a eighteen hours in
 
399
        # either direction.
 
400
        # Time zone handling is system specific, so it is difficult to
 
401
        # do more specific tests, but a value outside of this range is
 
402
        # probably wrong.
 
403
        eighteen_hours = 18 * 3600
 
404
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
405
 
 
406
    def test_local_time_offset_with_timestamp(self):
 
407
        """Test that local_time_offset() works with a timestamp."""
 
408
        offset = osutils.local_time_offset(1000000000.1234567)
 
409
        self.assertTrue(isinstance(offset, int))
 
410
        eighteen_hours = 18 * 3600
 
411
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
412
 
 
413
 
 
414
class TestLinks(tests.TestCaseInTempDir):
 
415
 
301
416
    def test_dereference_path(self):
302
 
        self.requireFeature(SymlinkFeature)
 
417
        self.requireFeature(tests.SymlinkFeature)
303
418
        cwd = osutils.realpath('.')
304
419
        os.mkdir('bar')
305
420
        bar_path = osutils.pathjoin(cwd, 'bar')
346
461
            osutils.make_readonly('dangling')
347
462
            osutils.make_writable('dangling')
348
463
 
349
 
    def test_kind_marker(self):
350
 
        self.assertEqual("", osutils.kind_marker("file"))
351
 
        self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
352
 
        self.assertEqual("@", osutils.kind_marker("symlink"))
353
 
        self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
354
 
 
355
464
    def test_host_os_dereferences_symlinks(self):
356
465
        osutils.host_os_dereferences_symlinks()
357
466
 
358
467
 
359
 
class TestCanonicalRelPath(TestCaseInTempDir):
 
468
class TestCanonicalRelPath(tests.TestCaseInTempDir):
360
469
 
361
 
    _test_needs_features = [CaseInsCasePresFilenameFeature]
 
470
    _test_needs_features = [tests.CaseInsCasePresFilenameFeature]
362
471
 
363
472
    def test_canonical_relpath_simple(self):
364
473
        f = file('MixedCaseName', 'w')
365
474
        f.close()
366
 
        self.failUnlessEqual(
367
 
            canonical_relpath(self.test_base_dir, 'mixedcasename'),
368
 
            'work/MixedCaseName')
 
475
        actual = osutils.canonical_relpath(self.test_base_dir, 'mixedcasename')
 
476
        self.failUnlessEqual('work/MixedCaseName', actual)
369
477
 
370
478
    def test_canonical_relpath_missing_tail(self):
371
479
        os.mkdir('MixedCaseParent')
372
 
        self.failUnlessEqual(
373
 
            canonical_relpath(self.test_base_dir, 'mixedcaseparent/nochild'),
374
 
            'work/MixedCaseParent/nochild')
375
 
 
376
 
 
377
 
class TestPumpFile(TestCase):
 
480
        actual = osutils.canonical_relpath(self.test_base_dir,
 
481
                                           'mixedcaseparent/nochild')
 
482
        self.failUnlessEqual('work/MixedCaseParent/nochild', actual)
 
483
 
 
484
 
 
485
class Test_CICPCanonicalRelpath(tests.TestCaseWithTransport):
 
486
 
 
487
    def assertRelpath(self, expected, base, path):
 
488
        actual = osutils._cicp_canonical_relpath(base, path)
 
489
        self.assertEqual(expected, actual)
 
490
 
 
491
    def test_simple(self):
 
492
        self.build_tree(['MixedCaseName'])
 
493
        base = osutils.realpath(self.get_transport('.').local_abspath('.'))
 
494
        self.assertRelpath('MixedCaseName', base, 'mixedcAsename')
 
495
 
 
496
    def test_subdir_missing_tail(self):
 
497
        self.build_tree(['MixedCaseParent/', 'MixedCaseParent/a_child'])
 
498
        base = osutils.realpath(self.get_transport('.').local_abspath('.'))
 
499
        self.assertRelpath('MixedCaseParent/a_child', base,
 
500
                           'MixedCaseParent/a_child')
 
501
        self.assertRelpath('MixedCaseParent/a_child', base,
 
502
                           'MixedCaseParent/A_Child')
 
503
        self.assertRelpath('MixedCaseParent/not_child', base,
 
504
                           'MixedCaseParent/not_child')
 
505
 
 
506
    def test_at_root_slash(self):
 
507
        # We can't test this on Windows, because it has a 'MIN_ABS_PATHLENGTH'
 
508
        # check...
 
509
        if osutils.MIN_ABS_PATHLENGTH > 1:
 
510
            raise tests.TestSkipped('relpath requires %d chars'
 
511
                                    % osutils.MIN_ABS_PATHLENGTH)
 
512
        self.assertRelpath('foo', '/', '/foo')
 
513
 
 
514
    def test_at_root_drive(self):
 
515
        if sys.platform != 'win32':
 
516
            raise tests.TestNotApplicable('we can only test drive-letter relative'
 
517
                                          ' paths on Windows where we have drive'
 
518
                                          ' letters.')
 
519
        # see bug #322807
 
520
        # The specific issue is that when at the root of a drive, 'abspath'
 
521
        # returns "C:/" or just "/". However, the code assumes that abspath
 
522
        # always returns something like "C:/foo" or "/foo" (no trailing slash).
 
523
        self.assertRelpath('foo', 'C:/', 'C:/foo')
 
524
        self.assertRelpath('foo', 'X:/', 'X:/foo')
 
525
        self.assertRelpath('foo', 'X:/', 'X://foo')
 
526
 
 
527
 
 
528
class TestPumpFile(tests.TestCase):
378
529
    """Test pumpfile method."""
 
530
 
379
531
    def setUp(self):
380
 
        TestCase.setUp(self)
 
532
        tests.TestCase.setUp(self)
381
533
        # create a test datablock
382
534
        self.block_size = 512
383
535
        pattern = '0123456789ABCDEF'
390
542
        # make sure test data is larger than max read size
391
543
        self.assertTrue(self.test_data_len > self.block_size)
392
544
 
393
 
        from_file = FakeReadFile(self.test_data)
 
545
        from_file = file_utils.FakeReadFile(self.test_data)
394
546
        to_file = StringIO()
395
547
 
396
548
        # read (max / 2) bytes and verify read size wasn't affected
397
549
        num_bytes_to_read = self.block_size / 2
398
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
550
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
399
551
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
400
552
        self.assertEqual(from_file.get_read_count(), 1)
401
553
 
402
554
        # read (max) bytes and verify read size wasn't affected
403
555
        num_bytes_to_read = self.block_size
404
556
        from_file.reset_read_count()
405
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
557
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
406
558
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
407
559
        self.assertEqual(from_file.get_read_count(), 1)
408
560
 
409
561
        # read (max + 1) bytes and verify read size was limited
410
562
        num_bytes_to_read = self.block_size + 1
411
563
        from_file.reset_read_count()
412
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
564
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
413
565
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
414
566
        self.assertEqual(from_file.get_read_count(), 2)
415
567
 
416
568
        # finish reading the rest of the data
417
569
        num_bytes_to_read = self.test_data_len - to_file.tell()
418
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
570
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
419
571
 
420
572
        # report error if the data wasn't equal (we only report the size due
421
573
        # to the length of the data)
431
583
        self.assertTrue(self.test_data_len > self.block_size)
432
584
 
433
585
        # retrieve data in blocks
434
 
        from_file = FakeReadFile(self.test_data)
 
586
        from_file = file_utils.FakeReadFile(self.test_data)
435
587
        to_file = StringIO()
436
 
        pumpfile(from_file, to_file, self.test_data_len, self.block_size)
 
588
        osutils.pumpfile(from_file, to_file, self.test_data_len,
 
589
                         self.block_size)
437
590
 
438
591
        # verify read size was equal to the maximum read size
439
592
        self.assertTrue(from_file.get_max_read_size() > 0)
454
607
        self.assertTrue(self.test_data_len > self.block_size)
455
608
 
456
609
        # retrieve data to EOF
457
 
        from_file = FakeReadFile(self.test_data)
 
610
        from_file = file_utils.FakeReadFile(self.test_data)
458
611
        to_file = StringIO()
459
 
        pumpfile(from_file, to_file, -1, self.block_size)
 
612
        osutils.pumpfile(from_file, to_file, -1, self.block_size)
460
613
 
461
614
        # verify read size was equal to the maximum read size
462
615
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
474
627
        test verifies that any existing usages of pumpfile will not be broken
475
628
        with this new version."""
476
629
        # retrieve data using default (old) pumpfile method
477
 
        from_file = FakeReadFile(self.test_data)
 
630
        from_file = file_utils.FakeReadFile(self.test_data)
478
631
        to_file = StringIO()
479
 
        pumpfile(from_file, to_file)
 
632
        osutils.pumpfile(from_file, to_file)
480
633
 
481
634
        # report error if the data wasn't equal (we only report the size due
482
635
        # to the length of the data)
491
644
            activity.append((length, direction))
492
645
        from_file = StringIO(self.test_data)
493
646
        to_file = StringIO()
494
 
        pumpfile(from_file, to_file, buff_size=500,
495
 
                 report_activity=log_activity, direction='read')
 
647
        osutils.pumpfile(from_file, to_file, buff_size=500,
 
648
                         report_activity=log_activity, direction='read')
496
649
        self.assertEqual([(500, 'read'), (500, 'read'), (500, 'read'),
497
650
                          (36, 'read')], activity)
498
651
 
499
652
        from_file = StringIO(self.test_data)
500
653
        to_file = StringIO()
501
654
        del activity[:]
502
 
        pumpfile(from_file, to_file, buff_size=500,
503
 
                 report_activity=log_activity, direction='write')
 
655
        osutils.pumpfile(from_file, to_file, buff_size=500,
 
656
                         report_activity=log_activity, direction='write')
504
657
        self.assertEqual([(500, 'write'), (500, 'write'), (500, 'write'),
505
658
                          (36, 'write')], activity)
506
659
 
508
661
        from_file = StringIO(self.test_data)
509
662
        to_file = StringIO()
510
663
        del activity[:]
511
 
        pumpfile(from_file, to_file, buff_size=500, read_length=1028,
512
 
                 report_activity=log_activity, direction='read')
 
664
        osutils.pumpfile(from_file, to_file, buff_size=500, read_length=1028,
 
665
                         report_activity=log_activity, direction='read')
513
666
        self.assertEqual([(500, 'read'), (500, 'read'), (28, 'read')], activity)
514
667
 
515
668
 
516
669
 
517
 
class TestPumpStringFile(TestCase):
 
670
class TestPumpStringFile(tests.TestCase):
518
671
 
519
672
    def test_empty(self):
520
673
        output = StringIO()
521
 
        pump_string_file("", output)
 
674
        osutils.pump_string_file("", output)
522
675
        self.assertEqual("", output.getvalue())
523
676
 
524
677
    def test_more_than_segment_size(self):
525
678
        output = StringIO()
526
 
        pump_string_file("123456789", output, 2)
 
679
        osutils.pump_string_file("123456789", output, 2)
527
680
        self.assertEqual("123456789", output.getvalue())
528
681
 
529
682
    def test_segment_size(self):
530
683
        output = StringIO()
531
 
        pump_string_file("12", output, 2)
 
684
        osutils.pump_string_file("12", output, 2)
532
685
        self.assertEqual("12", output.getvalue())
533
686
 
534
687
    def test_segment_size_multiple(self):
535
688
        output = StringIO()
536
 
        pump_string_file("1234", output, 2)
 
689
        osutils.pump_string_file("1234", output, 2)
537
690
        self.assertEqual("1234", output.getvalue())
538
691
 
539
692
 
540
 
class TestSafeUnicode(TestCase):
 
693
class TestRelpath(tests.TestCase):
 
694
 
 
695
    def test_simple_relpath(self):
 
696
        cwd = osutils.getcwd()
 
697
        subdir = cwd + '/subdir'
 
698
        self.assertEqual('subdir', osutils.relpath(cwd, subdir))
 
699
 
 
700
    def test_deep_relpath(self):
 
701
        cwd = osutils.getcwd()
 
702
        subdir = cwd + '/sub/subsubdir'
 
703
        self.assertEqual('sub/subsubdir', osutils.relpath(cwd, subdir))
 
704
 
 
705
    def test_not_relative(self):
 
706
        self.assertRaises(errors.PathNotChild,
 
707
                          osutils.relpath, 'C:/path', 'H:/path')
 
708
        self.assertRaises(errors.PathNotChild,
 
709
                          osutils.relpath, 'C:/', 'H:/path')
 
710
 
 
711
 
 
712
class TestSafeUnicode(tests.TestCase):
541
713
 
542
714
    def test_from_ascii_string(self):
543
715
        self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
552
724
        self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
553
725
 
554
726
    def test_bad_utf8_string(self):
555
 
        self.assertRaises(BzrBadParameterNotUnicode,
 
727
        self.assertRaises(errors.BzrBadParameterNotUnicode,
556
728
                          osutils.safe_unicode,
557
729
                          '\xbb\xbb')
558
730
 
559
731
 
560
 
class TestSafeUtf8(TestCase):
 
732
class TestSafeUtf8(tests.TestCase):
561
733
 
562
734
    def test_from_ascii_string(self):
563
735
        f = 'foobar'
573
745
        self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
574
746
 
575
747
    def test_bad_utf8_string(self):
576
 
        self.assertRaises(BzrBadParameterNotUnicode,
 
748
        self.assertRaises(errors.BzrBadParameterNotUnicode,
577
749
                          osutils.safe_utf8, '\xbb\xbb')
578
750
 
579
751
 
580
 
class TestSafeRevisionId(TestCase):
 
752
class TestSafeRevisionId(tests.TestCase):
581
753
 
582
754
    def test_from_ascii_string(self):
583
755
        # this shouldn't give a warning because it's getting an ascii string
605
777
        self.assertEqual(None, osutils.safe_revision_id(None))
606
778
 
607
779
 
608
 
class TestSafeFileId(TestCase):
 
780
class TestSafeFileId(tests.TestCase):
609
781
 
610
782
    def test_from_ascii_string(self):
611
783
        self.assertEqual('foobar', osutils.safe_file_id('foobar'))
631
803
        self.assertEqual(None, osutils.safe_file_id(None))
632
804
 
633
805
 
634
 
class TestWin32Funcs(TestCase):
635
 
    """Test that the _win32 versions of os utilities return appropriate paths."""
 
806
class TestWin32Funcs(tests.TestCase):
 
807
    """Test that _win32 versions of os utilities return appropriate paths."""
636
808
 
637
809
    def test_abspath(self):
638
810
        self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
645
817
        self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
646
818
 
647
819
    def test_pathjoin(self):
648
 
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path', 'to', 'foo'))
649
 
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path\\to', 'C:\\foo'))
650
 
        self.assertEqual('C:/foo', osutils._win32_pathjoin('path/to', 'C:/foo'))
651
 
        self.assertEqual('path/to/foo', osutils._win32_pathjoin('path/to/', 'foo'))
652
 
        self.assertEqual('/foo', osutils._win32_pathjoin('C:/path/to/', '/foo'))
653
 
        self.assertEqual('/foo', osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
 
820
        self.assertEqual('path/to/foo',
 
821
                         osutils._win32_pathjoin('path', 'to', 'foo'))
 
822
        self.assertEqual('C:/foo',
 
823
                         osutils._win32_pathjoin('path\\to', 'C:\\foo'))
 
824
        self.assertEqual('C:/foo',
 
825
                         osutils._win32_pathjoin('path/to', 'C:/foo'))
 
826
        self.assertEqual('path/to/foo',
 
827
                         osutils._win32_pathjoin('path/to/', 'foo'))
 
828
        self.assertEqual('/foo',
 
829
                         osutils._win32_pathjoin('C:/path/to/', '/foo'))
 
830
        self.assertEqual('/foo',
 
831
                         osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
654
832
 
655
833
    def test_normpath(self):
656
 
        self.assertEqual('path/to/foo', osutils._win32_normpath(r'path\\from\..\to\.\foo'))
657
 
        self.assertEqual('path/to/foo', osutils._win32_normpath('path//from/../to/./foo'))
 
834
        self.assertEqual('path/to/foo',
 
835
                         osutils._win32_normpath(r'path\\from\..\to\.\foo'))
 
836
        self.assertEqual('path/to/foo',
 
837
                         osutils._win32_normpath('path//from/../to/./foo'))
658
838
 
659
839
    def test_getcwd(self):
660
840
        cwd = osutils._win32_getcwd()
689
869
        self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
690
870
 
691
871
 
692
 
class TestWin32FuncsDirs(TestCaseInTempDir):
 
872
class TestWin32FuncsDirs(tests.TestCaseInTempDir):
693
873
    """Test win32 functions that create files."""
694
874
 
695
875
    def test_getcwd(self):
696
 
        if win32utils.winver == 'Windows 98':
697
 
            raise TestSkipped('Windows 98 cannot handle unicode filenames')
698
 
        # Make sure getcwd can handle unicode filenames
699
 
        try:
700
 
            os.mkdir(u'mu-\xb5')
701
 
        except UnicodeError:
702
 
            raise TestSkipped("Unable to create Unicode filename")
703
 
 
 
876
        self.requireFeature(tests.UnicodeFilenameFeature)
 
877
        os.mkdir(u'mu-\xb5')
704
878
        os.chdir(u'mu-\xb5')
705
879
        # TODO: jam 20060427 This will probably fail on Mac OSX because
706
880
        #       it will change the normalization of B\xe5gfors
711
885
    def test_minimum_path_selection(self):
712
886
        self.assertEqual(set(),
713
887
            osutils.minimum_path_selection([]))
 
888
        self.assertEqual(set(['a']),
 
889
            osutils.minimum_path_selection(['a']))
714
890
        self.assertEqual(set(['a', 'b']),
715
891
            osutils.minimum_path_selection(['a', 'b']))
716
892
        self.assertEqual(set(['a/', 'b']),
717
893
            osutils.minimum_path_selection(['a/', 'b']))
718
894
        self.assertEqual(set(['a/', 'b']),
719
895
            osutils.minimum_path_selection(['a/c', 'a/', 'b']))
 
896
        self.assertEqual(set(['a-b', 'a', 'a0b']),
 
897
            osutils.minimum_path_selection(['a-b', 'a/b', 'a0b', 'a']))
720
898
 
721
899
    def test_mkdtemp(self):
722
900
        tmpdir = osutils._win32_mkdtemp(dir='.')
778
956
        self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
779
957
 
780
958
 
781
 
class TestMacFuncsDirs(TestCaseInTempDir):
 
959
class TestParentDirectories(tests.TestCaseInTempDir):
 
960
    """Test osutils.parent_directories()"""
 
961
 
 
962
    def test_parent_directories(self):
 
963
        self.assertEqual([], osutils.parent_directories('a'))
 
964
        self.assertEqual(['a'], osutils.parent_directories('a/b'))
 
965
        self.assertEqual(['a/b', 'a'], osutils.parent_directories('a/b/c'))
 
966
 
 
967
 
 
968
class TestMacFuncsDirs(tests.TestCaseInTempDir):
782
969
    """Test mac special functions that require directories."""
783
970
 
784
971
    def test_getcwd(self):
785
 
        # On Mac, this will actually create Ba\u030agfors
786
 
        # but chdir will still work, because it accepts both paths
787
 
        try:
788
 
            os.mkdir(u'B\xe5gfors')
789
 
        except UnicodeError:
790
 
            raise TestSkipped("Unable to create Unicode filename")
791
 
 
 
972
        self.requireFeature(tests.UnicodeFilenameFeature)
 
973
        os.mkdir(u'B\xe5gfors')
792
974
        os.chdir(u'B\xe5gfors')
793
975
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
794
976
 
795
977
    def test_getcwd_nonnorm(self):
 
978
        self.requireFeature(tests.UnicodeFilenameFeature)
796
979
        # Test that _mac_getcwd() will normalize this path
797
 
        try:
798
 
            os.mkdir(u'Ba\u030agfors')
799
 
        except UnicodeError:
800
 
            raise TestSkipped("Unable to create Unicode filename")
801
 
 
 
980
        os.mkdir(u'Ba\u030agfors')
802
981
        os.chdir(u'Ba\u030agfors')
803
982
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
804
983
 
805
984
 
806
 
class TestChunksToLines(TestCase):
 
985
class TestChunksToLines(tests.TestCase):
807
986
 
808
987
    def test_smoketest(self):
809
988
        self.assertEqual(['foo\n', 'bar\n', 'baz\n'],
813
992
 
814
993
    def test_osutils_binding(self):
815
994
        from bzrlib.tests import test__chunks_to_lines
816
 
        if test__chunks_to_lines.CompiledChunksToLinesFeature.available():
 
995
        if test__chunks_to_lines.compiled_chunkstolines_feature.available():
817
996
            from bzrlib._chunks_to_lines_pyx import chunks_to_lines
818
997
        else:
819
998
            from bzrlib._chunks_to_lines_py import chunks_to_lines
820
999
        self.assertIs(chunks_to_lines, osutils.chunks_to_lines)
821
1000
 
822
1001
 
823
 
class TestSplitLines(TestCase):
 
1002
class TestSplitLines(tests.TestCase):
824
1003
 
825
1004
    def test_split_unicode(self):
826
1005
        self.assertEqual([u'foo\n', u'bar\xae'],
833
1012
                         osutils.split_lines('foo\rbar\n'))
834
1013
 
835
1014
 
836
 
class TestWalkDirs(TestCaseInTempDir):
 
1015
class TestWalkDirs(tests.TestCaseInTempDir):
 
1016
 
 
1017
    def assertExpectedBlocks(self, expected, result):
 
1018
        self.assertEqual(expected,
 
1019
                         [(dirinfo, [line[0:3] for line in block])
 
1020
                          for dirinfo, block in result])
837
1021
 
838
1022
    def test_walkdirs(self):
839
1023
        tree = [
872
1056
            result.append((dirdetail, dirblock))
873
1057
 
874
1058
        self.assertTrue(found_bzrdir)
875
 
        self.assertEqual(expected_dirblocks,
876
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1059
        self.assertExpectedBlocks(expected_dirblocks, result)
877
1060
        # you can search a subdir only, with a supplied prefix.
878
1061
        result = []
879
1062
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
880
1063
            result.append(dirblock)
881
 
        self.assertEqual(expected_dirblocks[1:],
882
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1064
        self.assertExpectedBlocks(expected_dirblocks[1:], result)
883
1065
 
884
1066
    def test_walkdirs_os_error(self):
885
 
        # <https://bugs.edge.launchpad.net/bzr/+bug/338653>
 
1067
        # <https://bugs.launchpad.net/bzr/+bug/338653>
886
1068
        # Pyrex readdir didn't raise useful messages if it had an error
887
1069
        # reading the directory
888
1070
        if sys.platform == 'win32':
891
1073
        os.mkdir("test-unreadable")
892
1074
        os.chmod("test-unreadable", 0000)
893
1075
        # must chmod it back so that it can be removed
894
 
        self.addCleanup(lambda: os.chmod("test-unreadable", 0700))
 
1076
        self.addCleanup(os.chmod, "test-unreadable", 0700)
895
1077
        # The error is not raised until the generator is actually evaluated.
896
1078
        # (It would be ok if it happened earlier but at the moment it
897
1079
        # doesn't.)
938
1120
            result.append((dirdetail, dirblock))
939
1121
 
940
1122
        self.assertTrue(found_bzrdir)
941
 
        self.assertEqual(expected_dirblocks,
942
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1123
        self.assertExpectedBlocks(expected_dirblocks, result)
 
1124
 
943
1125
        # you can search a subdir only, with a supplied prefix.
944
1126
        result = []
945
1127
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
946
1128
            result.append(dirblock)
947
 
        self.assertEqual(expected_dirblocks[1:],
948
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1129
        self.assertExpectedBlocks(expected_dirblocks[1:], result)
949
1130
 
950
1131
    def _filter_out_stat(self, result):
951
1132
        """Filter out the stat value from the walkdirs result"""
957
1138
            dirblock[:] = new_dirblock
958
1139
 
959
1140
    def _save_platform_info(self):
960
 
        cur_winver = win32utils.winver
961
 
        cur_fs_enc = osutils._fs_enc
962
 
        cur_dir_reader = osutils._selected_dir_reader
963
 
        def restore():
964
 
            win32utils.winver = cur_winver
965
 
            osutils._fs_enc = cur_fs_enc
966
 
            osutils._selected_dir_reader = cur_dir_reader
967
 
        self.addCleanup(restore)
 
1141
        self.overrideAttr(win32utils, 'winver')
 
1142
        self.overrideAttr(osutils, '_fs_enc')
 
1143
        self.overrideAttr(osutils, '_selected_dir_reader')
968
1144
 
969
 
    def assertReadFSDirIs(self, expected):
 
1145
    def assertDirReaderIs(self, expected):
970
1146
        """Assert the right implementation for _walkdirs_utf8 is chosen."""
971
1147
        # Force it to redetect
972
1148
        osutils._selected_dir_reader = None
979
1155
        self._save_platform_info()
980
1156
        win32utils.winver = None # Avoid the win32 detection code
981
1157
        osutils._fs_enc = 'UTF-8'
982
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1158
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
983
1159
 
984
1160
    def test_force_walkdirs_utf8_fs_ascii(self):
985
1161
        self.requireFeature(UTF8DirReaderFeature)
986
1162
        self._save_platform_info()
987
1163
        win32utils.winver = None # Avoid the win32 detection code
988
1164
        osutils._fs_enc = 'US-ASCII'
989
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1165
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
990
1166
 
991
1167
    def test_force_walkdirs_utf8_fs_ANSI(self):
992
1168
        self.requireFeature(UTF8DirReaderFeature)
993
1169
        self._save_platform_info()
994
1170
        win32utils.winver = None # Avoid the win32 detection code
995
1171
        osutils._fs_enc = 'ANSI_X3.4-1968'
996
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1172
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
997
1173
 
998
1174
    def test_force_walkdirs_utf8_fs_latin1(self):
999
1175
        self._save_platform_info()
1000
1176
        win32utils.winver = None # Avoid the win32 detection code
1001
1177
        osutils._fs_enc = 'latin1'
1002
 
        self.assertReadFSDirIs(osutils.UnicodeDirReader)
 
1178
        self.assertDirReaderIs(osutils.UnicodeDirReader)
1003
1179
 
1004
1180
    def test_force_walkdirs_utf8_nt(self):
1005
1181
        # Disabled because the thunk of the whole walkdirs api is disabled.
1006
 
        self.requireFeature(Win32ReadDirFeature)
 
1182
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1007
1183
        self._save_platform_info()
1008
1184
        win32utils.winver = 'Windows NT'
1009
1185
        from bzrlib._walkdirs_win32 import Win32ReadDir
1010
 
        self.assertReadFSDirIs(Win32ReadDir)
 
1186
        self.assertDirReaderIs(Win32ReadDir)
1011
1187
 
1012
1188
    def test_force_walkdirs_utf8_98(self):
1013
 
        self.requireFeature(Win32ReadDirFeature)
 
1189
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1014
1190
        self._save_platform_info()
1015
1191
        win32utils.winver = 'Windows 98'
1016
 
        self.assertReadFSDirIs(osutils.UnicodeDirReader)
 
1192
        self.assertDirReaderIs(osutils.UnicodeDirReader)
1017
1193
 
1018
1194
    def test_unicode_walkdirs(self):
1019
1195
        """Walkdirs should always return unicode paths."""
 
1196
        self.requireFeature(tests.UnicodeFilenameFeature)
1020
1197
        name0 = u'0file-\xb6'
1021
1198
        name1 = u'1dir-\u062c\u0648'
1022
1199
        name2 = u'2file-\u0633'
1027
1204
            name1 + '/' + name1 + '/',
1028
1205
            name2,
1029
1206
            ]
1030
 
        try:
1031
 
            self.build_tree(tree)
1032
 
        except UnicodeError:
1033
 
            raise TestSkipped('Could not represent Unicode chars'
1034
 
                              ' in current encoding.')
 
1207
        self.build_tree(tree)
1035
1208
        expected_dirblocks = [
1036
1209
                ((u'', u'.'),
1037
1210
                 [(name0, name0, 'file', './' + name0),
1063
1236
 
1064
1237
        The abspath portion might be in unicode or utf-8
1065
1238
        """
 
1239
        self.requireFeature(tests.UnicodeFilenameFeature)
1066
1240
        name0 = u'0file-\xb6'
1067
1241
        name1 = u'1dir-\u062c\u0648'
1068
1242
        name2 = u'2file-\u0633'
1073
1247
            name1 + '/' + name1 + '/',
1074
1248
            name2,
1075
1249
            ]
1076
 
        try:
1077
 
            self.build_tree(tree)
1078
 
        except UnicodeError:
1079
 
            raise TestSkipped('Could not represent Unicode chars'
1080
 
                              ' in current encoding.')
 
1250
        self.build_tree(tree)
1081
1251
        name0 = name0.encode('utf8')
1082
1252
        name1 = name1.encode('utf8')
1083
1253
        name2 = name2.encode('utf8')
1127
1297
 
1128
1298
        The abspath portion should be in unicode
1129
1299
        """
 
1300
        self.requireFeature(tests.UnicodeFilenameFeature)
1130
1301
        # Use the unicode reader. TODO: split into driver-and-driven unit
1131
1302
        # tests.
1132
1303
        self._save_platform_info()
1141
1312
            name1u + '/' + name1u + '/',
1142
1313
            name2u,
1143
1314
            ]
1144
 
        try:
1145
 
            self.build_tree(tree)
1146
 
        except UnicodeError:
1147
 
            raise TestSkipped('Could not represent Unicode chars'
1148
 
                              ' in current encoding.')
 
1315
        self.build_tree(tree)
1149
1316
        name0 = name0u.encode('utf8')
1150
1317
        name1 = name1u.encode('utf8')
1151
1318
        name2 = name2u.encode('utf8')
1176
1343
        self.assertEqual(expected_dirblocks, result)
1177
1344
 
1178
1345
    def test__walkdirs_utf8_win32readdir(self):
1179
 
        self.requireFeature(Win32ReadDirFeature)
 
1346
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1180
1347
        self.requireFeature(tests.UnicodeFilenameFeature)
1181
1348
        from bzrlib._walkdirs_win32 import Win32ReadDir
1182
1349
        self._save_platform_info()
1233
1400
 
1234
1401
    def test__walkdirs_utf_win32_find_file_stat_file(self):
1235
1402
        """make sure our Stat values are valid"""
1236
 
        self.requireFeature(Win32ReadDirFeature)
 
1403
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1237
1404
        self.requireFeature(tests.UnicodeFilenameFeature)
1238
1405
        from bzrlib._walkdirs_win32 import Win32ReadDir
1239
1406
        name0u = u'0file-\xb6'
1257
1424
 
1258
1425
    def test__walkdirs_utf_win32_find_file_stat_directory(self):
1259
1426
        """make sure our Stat values are valid"""
1260
 
        self.requireFeature(Win32ReadDirFeature)
 
1427
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1261
1428
        self.requireFeature(tests.UnicodeFilenameFeature)
1262
1429
        from bzrlib._walkdirs_win32 import Win32ReadDir
1263
1430
        name0u = u'0dir-\u062c\u0648'
1348
1515
            sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
1349
1516
 
1350
1517
 
1351
 
class TestCopyTree(TestCaseInTempDir):
 
1518
class TestCopyTree(tests.TestCaseInTempDir):
1352
1519
 
1353
1520
    def test_copy_basic_tree(self):
1354
1521
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
1364
1531
        self.assertEqual(['c'], os.listdir('target/b'))
1365
1532
 
1366
1533
    def test_copy_tree_symlinks(self):
1367
 
        self.requireFeature(SymlinkFeature)
 
1534
        self.requireFeature(tests.SymlinkFeature)
1368
1535
        self.build_tree(['source/'])
1369
1536
        os.symlink('a/generic/path', 'source/lnk')
1370
1537
        osutils.copy_tree('source', 'target')
1400
1567
            self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
1401
1568
 
1402
1569
 
1403
 
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
1404
 
# [bialix] 2006/12/26
1405
 
 
1406
 
 
1407
 
class TestSetUnsetEnv(TestCase):
 
1570
class TestSetUnsetEnv(tests.TestCase):
1408
1571
    """Test updating the environment"""
1409
1572
 
1410
1573
    def setUp(self):
1416
1579
        def cleanup():
1417
1580
            if 'BZR_TEST_ENV_VAR' in os.environ:
1418
1581
                del os.environ['BZR_TEST_ENV_VAR']
1419
 
 
1420
1582
        self.addCleanup(cleanup)
1421
1583
 
1422
1584
    def test_set(self):
1437
1599
 
1438
1600
        So Unicode strings must be encoded.
1439
1601
        """
1440
 
        uni_val, env_val = probe_unicode_in_user_encoding()
 
1602
        uni_val, env_val = tests.probe_unicode_in_user_encoding()
1441
1603
        if uni_val is None:
1442
 
            raise TestSkipped('Cannot find a unicode character that works in'
1443
 
                              ' encoding %s' % (osutils.get_user_encoding(),))
 
1604
            raise tests.TestSkipped(
 
1605
                'Cannot find a unicode character that works in encoding %s'
 
1606
                % (osutils.get_user_encoding(),))
1444
1607
 
1445
1608
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1446
1609
        self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1454
1617
        self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1455
1618
 
1456
1619
 
1457
 
class TestLocalTimeOffset(TestCase):
1458
 
 
1459
 
    def test_local_time_offset(self):
1460
 
        """Test that local_time_offset() returns a sane value."""
1461
 
        offset = osutils.local_time_offset()
1462
 
        self.assertTrue(isinstance(offset, int))
1463
 
        # Test that the offset is no more than a eighteen hours in
1464
 
        # either direction.
1465
 
        # Time zone handling is system specific, so it is difficult to
1466
 
        # do more specific tests, but a value outside of this range is
1467
 
        # probably wrong.
1468
 
        eighteen_hours = 18 * 3600
1469
 
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1470
 
 
1471
 
    def test_local_time_offset_with_timestamp(self):
1472
 
        """Test that local_time_offset() works with a timestamp."""
1473
 
        offset = osutils.local_time_offset(1000000000.1234567)
1474
 
        self.assertTrue(isinstance(offset, int))
1475
 
        eighteen_hours = 18 * 3600
1476
 
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1477
 
 
1478
 
 
1479
 
class TestSizeShaFile(TestCaseInTempDir):
 
1620
class TestSizeShaFile(tests.TestCaseInTempDir):
1480
1621
 
1481
1622
    def test_sha_empty(self):
1482
1623
        self.build_tree_contents([('foo', '')])
1491
1632
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
1492
1633
        self.build_tree_contents([('foo', text)])
1493
1634
        expected_sha = osutils.sha_string(text)
1494
 
        f = open('foo')
 
1635
        f = open('foo', 'rb')
1495
1636
        self.addCleanup(f.close)
1496
1637
        size, sha = osutils.size_sha_file(f)
1497
1638
        self.assertEqual(38, size)
1498
1639
        self.assertEqual(expected_sha, sha)
1499
1640
 
1500
1641
 
1501
 
class TestShaFileByName(TestCaseInTempDir):
 
1642
class TestShaFileByName(tests.TestCaseInTempDir):
1502
1643
 
1503
1644
    def test_sha_empty(self):
1504
1645
        self.build_tree_contents([('foo', '')])
1512
1653
        self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1513
1654
 
1514
1655
 
1515
 
class TestResourceLoading(TestCaseInTempDir):
 
1656
class TestResourceLoading(tests.TestCaseInTempDir):
1516
1657
 
1517
1658
    def test_resource_string(self):
1518
1659
        # test resource in bzrlib
1528
1669
        self.assertRaises(IOError, osutils.resource_string, 'bzrlib', 'yyy.xx')
1529
1670
 
1530
1671
 
1531
 
class TestReCompile(TestCase):
 
1672
class TestReCompile(tests.TestCase):
1532
1673
 
1533
1674
    def test_re_compile_checked(self):
1534
1675
        r = osutils.re_compile_checked(r'A*', re.IGNORECASE)
1544
1685
            "Invalid regular expression in test case: '*': "
1545
1686
            "nothing to repeat",
1546
1687
            str(err))
 
1688
 
 
1689
 
 
1690
class TestDirReader(tests.TestCaseInTempDir):
 
1691
 
 
1692
    # Set by load_tests
 
1693
    _dir_reader_class = None
 
1694
    _native_to_unicode = None
 
1695
 
 
1696
    def setUp(self):
 
1697
        tests.TestCaseInTempDir.setUp(self)
 
1698
        self.overrideAttr(osutils,
 
1699
                          '_selected_dir_reader', self._dir_reader_class())
 
1700
 
 
1701
    def _get_ascii_tree(self):
 
1702
        tree = [
 
1703
            '0file',
 
1704
            '1dir/',
 
1705
            '1dir/0file',
 
1706
            '1dir/1dir/',
 
1707
            '2file'
 
1708
            ]
 
1709
        expected_dirblocks = [
 
1710
                (('', '.'),
 
1711
                 [('0file', '0file', 'file'),
 
1712
                  ('1dir', '1dir', 'directory'),
 
1713
                  ('2file', '2file', 'file'),
 
1714
                 ]
 
1715
                ),
 
1716
                (('1dir', './1dir'),
 
1717
                 [('1dir/0file', '0file', 'file'),
 
1718
                  ('1dir/1dir', '1dir', 'directory'),
 
1719
                 ]
 
1720
                ),
 
1721
                (('1dir/1dir', './1dir/1dir'),
 
1722
                 [
 
1723
                 ]
 
1724
                ),
 
1725
            ]
 
1726
        return tree, expected_dirblocks
 
1727
 
 
1728
    def test_walk_cur_dir(self):
 
1729
        tree, expected_dirblocks = self._get_ascii_tree()
 
1730
        self.build_tree(tree)
 
1731
        result = list(osutils._walkdirs_utf8('.'))
 
1732
        # Filter out stat and abspath
 
1733
        self.assertEqual(expected_dirblocks,
 
1734
                         [(dirinfo, [line[0:3] for line in block])
 
1735
                          for dirinfo, block in result])
 
1736
 
 
1737
    def test_walk_sub_dir(self):
 
1738
        tree, expected_dirblocks = self._get_ascii_tree()
 
1739
        self.build_tree(tree)
 
1740
        # you can search a subdir only, with a supplied prefix.
 
1741
        result = list(osutils._walkdirs_utf8('./1dir', '1dir'))
 
1742
        # Filter out stat and abspath
 
1743
        self.assertEqual(expected_dirblocks[1:],
 
1744
                         [(dirinfo, [line[0:3] for line in block])
 
1745
                          for dirinfo, block in result])
 
1746
 
 
1747
    def _get_unicode_tree(self):
 
1748
        name0u = u'0file-\xb6'
 
1749
        name1u = u'1dir-\u062c\u0648'
 
1750
        name2u = u'2file-\u0633'
 
1751
        tree = [
 
1752
            name0u,
 
1753
            name1u + '/',
 
1754
            name1u + '/' + name0u,
 
1755
            name1u + '/' + name1u + '/',
 
1756
            name2u,
 
1757
            ]
 
1758
        name0 = name0u.encode('UTF-8')
 
1759
        name1 = name1u.encode('UTF-8')
 
1760
        name2 = name2u.encode('UTF-8')
 
1761
        expected_dirblocks = [
 
1762
                (('', '.'),
 
1763
                 [(name0, name0, 'file', './' + name0u),
 
1764
                  (name1, name1, 'directory', './' + name1u),
 
1765
                  (name2, name2, 'file', './' + name2u),
 
1766
                 ]
 
1767
                ),
 
1768
                ((name1, './' + name1u),
 
1769
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
 
1770
                                                        + '/' + name0u),
 
1771
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
 
1772
                                                            + '/' + name1u),
 
1773
                 ]
 
1774
                ),
 
1775
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
 
1776
                 [
 
1777
                 ]
 
1778
                ),
 
1779
            ]
 
1780
        return tree, expected_dirblocks
 
1781
 
 
1782
    def _filter_out(self, raw_dirblocks):
 
1783
        """Filter out a walkdirs_utf8 result.
 
1784
 
 
1785
        stat field is removed, all native paths are converted to unicode
 
1786
        """
 
1787
        filtered_dirblocks = []
 
1788
        for dirinfo, block in raw_dirblocks:
 
1789
            dirinfo = (dirinfo[0], self._native_to_unicode(dirinfo[1]))
 
1790
            details = []
 
1791
            for line in block:
 
1792
                details.append(line[0:3] + (self._native_to_unicode(line[4]), ))
 
1793
            filtered_dirblocks.append((dirinfo, details))
 
1794
        return filtered_dirblocks
 
1795
 
 
1796
    def test_walk_unicode_tree(self):
 
1797
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1798
        tree, expected_dirblocks = self._get_unicode_tree()
 
1799
        self.build_tree(tree)
 
1800
        result = list(osutils._walkdirs_utf8('.'))
 
1801
        self.assertEqual(expected_dirblocks, self._filter_out(result))
 
1802
 
 
1803
    def test_symlink(self):
 
1804
        self.requireFeature(tests.SymlinkFeature)
 
1805
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1806
        target = u'target\N{Euro Sign}'
 
1807
        link_name = u'l\N{Euro Sign}nk'
 
1808
        os.symlink(target, link_name)
 
1809
        target_utf8 = target.encode('UTF-8')
 
1810
        link_name_utf8 = link_name.encode('UTF-8')
 
1811
        expected_dirblocks = [
 
1812
                (('', '.'),
 
1813
                 [(link_name_utf8, link_name_utf8,
 
1814
                   'symlink', './' + link_name),],
 
1815
                 )]
 
1816
        result = list(osutils._walkdirs_utf8('.'))
 
1817
        self.assertEqual(expected_dirblocks, self._filter_out(result))
 
1818
 
 
1819
 
 
1820
class TestReadLink(tests.TestCaseInTempDir):
 
1821
    """Exposes os.readlink() problems and the osutils solution.
 
1822
 
 
1823
    The only guarantee offered by os.readlink(), starting with 2.6, is that a
 
1824
    unicode string will be returned if a unicode string is passed.
 
1825
 
 
1826
    But prior python versions failed to properly encode the passed unicode
 
1827
    string.
 
1828
    """
 
1829
    _test_needs_features = [tests.SymlinkFeature, tests.UnicodeFilenameFeature]
 
1830
 
 
1831
    def setUp(self):
 
1832
        super(tests.TestCaseInTempDir, self).setUp()
 
1833
        self.link = u'l\N{Euro Sign}ink'
 
1834
        self.target = u'targe\N{Euro Sign}t'
 
1835
        os.symlink(self.target, self.link)
 
1836
 
 
1837
    def test_os_readlink_link_encoding(self):
 
1838
        if sys.version_info < (2, 6):
 
1839
            self.assertRaises(UnicodeEncodeError, os.readlink, self.link)
 
1840
        else:
 
1841
            self.assertEquals(self.target,  os.readlink(self.link))
 
1842
 
 
1843
    def test_os_readlink_link_decoding(self):
 
1844
        self.assertEquals(self.target.encode(osutils._fs_enc),
 
1845
                          os.readlink(self.link.encode(osutils._fs_enc)))
 
1846
 
 
1847
 
 
1848
class TestConcurrency(tests.TestCase):
 
1849
 
 
1850
    def setUp(self):
 
1851
        super(TestConcurrency, self).setUp()
 
1852
        self.overrideAttr(osutils, '_cached_local_concurrency')
 
1853
 
 
1854
    def test_local_concurrency(self):
 
1855
        concurrency = osutils.local_concurrency()
 
1856
        self.assertIsInstance(concurrency, int)
 
1857
 
 
1858
    def test_local_concurrency_environment_variable(self):
 
1859
        os.environ['BZR_CONCURRENCY'] = '2'
 
1860
        self.assertEqual(2, osutils.local_concurrency(use_cache=False))
 
1861
        os.environ['BZR_CONCURRENCY'] = '3'
 
1862
        self.assertEqual(3, osutils.local_concurrency(use_cache=False))
 
1863
        os.environ['BZR_CONCURRENCY'] = 'foo'
 
1864
        self.assertEqual(1, osutils.local_concurrency(use_cache=False))
 
1865
 
 
1866
    def test_option_concurrency(self):
 
1867
        os.environ['BZR_CONCURRENCY'] = '1'
 
1868
        self.run_bzr('rocks --concurrency 42')
 
1869
        # Command line overrides envrionment variable
 
1870
        self.assertEquals('42', os.environ['BZR_CONCURRENCY'])
 
1871
        self.assertEquals(42, osutils.local_concurrency(use_cache=False))
 
1872
 
 
1873
 
 
1874
class TestFailedToLoadExtension(tests.TestCase):
 
1875
 
 
1876
    def _try_loading(self):
 
1877
        try:
 
1878
            import bzrlib._fictional_extension_py
 
1879
        except ImportError, e:
 
1880
            osutils.failed_to_load_extension(e)
 
1881
            return True
 
1882
 
 
1883
    def setUp(self):
 
1884
        super(TestFailedToLoadExtension, self).setUp()
 
1885
        self.overrideAttr(osutils, '_extension_load_failures', [])
 
1886
 
 
1887
    def test_failure_to_load(self):
 
1888
        self._try_loading()
 
1889
        self.assertLength(1, osutils._extension_load_failures)
 
1890
        self.assertEquals(osutils._extension_load_failures[0],
 
1891
            "No module named _fictional_extension_py")
 
1892
 
 
1893
    def test_report_extension_load_failures_no_warning(self):
 
1894
        self.assertTrue(self._try_loading())
 
1895
        warnings, result = self.callCatchWarnings(osutils.report_extension_load_failures)
 
1896
        # it used to give a Python warning; it no longer does
 
1897
        self.assertLength(0, warnings)
 
1898
 
 
1899
    def test_report_extension_load_failures_message(self):
 
1900
        log = StringIO()
 
1901
        trace.push_log_file(log)
 
1902
        self.assertTrue(self._try_loading())
 
1903
        osutils.report_extension_load_failures()
 
1904
        self.assertContainsRe(
 
1905
            log.getvalue(),
 
1906
            r"bzr: warning: some compiled extensions could not be loaded; "
 
1907
            "see <https://answers\.launchpad\.net/bzr/\+faq/703>\n"
 
1908
            )
 
1909
 
 
1910
 
 
1911
class TestTerminalWidth(tests.TestCase):
 
1912
 
 
1913
    def replace_stdout(self, new):
 
1914
        self.overrideAttr(sys, 'stdout', new)
 
1915
 
 
1916
    def replace__terminal_size(self, new):
 
1917
        self.overrideAttr(osutils, '_terminal_size', new)
 
1918
 
 
1919
    def set_fake_tty(self):
 
1920
 
 
1921
        class I_am_a_tty(object):
 
1922
            def isatty(self):
 
1923
                return True
 
1924
 
 
1925
        self.replace_stdout(I_am_a_tty())
 
1926
 
 
1927
    def test_default_values(self):
 
1928
        self.assertEqual(80, osutils.default_terminal_width)
 
1929
 
 
1930
    def test_defaults_to_BZR_COLUMNS(self):
 
1931
        # BZR_COLUMNS is set by the test framework
 
1932
        self.assertNotEqual('12', os.environ['BZR_COLUMNS'])
 
1933
        os.environ['BZR_COLUMNS'] = '12'
 
1934
        self.assertEqual(12, osutils.terminal_width())
 
1935
 
 
1936
    def test_falls_back_to_COLUMNS(self):
 
1937
        del os.environ['BZR_COLUMNS']
 
1938
        self.assertNotEqual('42', os.environ['COLUMNS'])
 
1939
        self.set_fake_tty()
 
1940
        os.environ['COLUMNS'] = '42'
 
1941
        self.assertEqual(42, osutils.terminal_width())
 
1942
 
 
1943
    def test_tty_default_without_columns(self):
 
1944
        del os.environ['BZR_COLUMNS']
 
1945
        del os.environ['COLUMNS']
 
1946
 
 
1947
        def terminal_size(w, h):
 
1948
            return 42, 42
 
1949
 
 
1950
        self.set_fake_tty()
 
1951
        # We need to override the osutils definition as it depends on the
 
1952
        # running environment that we can't control (PQM running without a
 
1953
        # controlling terminal is one example).
 
1954
        self.replace__terminal_size(terminal_size)
 
1955
        self.assertEqual(42, osutils.terminal_width())
 
1956
 
 
1957
    def test_non_tty_default_without_columns(self):
 
1958
        del os.environ['BZR_COLUMNS']
 
1959
        del os.environ['COLUMNS']
 
1960
        self.replace_stdout(None)
 
1961
        self.assertEqual(None, osutils.terminal_width())
 
1962
 
 
1963
    def test_no_TIOCGWINSZ(self):
 
1964
        self.requireFeature(term_ios_feature)
 
1965
        termios = term_ios_feature.module
 
1966
        # bug 63539 is about a termios without TIOCGWINSZ attribute
 
1967
        try:
 
1968
            orig = termios.TIOCGWINSZ
 
1969
        except AttributeError:
 
1970
            # We won't remove TIOCGWINSZ, because it doesn't exist anyway :)
 
1971
            pass
 
1972
        else:
 
1973
            self.overrideAttr(termios, 'TIOCGWINSZ')
 
1974
            del termios.TIOCGWINSZ
 
1975
        del os.environ['BZR_COLUMNS']
 
1976
        del os.environ['COLUMNS']
 
1977
        # Whatever the result is, if we don't raise an exception, it's ok.
 
1978
        osutils.terminal_width()
 
1979
 
 
1980
class TestCreationOps(tests.TestCaseInTempDir):
 
1981
    _test_needs_features = [features.chown_feature]
 
1982
 
 
1983
    def setUp(self):
 
1984
        tests.TestCaseInTempDir.setUp(self)
 
1985
        self.overrideAttr(os, 'chown', self._dummy_chown)
 
1986
 
 
1987
        # params set by call to _dummy_chown
 
1988
        self.path = self.uid = self.gid = None
 
1989
 
 
1990
    def _dummy_chown(self, path, uid, gid):
 
1991
        self.path, self.uid, self.gid = path, uid, gid
 
1992
 
 
1993
    def test_copy_ownership_from_path(self):
 
1994
        """copy_ownership_from_path test with specified src."""
 
1995
        ownsrc = '/'
 
1996
        f = open('test_file', 'wt')
 
1997
        osutils.copy_ownership_from_path('test_file', ownsrc)
 
1998
 
 
1999
        s = os.stat(ownsrc)
 
2000
        self.assertEquals(self.path, 'test_file')
 
2001
        self.assertEquals(self.uid, s.st_uid)
 
2002
        self.assertEquals(self.gid, s.st_gid)
 
2003
 
 
2004
    def test_copy_ownership_nonesrc(self):
 
2005
        """copy_ownership_from_path test with src=None."""
 
2006
        f = open('test_file', 'wt')
 
2007
        # should use parent dir for permissions
 
2008
        osutils.copy_ownership_from_path('test_file')
 
2009
 
 
2010
        s = os.stat('..')
 
2011
        self.assertEquals(self.path, 'test_file')
 
2012
        self.assertEquals(self.uid, s.st_uid)
 
2013
        self.assertEquals(self.gid, s.st_gid)
 
2014
 
 
2015
class TestGetuserUnicode(tests.TestCase):
 
2016
 
 
2017
    def test_ascii_user(self):
 
2018
        osutils.set_or_unset_env('LOGNAME', 'jrandom')
 
2019
        self.assertEqual(u'jrandom', osutils.getuser_unicode())
 
2020
 
 
2021
    def test_unicode_user(self):
 
2022
        ue = osutils.get_user_encoding()
 
2023
        osutils.set_or_unset_env('LOGNAME', u'jrandom\xb6'.encode(ue))
 
2024
        self.assertEqual(u'jrandom\xb6', osutils.getuser_unicode())