~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_osutils.py

  • Committer: John Arbash Meinel
  • Date: 2010-05-11 10:45:26 UTC
  • mto: This revision was merged to the branch mainline in revision 5225.
  • Revision ID: john@arbash-meinel.com-20100511104526-zxnstcxta22hzw2n
Implement a compiled extension for parsing the text key out of a CHKInventory value.

Related to bug #562666. This seems to shave 5-10% out of the time spent doing a complete
branch of bzr.dev/launchpad/etc.

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
    def test_rename_error(self):
 
188
        # We wrap os.rename to make it give an error including the filenames
 
189
        # https://bugs.launchpad.net/bzr/+bug/491763
 
190
        err = self.assertRaises(OSError, osutils.rename,
 
191
            'nonexistent', 'target')
 
192
        self.assertContainsString(str(err), 'nonexistent')
 
193
 
 
194
 
 
195
class TestRandChars(tests.TestCase):
 
196
 
134
197
    def test_01_rand_chars_empty(self):
135
198
        result = osutils.rand_chars(0)
136
199
        self.assertEqual(result, '')
141
204
        self.assertEqual(type(result), str)
142
205
        self.assertContainsRe(result, r'^[a-z0-9]{100}$')
143
206
 
 
207
 
 
208
class TestIsInside(tests.TestCase):
 
209
 
144
210
    def test_is_inside(self):
145
211
        is_inside = osutils.is_inside
146
212
        self.assertTrue(is_inside('src', 'src/foo.c'))
151
217
        self.assertTrue(is_inside('', 'foo.c'))
152
218
 
153
219
    def test_is_inside_any(self):
154
 
        SRC_FOO_C = pathjoin('src', 'foo.c')
 
220
        SRC_FOO_C = osutils.pathjoin('src', 'foo.c')
155
221
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
156
222
                         (['src'], SRC_FOO_C),
157
223
                         (['src'], 'src'),
158
224
                         ]:
159
 
            self.assert_(is_inside_any(dirs, fn))
 
225
            self.assert_(osutils.is_inside_any(dirs, fn))
160
226
        for dirs, fn in [(['src'], 'srccontrol'),
161
227
                         (['src'], 'srccontrol/foo')]:
162
 
            self.assertFalse(is_inside_any(dirs, fn))
 
228
            self.assertFalse(osutils.is_inside_any(dirs, fn))
163
229
 
164
230
    def test_is_inside_or_parent_of_any(self):
165
231
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
168
234
                         (['src/bar.c', 'bla/foo.c'], 'src'),
169
235
                         (['src'], 'src'),
170
236
                         ]:
171
 
            self.assert_(is_inside_or_parent_of_any(dirs, fn))
 
237
            self.assert_(osutils.is_inside_or_parent_of_any(dirs, fn))
172
238
 
173
239
        for dirs, fn in [(['src'], 'srccontrol'),
174
240
                         (['srccontrol/foo.c'], 'src'),
175
241
                         (['src'], 'srccontrol/foo')]:
176
 
            self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
 
242
            self.assertFalse(osutils.is_inside_or_parent_of_any(dirs, fn))
 
243
 
 
244
 
 
245
class TestRmTree(tests.TestCaseInTempDir):
177
246
 
178
247
    def test_rmtree(self):
179
248
        # Check to remove tree with read-only files/dirs
193
262
        self.failIfExists('dir/file')
194
263
        self.failIfExists('dir')
195
264
 
 
265
 
 
266
class TestDeleteAny(tests.TestCaseInTempDir):
 
267
 
 
268
    def test_delete_any_readonly(self):
 
269
        # from <https://bugs.launchpad.net/bzr/+bug/218206>
 
270
        self.build_tree(['d/', 'f'])
 
271
        osutils.make_readonly('d')
 
272
        osutils.make_readonly('f')
 
273
 
 
274
        osutils.delete_any('f')
 
275
        osutils.delete_any('d')
 
276
 
 
277
 
 
278
class TestKind(tests.TestCaseInTempDir):
 
279
 
196
280
    def test_file_kind(self):
197
281
        self.build_tree(['file', 'dir/'])
198
282
        self.assertEquals('file', osutils.file_kind('file'))
228
312
                os.remove('socket')
229
313
 
230
314
    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'), '+')
 
315
        self.assertEqual("", osutils.kind_marker("file"))
 
316
        self.assertEqual("/", osutils.kind_marker('directory'))
 
317
        self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
 
318
        self.assertEqual("@", osutils.kind_marker("symlink"))
 
319
        self.assertEqual("+", osutils.kind_marker("tree-reference"))
 
320
        self.assertEqual("", osutils.kind_marker("fifo"))
 
321
        self.assertEqual("", osutils.kind_marker("socket"))
 
322
        self.assertEqual("", osutils.kind_marker("unknown"))
 
323
 
 
324
 
 
325
class TestUmask(tests.TestCaseInTempDir):
235
326
 
236
327
    def test_get_umask(self):
237
328
        if sys.platform == 'win32':
240
331
            return
241
332
 
242
333
        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)
 
334
        self.addCleanup(os.umask, orig_umask)
 
335
        os.umask(0222)
 
336
        self.assertEqual(0222, osutils.get_umask())
 
337
        os.umask(0022)
 
338
        self.assertEqual(0022, osutils.get_umask())
 
339
        os.umask(0002)
 
340
        self.assertEqual(0002, osutils.get_umask())
 
341
        os.umask(0027)
 
342
        self.assertEqual(0027, osutils.get_umask())
 
343
 
 
344
 
 
345
class TestDateTime(tests.TestCase):
254
346
 
255
347
    def assertFormatedDelta(self, expected, seconds):
256
348
        """Assert osutils.format_delta formats as expected"""
298
390
        # Instead blackbox.test_locale should check for localized
299
391
        # dates once they do occur in output strings.
300
392
 
 
393
    def test_format_date_with_offset_in_original_timezone(self):
 
394
        self.assertEqual("Thu 1970-01-01 00:00:00 +0000",
 
395
            osutils.format_date_with_offset_in_original_timezone(0))
 
396
        self.assertEqual("Fri 1970-01-02 03:46:40 +0000",
 
397
            osutils.format_date_with_offset_in_original_timezone(100000))
 
398
        self.assertEqual("Fri 1970-01-02 05:46:40 +0200",
 
399
            osutils.format_date_with_offset_in_original_timezone(100000, 7200))
 
400
 
 
401
    def test_local_time_offset(self):
 
402
        """Test that local_time_offset() returns a sane value."""
 
403
        offset = osutils.local_time_offset()
 
404
        self.assertTrue(isinstance(offset, int))
 
405
        # Test that the offset is no more than a eighteen hours in
 
406
        # either direction.
 
407
        # Time zone handling is system specific, so it is difficult to
 
408
        # do more specific tests, but a value outside of this range is
 
409
        # probably wrong.
 
410
        eighteen_hours = 18 * 3600
 
411
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
412
 
 
413
    def test_local_time_offset_with_timestamp(self):
 
414
        """Test that local_time_offset() works with a timestamp."""
 
415
        offset = osutils.local_time_offset(1000000000.1234567)
 
416
        self.assertTrue(isinstance(offset, int))
 
417
        eighteen_hours = 18 * 3600
 
418
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
419
 
 
420
 
 
421
class TestLinks(tests.TestCaseInTempDir):
 
422
 
301
423
    def test_dereference_path(self):
302
 
        self.requireFeature(SymlinkFeature)
 
424
        self.requireFeature(tests.SymlinkFeature)
303
425
        cwd = osutils.realpath('.')
304
426
        os.mkdir('bar')
305
427
        bar_path = osutils.pathjoin(cwd, 'bar')
346
468
            osutils.make_readonly('dangling')
347
469
            osutils.make_writable('dangling')
348
470
 
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
471
    def test_host_os_dereferences_symlinks(self):
356
472
        osutils.host_os_dereferences_symlinks()
357
473
 
358
474
 
359
 
class TestCanonicalRelPath(TestCaseInTempDir):
 
475
class TestCanonicalRelPath(tests.TestCaseInTempDir):
360
476
 
361
 
    _test_needs_features = [CaseInsCasePresFilenameFeature]
 
477
    _test_needs_features = [tests.CaseInsCasePresFilenameFeature]
362
478
 
363
479
    def test_canonical_relpath_simple(self):
364
480
        f = file('MixedCaseName', 'w')
365
481
        f.close()
366
 
        self.failUnlessEqual(
367
 
            canonical_relpath(self.test_base_dir, 'mixedcasename'),
368
 
            'work/MixedCaseName')
 
482
        actual = osutils.canonical_relpath(self.test_base_dir, 'mixedcasename')
 
483
        self.failUnlessEqual('work/MixedCaseName', actual)
369
484
 
370
485
    def test_canonical_relpath_missing_tail(self):
371
486
        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):
 
487
        actual = osutils.canonical_relpath(self.test_base_dir,
 
488
                                           'mixedcaseparent/nochild')
 
489
        self.failUnlessEqual('work/MixedCaseParent/nochild', actual)
 
490
 
 
491
 
 
492
class Test_CICPCanonicalRelpath(tests.TestCaseWithTransport):
 
493
 
 
494
    def assertRelpath(self, expected, base, path):
 
495
        actual = osutils._cicp_canonical_relpath(base, path)
 
496
        self.assertEqual(expected, actual)
 
497
 
 
498
    def test_simple(self):
 
499
        self.build_tree(['MixedCaseName'])
 
500
        base = osutils.realpath(self.get_transport('.').local_abspath('.'))
 
501
        self.assertRelpath('MixedCaseName', base, 'mixedcAsename')
 
502
 
 
503
    def test_subdir_missing_tail(self):
 
504
        self.build_tree(['MixedCaseParent/', 'MixedCaseParent/a_child'])
 
505
        base = osutils.realpath(self.get_transport('.').local_abspath('.'))
 
506
        self.assertRelpath('MixedCaseParent/a_child', base,
 
507
                           'MixedCaseParent/a_child')
 
508
        self.assertRelpath('MixedCaseParent/a_child', base,
 
509
                           'MixedCaseParent/A_Child')
 
510
        self.assertRelpath('MixedCaseParent/not_child', base,
 
511
                           'MixedCaseParent/not_child')
 
512
 
 
513
    def test_at_root_slash(self):
 
514
        # We can't test this on Windows, because it has a 'MIN_ABS_PATHLENGTH'
 
515
        # check...
 
516
        if osutils.MIN_ABS_PATHLENGTH > 1:
 
517
            raise tests.TestSkipped('relpath requires %d chars'
 
518
                                    % osutils.MIN_ABS_PATHLENGTH)
 
519
        self.assertRelpath('foo', '/', '/foo')
 
520
 
 
521
    def test_at_root_drive(self):
 
522
        if sys.platform != 'win32':
 
523
            raise tests.TestNotApplicable('we can only test drive-letter relative'
 
524
                                          ' paths on Windows where we have drive'
 
525
                                          ' letters.')
 
526
        # see bug #322807
 
527
        # The specific issue is that when at the root of a drive, 'abspath'
 
528
        # returns "C:/" or just "/". However, the code assumes that abspath
 
529
        # always returns something like "C:/foo" or "/foo" (no trailing slash).
 
530
        self.assertRelpath('foo', 'C:/', 'C:/foo')
 
531
        self.assertRelpath('foo', 'X:/', 'X:/foo')
 
532
        self.assertRelpath('foo', 'X:/', 'X://foo')
 
533
 
 
534
 
 
535
class TestPumpFile(tests.TestCase):
378
536
    """Test pumpfile method."""
 
537
 
379
538
    def setUp(self):
380
 
        TestCase.setUp(self)
 
539
        tests.TestCase.setUp(self)
381
540
        # create a test datablock
382
541
        self.block_size = 512
383
542
        pattern = '0123456789ABCDEF'
390
549
        # make sure test data is larger than max read size
391
550
        self.assertTrue(self.test_data_len > self.block_size)
392
551
 
393
 
        from_file = FakeReadFile(self.test_data)
 
552
        from_file = file_utils.FakeReadFile(self.test_data)
394
553
        to_file = StringIO()
395
554
 
396
555
        # read (max / 2) bytes and verify read size wasn't affected
397
556
        num_bytes_to_read = self.block_size / 2
398
 
        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)
399
558
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
400
559
        self.assertEqual(from_file.get_read_count(), 1)
401
560
 
402
561
        # read (max) bytes and verify read size wasn't affected
403
562
        num_bytes_to_read = self.block_size
404
563
        from_file.reset_read_count()
405
 
        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)
406
565
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
407
566
        self.assertEqual(from_file.get_read_count(), 1)
408
567
 
409
568
        # read (max + 1) bytes and verify read size was limited
410
569
        num_bytes_to_read = self.block_size + 1
411
570
        from_file.reset_read_count()
412
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
571
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
413
572
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
414
573
        self.assertEqual(from_file.get_read_count(), 2)
415
574
 
416
575
        # finish reading the rest of the data
417
576
        num_bytes_to_read = self.test_data_len - to_file.tell()
418
 
        pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
577
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
419
578
 
420
579
        # report error if the data wasn't equal (we only report the size due
421
580
        # to the length of the data)
431
590
        self.assertTrue(self.test_data_len > self.block_size)
432
591
 
433
592
        # retrieve data in blocks
434
 
        from_file = FakeReadFile(self.test_data)
 
593
        from_file = file_utils.FakeReadFile(self.test_data)
435
594
        to_file = StringIO()
436
 
        pumpfile(from_file, to_file, self.test_data_len, self.block_size)
 
595
        osutils.pumpfile(from_file, to_file, self.test_data_len,
 
596
                         self.block_size)
437
597
 
438
598
        # verify read size was equal to the maximum read size
439
599
        self.assertTrue(from_file.get_max_read_size() > 0)
454
614
        self.assertTrue(self.test_data_len > self.block_size)
455
615
 
456
616
        # retrieve data to EOF
457
 
        from_file = FakeReadFile(self.test_data)
 
617
        from_file = file_utils.FakeReadFile(self.test_data)
458
618
        to_file = StringIO()
459
 
        pumpfile(from_file, to_file, -1, self.block_size)
 
619
        osutils.pumpfile(from_file, to_file, -1, self.block_size)
460
620
 
461
621
        # verify read size was equal to the maximum read size
462
622
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
474
634
        test verifies that any existing usages of pumpfile will not be broken
475
635
        with this new version."""
476
636
        # retrieve data using default (old) pumpfile method
477
 
        from_file = FakeReadFile(self.test_data)
 
637
        from_file = file_utils.FakeReadFile(self.test_data)
478
638
        to_file = StringIO()
479
 
        pumpfile(from_file, to_file)
 
639
        osutils.pumpfile(from_file, to_file)
480
640
 
481
641
        # report error if the data wasn't equal (we only report the size due
482
642
        # to the length of the data)
491
651
            activity.append((length, direction))
492
652
        from_file = StringIO(self.test_data)
493
653
        to_file = StringIO()
494
 
        pumpfile(from_file, to_file, buff_size=500,
495
 
                 report_activity=log_activity, direction='read')
 
654
        osutils.pumpfile(from_file, to_file, buff_size=500,
 
655
                         report_activity=log_activity, direction='read')
496
656
        self.assertEqual([(500, 'read'), (500, 'read'), (500, 'read'),
497
657
                          (36, 'read')], activity)
498
658
 
499
659
        from_file = StringIO(self.test_data)
500
660
        to_file = StringIO()
501
661
        del activity[:]
502
 
        pumpfile(from_file, to_file, buff_size=500,
503
 
                 report_activity=log_activity, direction='write')
 
662
        osutils.pumpfile(from_file, to_file, buff_size=500,
 
663
                         report_activity=log_activity, direction='write')
504
664
        self.assertEqual([(500, 'write'), (500, 'write'), (500, 'write'),
505
665
                          (36, 'write')], activity)
506
666
 
508
668
        from_file = StringIO(self.test_data)
509
669
        to_file = StringIO()
510
670
        del activity[:]
511
 
        pumpfile(from_file, to_file, buff_size=500, read_length=1028,
512
 
                 report_activity=log_activity, direction='read')
 
671
        osutils.pumpfile(from_file, to_file, buff_size=500, read_length=1028,
 
672
                         report_activity=log_activity, direction='read')
513
673
        self.assertEqual([(500, 'read'), (500, 'read'), (28, 'read')], activity)
514
674
 
515
675
 
516
676
 
517
 
class TestPumpStringFile(TestCase):
 
677
class TestPumpStringFile(tests.TestCase):
518
678
 
519
679
    def test_empty(self):
520
680
        output = StringIO()
521
 
        pump_string_file("", output)
 
681
        osutils.pump_string_file("", output)
522
682
        self.assertEqual("", output.getvalue())
523
683
 
524
684
    def test_more_than_segment_size(self):
525
685
        output = StringIO()
526
 
        pump_string_file("123456789", output, 2)
 
686
        osutils.pump_string_file("123456789", output, 2)
527
687
        self.assertEqual("123456789", output.getvalue())
528
688
 
529
689
    def test_segment_size(self):
530
690
        output = StringIO()
531
 
        pump_string_file("12", output, 2)
 
691
        osutils.pump_string_file("12", output, 2)
532
692
        self.assertEqual("12", output.getvalue())
533
693
 
534
694
    def test_segment_size_multiple(self):
535
695
        output = StringIO()
536
 
        pump_string_file("1234", output, 2)
 
696
        osutils.pump_string_file("1234", output, 2)
537
697
        self.assertEqual("1234", output.getvalue())
538
698
 
539
699
 
540
 
class TestSafeUnicode(TestCase):
 
700
class TestRelpath(tests.TestCase):
 
701
 
 
702
    def test_simple_relpath(self):
 
703
        cwd = osutils.getcwd()
 
704
        subdir = cwd + '/subdir'
 
705
        self.assertEqual('subdir', osutils.relpath(cwd, subdir))
 
706
 
 
707
    def test_deep_relpath(self):
 
708
        cwd = osutils.getcwd()
 
709
        subdir = cwd + '/sub/subsubdir'
 
710
        self.assertEqual('sub/subsubdir', osutils.relpath(cwd, subdir))
 
711
 
 
712
    def test_not_relative(self):
 
713
        self.assertRaises(errors.PathNotChild,
 
714
                          osutils.relpath, 'C:/path', 'H:/path')
 
715
        self.assertRaises(errors.PathNotChild,
 
716
                          osutils.relpath, 'C:/', 'H:/path')
 
717
 
 
718
 
 
719
class TestSafeUnicode(tests.TestCase):
541
720
 
542
721
    def test_from_ascii_string(self):
543
722
        self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
552
731
        self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
553
732
 
554
733
    def test_bad_utf8_string(self):
555
 
        self.assertRaises(BzrBadParameterNotUnicode,
 
734
        self.assertRaises(errors.BzrBadParameterNotUnicode,
556
735
                          osutils.safe_unicode,
557
736
                          '\xbb\xbb')
558
737
 
559
738
 
560
 
class TestSafeUtf8(TestCase):
 
739
class TestSafeUtf8(tests.TestCase):
561
740
 
562
741
    def test_from_ascii_string(self):
563
742
        f = 'foobar'
573
752
        self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
574
753
 
575
754
    def test_bad_utf8_string(self):
576
 
        self.assertRaises(BzrBadParameterNotUnicode,
 
755
        self.assertRaises(errors.BzrBadParameterNotUnicode,
577
756
                          osutils.safe_utf8, '\xbb\xbb')
578
757
 
579
758
 
580
 
class TestSafeRevisionId(TestCase):
 
759
class TestSafeRevisionId(tests.TestCase):
581
760
 
582
761
    def test_from_ascii_string(self):
583
762
        # this shouldn't give a warning because it's getting an ascii string
605
784
        self.assertEqual(None, osutils.safe_revision_id(None))
606
785
 
607
786
 
608
 
class TestSafeFileId(TestCase):
 
787
class TestSafeFileId(tests.TestCase):
609
788
 
610
789
    def test_from_ascii_string(self):
611
790
        self.assertEqual('foobar', osutils.safe_file_id('foobar'))
631
810
        self.assertEqual(None, osutils.safe_file_id(None))
632
811
 
633
812
 
634
 
class TestWin32Funcs(TestCase):
635
 
    """Test that the _win32 versions of os utilities return appropriate paths."""
 
813
class TestWin32Funcs(tests.TestCase):
 
814
    """Test that _win32 versions of os utilities return appropriate paths."""
636
815
 
637
816
    def test_abspath(self):
638
817
        self.assertEqual('C:/foo', osutils._win32_abspath('C:\\foo'))
645
824
        self.assertEqual('C:/foo', osutils._win32_realpath('C:/foo'))
646
825
 
647
826
    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'))
 
827
        self.assertEqual('path/to/foo',
 
828
                         osutils._win32_pathjoin('path', 'to', 'foo'))
 
829
        self.assertEqual('C:/foo',
 
830
                         osutils._win32_pathjoin('path\\to', 'C:\\foo'))
 
831
        self.assertEqual('C:/foo',
 
832
                         osutils._win32_pathjoin('path/to', 'C:/foo'))
 
833
        self.assertEqual('path/to/foo',
 
834
                         osutils._win32_pathjoin('path/to/', 'foo'))
 
835
        self.assertEqual('/foo',
 
836
                         osutils._win32_pathjoin('C:/path/to/', '/foo'))
 
837
        self.assertEqual('/foo',
 
838
                         osutils._win32_pathjoin('C:\\path\\to\\', '\\foo'))
654
839
 
655
840
    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'))
 
841
        self.assertEqual('path/to/foo',
 
842
                         osutils._win32_normpath(r'path\\from\..\to\.\foo'))
 
843
        self.assertEqual('path/to/foo',
 
844
                         osutils._win32_normpath('path//from/../to/./foo'))
658
845
 
659
846
    def test_getcwd(self):
660
847
        cwd = osutils._win32_getcwd()
689
876
        self.assertEqual(cwd+'/'+u, osutils._win98_abspath(u))
690
877
 
691
878
 
692
 
class TestWin32FuncsDirs(TestCaseInTempDir):
 
879
class TestWin32FuncsDirs(tests.TestCaseInTempDir):
693
880
    """Test win32 functions that create files."""
694
881
 
695
882
    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
 
 
 
883
        self.requireFeature(tests.UnicodeFilenameFeature)
 
884
        os.mkdir(u'mu-\xb5')
704
885
        os.chdir(u'mu-\xb5')
705
886
        # TODO: jam 20060427 This will probably fail on Mac OSX because
706
887
        #       it will change the normalization of B\xe5gfors
711
892
    def test_minimum_path_selection(self):
712
893
        self.assertEqual(set(),
713
894
            osutils.minimum_path_selection([]))
 
895
        self.assertEqual(set(['a']),
 
896
            osutils.minimum_path_selection(['a']))
714
897
        self.assertEqual(set(['a', 'b']),
715
898
            osutils.minimum_path_selection(['a', 'b']))
716
899
        self.assertEqual(set(['a/', 'b']),
717
900
            osutils.minimum_path_selection(['a/', 'b']))
718
901
        self.assertEqual(set(['a/', 'b']),
719
902
            osutils.minimum_path_selection(['a/c', 'a/', 'b']))
 
903
        self.assertEqual(set(['a-b', 'a', 'a0b']),
 
904
            osutils.minimum_path_selection(['a-b', 'a/b', 'a0b', 'a']))
720
905
 
721
906
    def test_mkdtemp(self):
722
907
        tmpdir = osutils._win32_mkdtemp(dir='.')
778
963
        self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
779
964
 
780
965
 
781
 
class TestMacFuncsDirs(TestCaseInTempDir):
 
966
class TestParentDirectories(tests.TestCaseInTempDir):
 
967
    """Test osutils.parent_directories()"""
 
968
 
 
969
    def test_parent_directories(self):
 
970
        self.assertEqual([], osutils.parent_directories('a'))
 
971
        self.assertEqual(['a'], osutils.parent_directories('a/b'))
 
972
        self.assertEqual(['a/b', 'a'], osutils.parent_directories('a/b/c'))
 
973
 
 
974
 
 
975
class TestMacFuncsDirs(tests.TestCaseInTempDir):
782
976
    """Test mac special functions that require directories."""
783
977
 
784
978
    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
 
 
 
979
        self.requireFeature(tests.UnicodeFilenameFeature)
 
980
        os.mkdir(u'B\xe5gfors')
792
981
        os.chdir(u'B\xe5gfors')
793
982
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
794
983
 
795
984
    def test_getcwd_nonnorm(self):
 
985
        self.requireFeature(tests.UnicodeFilenameFeature)
796
986
        # 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
 
 
 
987
        os.mkdir(u'Ba\u030agfors')
802
988
        os.chdir(u'Ba\u030agfors')
803
989
        self.assertEndsWith(osutils._mac_getcwd(), u'B\xe5gfors')
804
990
 
805
991
 
806
 
class TestChunksToLines(TestCase):
 
992
class TestChunksToLines(tests.TestCase):
807
993
 
808
994
    def test_smoketest(self):
809
995
        self.assertEqual(['foo\n', 'bar\n', 'baz\n'],
813
999
 
814
1000
    def test_osutils_binding(self):
815
1001
        from bzrlib.tests import test__chunks_to_lines
816
 
        if test__chunks_to_lines.CompiledChunksToLinesFeature.available():
 
1002
        if test__chunks_to_lines.compiled_chunkstolines_feature.available():
817
1003
            from bzrlib._chunks_to_lines_pyx import chunks_to_lines
818
1004
        else:
819
1005
            from bzrlib._chunks_to_lines_py import chunks_to_lines
820
1006
        self.assertIs(chunks_to_lines, osutils.chunks_to_lines)
821
1007
 
822
1008
 
823
 
class TestSplitLines(TestCase):
 
1009
class TestSplitLines(tests.TestCase):
824
1010
 
825
1011
    def test_split_unicode(self):
826
1012
        self.assertEqual([u'foo\n', u'bar\xae'],
833
1019
                         osutils.split_lines('foo\rbar\n'))
834
1020
 
835
1021
 
836
 
class TestWalkDirs(TestCaseInTempDir):
 
1022
class TestWalkDirs(tests.TestCaseInTempDir):
 
1023
 
 
1024
    def assertExpectedBlocks(self, expected, result):
 
1025
        self.assertEqual(expected,
 
1026
                         [(dirinfo, [line[0:3] for line in block])
 
1027
                          for dirinfo, block in result])
837
1028
 
838
1029
    def test_walkdirs(self):
839
1030
        tree = [
872
1063
            result.append((dirdetail, dirblock))
873
1064
 
874
1065
        self.assertTrue(found_bzrdir)
875
 
        self.assertEqual(expected_dirblocks,
876
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1066
        self.assertExpectedBlocks(expected_dirblocks, result)
877
1067
        # you can search a subdir only, with a supplied prefix.
878
1068
        result = []
879
1069
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
880
1070
            result.append(dirblock)
881
 
        self.assertEqual(expected_dirblocks[1:],
882
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1071
        self.assertExpectedBlocks(expected_dirblocks[1:], result)
883
1072
 
884
1073
    def test_walkdirs_os_error(self):
885
1074
        # <https://bugs.edge.launchpad.net/bzr/+bug/338653>
891
1080
        os.mkdir("test-unreadable")
892
1081
        os.chmod("test-unreadable", 0000)
893
1082
        # must chmod it back so that it can be removed
894
 
        self.addCleanup(lambda: os.chmod("test-unreadable", 0700))
 
1083
        self.addCleanup(os.chmod, "test-unreadable", 0700)
895
1084
        # The error is not raised until the generator is actually evaluated.
896
1085
        # (It would be ok if it happened earlier but at the moment it
897
1086
        # doesn't.)
938
1127
            result.append((dirdetail, dirblock))
939
1128
 
940
1129
        self.assertTrue(found_bzrdir)
941
 
        self.assertEqual(expected_dirblocks,
942
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1130
        self.assertExpectedBlocks(expected_dirblocks, result)
 
1131
 
943
1132
        # you can search a subdir only, with a supplied prefix.
944
1133
        result = []
945
1134
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
946
1135
            result.append(dirblock)
947
 
        self.assertEqual(expected_dirblocks[1:],
948
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1136
        self.assertExpectedBlocks(expected_dirblocks[1:], result)
949
1137
 
950
1138
    def _filter_out_stat(self, result):
951
1139
        """Filter out the stat value from the walkdirs result"""
957
1145
            dirblock[:] = new_dirblock
958
1146
 
959
1147
    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)
 
1148
        self.overrideAttr(win32utils, 'winver')
 
1149
        self.overrideAttr(osutils, '_fs_enc')
 
1150
        self.overrideAttr(osutils, '_selected_dir_reader')
968
1151
 
969
 
    def assertReadFSDirIs(self, expected):
 
1152
    def assertDirReaderIs(self, expected):
970
1153
        """Assert the right implementation for _walkdirs_utf8 is chosen."""
971
1154
        # Force it to redetect
972
1155
        osutils._selected_dir_reader = None
979
1162
        self._save_platform_info()
980
1163
        win32utils.winver = None # Avoid the win32 detection code
981
1164
        osutils._fs_enc = 'UTF-8'
982
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1165
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
983
1166
 
984
1167
    def test_force_walkdirs_utf8_fs_ascii(self):
985
1168
        self.requireFeature(UTF8DirReaderFeature)
986
1169
        self._save_platform_info()
987
1170
        win32utils.winver = None # Avoid the win32 detection code
988
1171
        osutils._fs_enc = 'US-ASCII'
989
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1172
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
990
1173
 
991
1174
    def test_force_walkdirs_utf8_fs_ANSI(self):
992
1175
        self.requireFeature(UTF8DirReaderFeature)
993
1176
        self._save_platform_info()
994
1177
        win32utils.winver = None # Avoid the win32 detection code
995
1178
        osutils._fs_enc = 'ANSI_X3.4-1968'
996
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1179
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
997
1180
 
998
1181
    def test_force_walkdirs_utf8_fs_latin1(self):
999
1182
        self._save_platform_info()
1000
1183
        win32utils.winver = None # Avoid the win32 detection code
1001
1184
        osutils._fs_enc = 'latin1'
1002
 
        self.assertReadFSDirIs(osutils.UnicodeDirReader)
 
1185
        self.assertDirReaderIs(osutils.UnicodeDirReader)
1003
1186
 
1004
1187
    def test_force_walkdirs_utf8_nt(self):
1005
1188
        # Disabled because the thunk of the whole walkdirs api is disabled.
1006
 
        self.requireFeature(Win32ReadDirFeature)
 
1189
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1007
1190
        self._save_platform_info()
1008
1191
        win32utils.winver = 'Windows NT'
1009
1192
        from bzrlib._walkdirs_win32 import Win32ReadDir
1010
 
        self.assertReadFSDirIs(Win32ReadDir)
 
1193
        self.assertDirReaderIs(Win32ReadDir)
1011
1194
 
1012
1195
    def test_force_walkdirs_utf8_98(self):
1013
 
        self.requireFeature(Win32ReadDirFeature)
 
1196
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1014
1197
        self._save_platform_info()
1015
1198
        win32utils.winver = 'Windows 98'
1016
 
        self.assertReadFSDirIs(osutils.UnicodeDirReader)
 
1199
        self.assertDirReaderIs(osutils.UnicodeDirReader)
1017
1200
 
1018
1201
    def test_unicode_walkdirs(self):
1019
1202
        """Walkdirs should always return unicode paths."""
 
1203
        self.requireFeature(tests.UnicodeFilenameFeature)
1020
1204
        name0 = u'0file-\xb6'
1021
1205
        name1 = u'1dir-\u062c\u0648'
1022
1206
        name2 = u'2file-\u0633'
1027
1211
            name1 + '/' + name1 + '/',
1028
1212
            name2,
1029
1213
            ]
1030
 
        try:
1031
 
            self.build_tree(tree)
1032
 
        except UnicodeError:
1033
 
            raise TestSkipped('Could not represent Unicode chars'
1034
 
                              ' in current encoding.')
 
1214
        self.build_tree(tree)
1035
1215
        expected_dirblocks = [
1036
1216
                ((u'', u'.'),
1037
1217
                 [(name0, name0, 'file', './' + name0),
1063
1243
 
1064
1244
        The abspath portion might be in unicode or utf-8
1065
1245
        """
 
1246
        self.requireFeature(tests.UnicodeFilenameFeature)
1066
1247
        name0 = u'0file-\xb6'
1067
1248
        name1 = u'1dir-\u062c\u0648'
1068
1249
        name2 = u'2file-\u0633'
1073
1254
            name1 + '/' + name1 + '/',
1074
1255
            name2,
1075
1256
            ]
1076
 
        try:
1077
 
            self.build_tree(tree)
1078
 
        except UnicodeError:
1079
 
            raise TestSkipped('Could not represent Unicode chars'
1080
 
                              ' in current encoding.')
 
1257
        self.build_tree(tree)
1081
1258
        name0 = name0.encode('utf8')
1082
1259
        name1 = name1.encode('utf8')
1083
1260
        name2 = name2.encode('utf8')
1127
1304
 
1128
1305
        The abspath portion should be in unicode
1129
1306
        """
 
1307
        self.requireFeature(tests.UnicodeFilenameFeature)
1130
1308
        # Use the unicode reader. TODO: split into driver-and-driven unit
1131
1309
        # tests.
1132
1310
        self._save_platform_info()
1141
1319
            name1u + '/' + name1u + '/',
1142
1320
            name2u,
1143
1321
            ]
1144
 
        try:
1145
 
            self.build_tree(tree)
1146
 
        except UnicodeError:
1147
 
            raise TestSkipped('Could not represent Unicode chars'
1148
 
                              ' in current encoding.')
 
1322
        self.build_tree(tree)
1149
1323
        name0 = name0u.encode('utf8')
1150
1324
        name1 = name1u.encode('utf8')
1151
1325
        name2 = name2u.encode('utf8')
1176
1350
        self.assertEqual(expected_dirblocks, result)
1177
1351
 
1178
1352
    def test__walkdirs_utf8_win32readdir(self):
1179
 
        self.requireFeature(Win32ReadDirFeature)
 
1353
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1180
1354
        self.requireFeature(tests.UnicodeFilenameFeature)
1181
1355
        from bzrlib._walkdirs_win32 import Win32ReadDir
1182
1356
        self._save_platform_info()
1233
1407
 
1234
1408
    def test__walkdirs_utf_win32_find_file_stat_file(self):
1235
1409
        """make sure our Stat values are valid"""
1236
 
        self.requireFeature(Win32ReadDirFeature)
 
1410
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1237
1411
        self.requireFeature(tests.UnicodeFilenameFeature)
1238
1412
        from bzrlib._walkdirs_win32 import Win32ReadDir
1239
1413
        name0u = u'0file-\xb6'
1257
1431
 
1258
1432
    def test__walkdirs_utf_win32_find_file_stat_directory(self):
1259
1433
        """make sure our Stat values are valid"""
1260
 
        self.requireFeature(Win32ReadDirFeature)
 
1434
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1261
1435
        self.requireFeature(tests.UnicodeFilenameFeature)
1262
1436
        from bzrlib._walkdirs_win32 import Win32ReadDir
1263
1437
        name0u = u'0dir-\u062c\u0648'
1348
1522
            sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
1349
1523
 
1350
1524
 
1351
 
class TestCopyTree(TestCaseInTempDir):
 
1525
class TestCopyTree(tests.TestCaseInTempDir):
1352
1526
 
1353
1527
    def test_copy_basic_tree(self):
1354
1528
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
1364
1538
        self.assertEqual(['c'], os.listdir('target/b'))
1365
1539
 
1366
1540
    def test_copy_tree_symlinks(self):
1367
 
        self.requireFeature(SymlinkFeature)
 
1541
        self.requireFeature(tests.SymlinkFeature)
1368
1542
        self.build_tree(['source/'])
1369
1543
        os.symlink('a/generic/path', 'source/lnk')
1370
1544
        osutils.copy_tree('source', 'target')
1400
1574
            self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
1401
1575
 
1402
1576
 
1403
 
#class TestTerminalEncoding has been moved to test_osutils_encodings.py
1404
 
# [bialix] 2006/12/26
1405
 
 
1406
 
 
1407
 
class TestSetUnsetEnv(TestCase):
 
1577
class TestSetUnsetEnv(tests.TestCase):
1408
1578
    """Test updating the environment"""
1409
1579
 
1410
1580
    def setUp(self):
1416
1586
        def cleanup():
1417
1587
            if 'BZR_TEST_ENV_VAR' in os.environ:
1418
1588
                del os.environ['BZR_TEST_ENV_VAR']
1419
 
 
1420
1589
        self.addCleanup(cleanup)
1421
1590
 
1422
1591
    def test_set(self):
1437
1606
 
1438
1607
        So Unicode strings must be encoded.
1439
1608
        """
1440
 
        uni_val, env_val = probe_unicode_in_user_encoding()
 
1609
        uni_val, env_val = tests.probe_unicode_in_user_encoding()
1441
1610
        if uni_val is None:
1442
 
            raise TestSkipped('Cannot find a unicode character that works in'
1443
 
                              ' encoding %s' % (osutils.get_user_encoding(),))
 
1611
            raise tests.TestSkipped(
 
1612
                'Cannot find a unicode character that works in encoding %s'
 
1613
                % (osutils.get_user_encoding(),))
1444
1614
 
1445
1615
        old = osutils.set_or_unset_env('BZR_TEST_ENV_VAR', uni_val)
1446
1616
        self.assertEqual(env_val, os.environ.get('BZR_TEST_ENV_VAR'))
1454
1624
        self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1455
1625
 
1456
1626
 
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):
 
1627
class TestSizeShaFile(tests.TestCaseInTempDir):
1480
1628
 
1481
1629
    def test_sha_empty(self):
1482
1630
        self.build_tree_contents([('foo', '')])
1491
1639
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
1492
1640
        self.build_tree_contents([('foo', text)])
1493
1641
        expected_sha = osutils.sha_string(text)
1494
 
        f = open('foo')
 
1642
        f = open('foo', 'rb')
1495
1643
        self.addCleanup(f.close)
1496
1644
        size, sha = osutils.size_sha_file(f)
1497
1645
        self.assertEqual(38, size)
1498
1646
        self.assertEqual(expected_sha, sha)
1499
1647
 
1500
1648
 
1501
 
class TestShaFileByName(TestCaseInTempDir):
 
1649
class TestShaFileByName(tests.TestCaseInTempDir):
1502
1650
 
1503
1651
    def test_sha_empty(self):
1504
1652
        self.build_tree_contents([('foo', '')])
1512
1660
        self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1513
1661
 
1514
1662
 
1515
 
class TestResourceLoading(TestCaseInTempDir):
 
1663
class TestResourceLoading(tests.TestCaseInTempDir):
1516
1664
 
1517
1665
    def test_resource_string(self):
1518
1666
        # test resource in bzrlib
1528
1676
        self.assertRaises(IOError, osutils.resource_string, 'bzrlib', 'yyy.xx')
1529
1677
 
1530
1678
 
1531
 
class TestReCompile(TestCase):
 
1679
class TestReCompile(tests.TestCase):
1532
1680
 
1533
1681
    def test_re_compile_checked(self):
1534
1682
        r = osutils.re_compile_checked(r'A*', re.IGNORECASE)
1544
1692
            "Invalid regular expression in test case: '*': "
1545
1693
            "nothing to repeat",
1546
1694
            str(err))
 
1695
 
 
1696
 
 
1697
class TestDirReader(tests.TestCaseInTempDir):
 
1698
 
 
1699
    # Set by load_tests
 
1700
    _dir_reader_class = None
 
1701
    _native_to_unicode = None
 
1702
 
 
1703
    def setUp(self):
 
1704
        tests.TestCaseInTempDir.setUp(self)
 
1705
        self.overrideAttr(osutils,
 
1706
                          '_selected_dir_reader', self._dir_reader_class())
 
1707
 
 
1708
    def _get_ascii_tree(self):
 
1709
        tree = [
 
1710
            '0file',
 
1711
            '1dir/',
 
1712
            '1dir/0file',
 
1713
            '1dir/1dir/',
 
1714
            '2file'
 
1715
            ]
 
1716
        expected_dirblocks = [
 
1717
                (('', '.'),
 
1718
                 [('0file', '0file', 'file'),
 
1719
                  ('1dir', '1dir', 'directory'),
 
1720
                  ('2file', '2file', 'file'),
 
1721
                 ]
 
1722
                ),
 
1723
                (('1dir', './1dir'),
 
1724
                 [('1dir/0file', '0file', 'file'),
 
1725
                  ('1dir/1dir', '1dir', 'directory'),
 
1726
                 ]
 
1727
                ),
 
1728
                (('1dir/1dir', './1dir/1dir'),
 
1729
                 [
 
1730
                 ]
 
1731
                ),
 
1732
            ]
 
1733
        return tree, expected_dirblocks
 
1734
 
 
1735
    def test_walk_cur_dir(self):
 
1736
        tree, expected_dirblocks = self._get_ascii_tree()
 
1737
        self.build_tree(tree)
 
1738
        result = list(osutils._walkdirs_utf8('.'))
 
1739
        # Filter out stat and abspath
 
1740
        self.assertEqual(expected_dirblocks,
 
1741
                         [(dirinfo, [line[0:3] for line in block])
 
1742
                          for dirinfo, block in result])
 
1743
 
 
1744
    def test_walk_sub_dir(self):
 
1745
        tree, expected_dirblocks = self._get_ascii_tree()
 
1746
        self.build_tree(tree)
 
1747
        # you can search a subdir only, with a supplied prefix.
 
1748
        result = list(osutils._walkdirs_utf8('./1dir', '1dir'))
 
1749
        # Filter out stat and abspath
 
1750
        self.assertEqual(expected_dirblocks[1:],
 
1751
                         [(dirinfo, [line[0:3] for line in block])
 
1752
                          for dirinfo, block in result])
 
1753
 
 
1754
    def _get_unicode_tree(self):
 
1755
        name0u = u'0file-\xb6'
 
1756
        name1u = u'1dir-\u062c\u0648'
 
1757
        name2u = u'2file-\u0633'
 
1758
        tree = [
 
1759
            name0u,
 
1760
            name1u + '/',
 
1761
            name1u + '/' + name0u,
 
1762
            name1u + '/' + name1u + '/',
 
1763
            name2u,
 
1764
            ]
 
1765
        name0 = name0u.encode('UTF-8')
 
1766
        name1 = name1u.encode('UTF-8')
 
1767
        name2 = name2u.encode('UTF-8')
 
1768
        expected_dirblocks = [
 
1769
                (('', '.'),
 
1770
                 [(name0, name0, 'file', './' + name0u),
 
1771
                  (name1, name1, 'directory', './' + name1u),
 
1772
                  (name2, name2, 'file', './' + name2u),
 
1773
                 ]
 
1774
                ),
 
1775
                ((name1, './' + name1u),
 
1776
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
 
1777
                                                        + '/' + name0u),
 
1778
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
 
1779
                                                            + '/' + name1u),
 
1780
                 ]
 
1781
                ),
 
1782
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
 
1783
                 [
 
1784
                 ]
 
1785
                ),
 
1786
            ]
 
1787
        return tree, expected_dirblocks
 
1788
 
 
1789
    def _filter_out(self, raw_dirblocks):
 
1790
        """Filter out a walkdirs_utf8 result.
 
1791
 
 
1792
        stat field is removed, all native paths are converted to unicode
 
1793
        """
 
1794
        filtered_dirblocks = []
 
1795
        for dirinfo, block in raw_dirblocks:
 
1796
            dirinfo = (dirinfo[0], self._native_to_unicode(dirinfo[1]))
 
1797
            details = []
 
1798
            for line in block:
 
1799
                details.append(line[0:3] + (self._native_to_unicode(line[4]), ))
 
1800
            filtered_dirblocks.append((dirinfo, details))
 
1801
        return filtered_dirblocks
 
1802
 
 
1803
    def test_walk_unicode_tree(self):
 
1804
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1805
        tree, expected_dirblocks = self._get_unicode_tree()
 
1806
        self.build_tree(tree)
 
1807
        result = list(osutils._walkdirs_utf8('.'))
 
1808
        self.assertEqual(expected_dirblocks, self._filter_out(result))
 
1809
 
 
1810
    def test_symlink(self):
 
1811
        self.requireFeature(tests.SymlinkFeature)
 
1812
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1813
        target = u'target\N{Euro Sign}'
 
1814
        link_name = u'l\N{Euro Sign}nk'
 
1815
        os.symlink(target, link_name)
 
1816
        target_utf8 = target.encode('UTF-8')
 
1817
        link_name_utf8 = link_name.encode('UTF-8')
 
1818
        expected_dirblocks = [
 
1819
                (('', '.'),
 
1820
                 [(link_name_utf8, link_name_utf8,
 
1821
                   'symlink', './' + link_name),],
 
1822
                 )]
 
1823
        result = list(osutils._walkdirs_utf8('.'))
 
1824
        self.assertEqual(expected_dirblocks, self._filter_out(result))
 
1825
 
 
1826
 
 
1827
class TestReadLink(tests.TestCaseInTempDir):
 
1828
    """Exposes os.readlink() problems and the osutils solution.
 
1829
 
 
1830
    The only guarantee offered by os.readlink(), starting with 2.6, is that a
 
1831
    unicode string will be returned if a unicode string is passed.
 
1832
 
 
1833
    But prior python versions failed to properly encode the passed unicode
 
1834
    string.
 
1835
    """
 
1836
    _test_needs_features = [tests.SymlinkFeature, tests.UnicodeFilenameFeature]
 
1837
 
 
1838
    def setUp(self):
 
1839
        super(tests.TestCaseInTempDir, self).setUp()
 
1840
        self.link = u'l\N{Euro Sign}ink'
 
1841
        self.target = u'targe\N{Euro Sign}t'
 
1842
        os.symlink(self.target, self.link)
 
1843
 
 
1844
    def test_os_readlink_link_encoding(self):
 
1845
        if sys.version_info < (2, 6):
 
1846
            self.assertRaises(UnicodeEncodeError, os.readlink, self.link)
 
1847
        else:
 
1848
            self.assertEquals(self.target,  os.readlink(self.link))
 
1849
 
 
1850
    def test_os_readlink_link_decoding(self):
 
1851
        self.assertEquals(self.target.encode(osutils._fs_enc),
 
1852
                          os.readlink(self.link.encode(osutils._fs_enc)))
 
1853
 
 
1854
 
 
1855
class TestConcurrency(tests.TestCase):
 
1856
 
 
1857
    def setUp(self):
 
1858
        super(TestConcurrency, self).setUp()
 
1859
        self.overrideAttr(osutils, '_cached_local_concurrency')
 
1860
 
 
1861
    def test_local_concurrency(self):
 
1862
        concurrency = osutils.local_concurrency()
 
1863
        self.assertIsInstance(concurrency, int)
 
1864
 
 
1865
    def test_local_concurrency_environment_variable(self):
 
1866
        os.environ['BZR_CONCURRENCY'] = '2'
 
1867
        self.assertEqual(2, osutils.local_concurrency(use_cache=False))
 
1868
        os.environ['BZR_CONCURRENCY'] = '3'
 
1869
        self.assertEqual(3, osutils.local_concurrency(use_cache=False))
 
1870
        os.environ['BZR_CONCURRENCY'] = 'foo'
 
1871
        self.assertEqual(1, osutils.local_concurrency(use_cache=False))
 
1872
 
 
1873
    def test_option_concurrency(self):
 
1874
        os.environ['BZR_CONCURRENCY'] = '1'
 
1875
        self.run_bzr('rocks --concurrency 42')
 
1876
        # Command line overrides envrionment variable
 
1877
        self.assertEquals('42', os.environ['BZR_CONCURRENCY'])
 
1878
        self.assertEquals(42, osutils.local_concurrency(use_cache=False))
 
1879
 
 
1880
 
 
1881
class TestFailedToLoadExtension(tests.TestCase):
 
1882
 
 
1883
    def _try_loading(self):
 
1884
        try:
 
1885
            import bzrlib._fictional_extension_py
 
1886
        except ImportError, e:
 
1887
            osutils.failed_to_load_extension(e)
 
1888
            return True
 
1889
 
 
1890
    def setUp(self):
 
1891
        super(TestFailedToLoadExtension, self).setUp()
 
1892
        self.overrideAttr(osutils, '_extension_load_failures', [])
 
1893
 
 
1894
    def test_failure_to_load(self):
 
1895
        self._try_loading()
 
1896
        self.assertLength(1, osutils._extension_load_failures)
 
1897
        self.assertEquals(osutils._extension_load_failures[0],
 
1898
            "No module named _fictional_extension_py")
 
1899
 
 
1900
    def test_report_extension_load_failures_no_warning(self):
 
1901
        self.assertTrue(self._try_loading())
 
1902
        warnings, result = self.callCatchWarnings(osutils.report_extension_load_failures)
 
1903
        # it used to give a Python warning; it no longer does
 
1904
        self.assertLength(0, warnings)
 
1905
 
 
1906
    def test_report_extension_load_failures_message(self):
 
1907
        log = StringIO()
 
1908
        trace.push_log_file(log)
 
1909
        self.assertTrue(self._try_loading())
 
1910
        osutils.report_extension_load_failures()
 
1911
        self.assertContainsRe(
 
1912
            log.getvalue(),
 
1913
            r"bzr: warning: some compiled extensions could not be loaded; "
 
1914
            "see <https://answers\.launchpad\.net/bzr/\+faq/703>\n"
 
1915
            )
 
1916
 
 
1917
 
 
1918
class TestTerminalWidth(tests.TestCase):
 
1919
 
 
1920
    def replace_stdout(self, new):
 
1921
        self.overrideAttr(sys, 'stdout', new)
 
1922
 
 
1923
    def replace__terminal_size(self, new):
 
1924
        self.overrideAttr(osutils, '_terminal_size', new)
 
1925
 
 
1926
    def set_fake_tty(self):
 
1927
 
 
1928
        class I_am_a_tty(object):
 
1929
            def isatty(self):
 
1930
                return True
 
1931
 
 
1932
        self.replace_stdout(I_am_a_tty())
 
1933
 
 
1934
    def test_default_values(self):
 
1935
        self.assertEqual(80, osutils.default_terminal_width)
 
1936
 
 
1937
    def test_defaults_to_BZR_COLUMNS(self):
 
1938
        # BZR_COLUMNS is set by the test framework
 
1939
        self.assertNotEqual('12', os.environ['BZR_COLUMNS'])
 
1940
        os.environ['BZR_COLUMNS'] = '12'
 
1941
        self.assertEqual(12, osutils.terminal_width())
 
1942
 
 
1943
    def test_falls_back_to_COLUMNS(self):
 
1944
        del os.environ['BZR_COLUMNS']
 
1945
        self.assertNotEqual('42', os.environ['COLUMNS'])
 
1946
        self.set_fake_tty()
 
1947
        os.environ['COLUMNS'] = '42'
 
1948
        self.assertEqual(42, osutils.terminal_width())
 
1949
 
 
1950
    def test_tty_default_without_columns(self):
 
1951
        del os.environ['BZR_COLUMNS']
 
1952
        del os.environ['COLUMNS']
 
1953
 
 
1954
        def terminal_size(w, h):
 
1955
            return 42, 42
 
1956
 
 
1957
        self.set_fake_tty()
 
1958
        # We need to override the osutils definition as it depends on the
 
1959
        # running environment that we can't control (PQM running without a
 
1960
        # controlling terminal is one example).
 
1961
        self.replace__terminal_size(terminal_size)
 
1962
        self.assertEqual(42, osutils.terminal_width())
 
1963
 
 
1964
    def test_non_tty_default_without_columns(self):
 
1965
        del os.environ['BZR_COLUMNS']
 
1966
        del os.environ['COLUMNS']
 
1967
        self.replace_stdout(None)
 
1968
        self.assertEqual(None, osutils.terminal_width())
 
1969
 
 
1970
    def test_no_TIOCGWINSZ(self):
 
1971
        self.requireFeature(term_ios_feature)
 
1972
        termios = term_ios_feature.module
 
1973
        # bug 63539 is about a termios without TIOCGWINSZ attribute
 
1974
        try:
 
1975
            orig = termios.TIOCGWINSZ
 
1976
        except AttributeError:
 
1977
            # We won't remove TIOCGWINSZ, because it doesn't exist anyway :)
 
1978
            pass
 
1979
        else:
 
1980
            self.overrideAttr(termios, 'TIOCGWINSZ')
 
1981
            del termios.TIOCGWINSZ
 
1982
        del os.environ['BZR_COLUMNS']
 
1983
        del os.environ['COLUMNS']
 
1984
        # Whatever the result is, if we don't raise an exception, it's ok.
 
1985
        osutils.terminal_width()
 
1986
 
 
1987
class TestCreationOps(tests.TestCaseInTempDir):
 
1988
    _test_needs_features = [features.chown_feature]
 
1989
 
 
1990
    def setUp(self):
 
1991
        tests.TestCaseInTempDir.setUp(self)
 
1992
        self.overrideAttr(os, 'chown', self._dummy_chown)
 
1993
 
 
1994
        # params set by call to _dummy_chown
 
1995
        self.path = self.uid = self.gid = None
 
1996
 
 
1997
    def _dummy_chown(self, path, uid, gid):
 
1998
        self.path, self.uid, self.gid = path, uid, gid
 
1999
 
 
2000
    def test_copy_ownership_from_path(self):
 
2001
        """copy_ownership_from_path test with specified src."""
 
2002
        ownsrc = '/'
 
2003
        f = open('test_file', 'wt')
 
2004
        osutils.copy_ownership_from_path('test_file', ownsrc)
 
2005
 
 
2006
        s = os.stat(ownsrc)
 
2007
        self.assertEquals(self.path, 'test_file')
 
2008
        self.assertEquals(self.uid, s.st_uid)
 
2009
        self.assertEquals(self.gid, s.st_gid)
 
2010
 
 
2011
    def test_copy_ownership_nonesrc(self):
 
2012
        """copy_ownership_from_path test with src=None."""
 
2013
        f = open('test_file', 'wt')
 
2014
        # should use parent dir for permissions
 
2015
        osutils.copy_ownership_from_path('test_file')
 
2016
 
 
2017
        s = os.stat('..')
 
2018
        self.assertEquals(self.path, 'test_file')
 
2019
        self.assertEquals(self.uid, s.st_uid)
 
2020
        self.assertEquals(self.gid, s.st_gid)
 
2021
 
 
2022
class TestGetuserUnicode(tests.TestCase):
 
2023
 
 
2024
    def test_ascii_user(self):
 
2025
        osutils.set_or_unset_env('LOGNAME', 'jrandom')
 
2026
        self.assertEqual(u'jrandom', osutils.getuser_unicode())
 
2027
 
 
2028
    def test_unicode_user(self):
 
2029
        ue = osutils.get_user_encoding()
 
2030
        osutils.set_or_unset_env('LOGNAME', u'jrandom\xb6'.encode(ue))
 
2031
        self.assertEqual(u'jrandom\xb6', osutils.getuser_unicode())