/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_osutils.py

  • Committer: Jelmer Vernooij
  • Date: 2020-03-22 01:35:14 UTC
  • mfrom: (7490.7.6 work)
  • mto: This revision was merged to the branch mainline in revision 7499.
  • Revision ID: jelmer@jelmer.uk-20200322013514-7vw1ntwho04rcuj3
merge lp:brz/3.1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Tests for the osutils wrapper."""
18
18
 
19
 
from __future__ import absolute_import, division
20
 
 
21
19
import errno
 
20
from io import BytesIO
22
21
import os
23
 
import re
24
22
import select
25
23
import socket
26
24
import sys
29
27
 
30
28
from .. import (
31
29
    errors,
32
 
    lazy_regex,
33
30
    osutils,
34
 
    symbol_versioning,
35
31
    tests,
36
32
    trace,
37
33
    win32utils,
38
34
    )
39
 
from ..sixish import (
40
 
    BytesIO,
41
 
    )
42
35
from . import (
43
36
    features,
44
37
    file_utils,
58
51
        except ImportError:
59
52
            return False
60
53
 
 
54
 
61
55
UTF8DirReaderFeature = _UTF8DirReaderFeature('breezy._readdir_pyx')
62
56
 
63
57
term_ios_feature = features.ModuleAvailableFeature('termios')
136
130
 
137
131
    def test_fancy_rename(self):
138
132
        # This should work everywhere
139
 
        self.create_file('a', 'something in a\n')
 
133
        self.create_file('a', b'something in a\n')
140
134
        self._fancy_rename('a', 'b')
141
135
        self.assertPathDoesNotExist('a')
142
136
        self.assertPathExists('b')
143
 
        self.check_file_contents('b', 'something in a\n')
 
137
        self.check_file_contents('b', b'something in a\n')
144
138
 
145
 
        self.create_file('a', 'new something in a\n')
 
139
        self.create_file('a', b'new something in a\n')
146
140
        self._fancy_rename('b', 'a')
147
141
 
148
 
        self.check_file_contents('a', 'something in a\n')
 
142
        self.check_file_contents('a', b'something in a\n')
149
143
 
150
144
    def test_fancy_rename_fails_source_missing(self):
151
145
        # An exception should be raised, and the target should be left in place
152
 
        self.create_file('target', 'data in target\n')
 
146
        self.create_file('target', b'data in target\n')
153
147
        self.assertRaises((IOError, OSError), self._fancy_rename,
154
148
                          'missingsource', 'target')
155
149
        self.assertPathExists('target')
156
 
        self.check_file_contents('target', 'data in target\n')
 
150
        self.check_file_contents('target', b'data in target\n')
157
151
 
158
152
    def test_fancy_rename_fails_if_source_and_target_missing(self):
159
153
        self.assertRaises((IOError, OSError), self._fancy_rename,
161
155
 
162
156
    def test_rename(self):
163
157
        # Rename should be semi-atomic on all platforms
164
 
        self.create_file('a', 'something in a\n')
 
158
        self.create_file('a', b'something in a\n')
165
159
        osutils.rename('a', 'b')
166
160
        self.assertPathDoesNotExist('a')
167
161
        self.assertPathExists('b')
168
 
        self.check_file_contents('b', 'something in a\n')
 
162
        self.check_file_contents('b', b'something in a\n')
169
163
 
170
 
        self.create_file('a', 'new something in a\n')
 
164
        self.create_file('a', b'new something in a\n')
171
165
        osutils.rename('b', 'a')
172
166
 
173
 
        self.check_file_contents('a', 'something in a\n')
 
167
        self.check_file_contents('a', b'something in a\n')
174
168
 
175
169
    # TODO: test fancy_rename using a MemoryTransport
176
170
 
255
249
            # Without it, we may end up re-reading content when we don't have
256
250
            # to, but otherwise it doesn't effect correctness.
257
251
            self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
258
 
        f = open('test-file.txt', 'wb')
259
 
        self.addCleanup(f.close)
260
 
        f.write('some content\n')
261
 
        f.flush()
262
 
        self.assertEqualStat(osutils.fstat(f.fileno()),
263
 
                             osutils.lstat('test-file.txt'))
 
252
        with open('test-file.txt', 'wb') as f:
 
253
            f.write(b'some content\n')
 
254
            f.flush()
 
255
            self.assertEqualStat(osutils.fstat(f.fileno()),
 
256
                                 osutils.lstat('test-file.txt'))
264
257
 
265
258
 
266
259
class TestRmTree(tests.TestCaseInTempDir):
268
261
    def test_rmtree(self):
269
262
        # Check to remove tree with read-only files/dirs
270
263
        os.mkdir('dir')
271
 
        f = file('dir/file', 'w')
272
 
        f.write('spam')
273
 
        f.close()
 
264
        with open('dir/file', 'w') as f:
 
265
            f.write('spam')
274
266
        # would like to also try making the directory readonly, but at the
275
267
        # moment python shutil.rmtree doesn't handle that properly - it would
276
268
        # need to chmod the directory before removing things inside it - deferred
313
305
            if e.errno not in (errno.ENOENT,):
314
306
                raise
315
307
        else:
316
 
            self.assertEqual('chardev', osutils.file_kind('/dev/null'))
 
308
            self.assertEqual(
 
309
                'chardev',
 
310
                osutils.file_kind(os.path.realpath('/dev/null')))
317
311
 
318
312
        mkfifo = getattr(os, 'mkfifo', None)
319
313
        if mkfifo:
403
397
 
404
398
    def test_format_date(self):
405
399
        self.assertRaises(osutils.UnsupportedTimezoneFormat,
406
 
            osutils.format_date, 0, timezone='foo')
 
400
                          osutils.format_date, 0, timezone='foo')
407
401
        self.assertIsInstance(osutils.format_date(0), str)
408
 
        self.assertIsInstance(osutils.format_local_date(0), unicode)
 
402
        self.assertIsInstance(osutils.format_local_date(0), str)
409
403
        # Testing for the actual value of the local weekday without
410
404
        # duplicating the code from format_date is difficult.
411
405
        # Instead blackbox.test_locale should check for localized
413
407
 
414
408
    def test_format_date_with_offset_in_original_timezone(self):
415
409
        self.assertEqual("Thu 1970-01-01 00:00:00 +0000",
416
 
            osutils.format_date_with_offset_in_original_timezone(0))
 
410
                         osutils.format_date_with_offset_in_original_timezone(0))
417
411
        self.assertEqual("Fri 1970-01-02 03:46:40 +0000",
418
 
            osutils.format_date_with_offset_in_original_timezone(100000))
 
412
                         osutils.format_date_with_offset_in_original_timezone(100000))
419
413
        self.assertEqual("Fri 1970-01-02 05:46:40 +0200",
420
 
            osutils.format_date_with_offset_in_original_timezone(100000, 7200))
 
414
                         osutils.format_date_with_offset_in_original_timezone(100000, 7200))
421
415
 
422
416
    def test_local_time_offset(self):
423
417
        """Test that local_time_offset() returns a sane value."""
512
506
        self.assertEqual(baz_path, osutils.dereference_path(foo_baz_path))
513
507
 
514
508
    def test_changing_access(self):
515
 
        f = file('file', 'w')
516
 
        f.write('monkey')
517
 
        f.close()
 
509
        with open('file', 'w') as f:
 
510
            f.write('monkey')
518
511
 
519
512
        # Make a file readonly
520
513
        osutils.make_readonly('file')
541
534
    _test_needs_features = [features.CaseInsCasePresFilenameFeature]
542
535
 
543
536
    def test_canonical_relpath_simple(self):
544
 
        f = file('MixedCaseName', 'w')
 
537
        f = open('MixedCaseName', 'w')
545
538
        f.close()
546
539
        actual = osutils.canonical_relpath(self.test_base_dir, 'mixedcasename')
547
540
        self.assertEqual('work/MixedCaseName', actual)
618
611
 
619
612
        # read (max // 2) bytes and verify read size wasn't affected
620
613
        num_bytes_to_read = self.block_size // 2
621
 
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
614
        osutils.pumpfile(from_file, to_file,
 
615
                         num_bytes_to_read, self.block_size)
622
616
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
623
617
        self.assertEqual(from_file.get_read_count(), 1)
624
618
 
625
619
        # read (max) bytes and verify read size wasn't affected
626
620
        num_bytes_to_read = self.block_size
627
621
        from_file.reset_read_count()
628
 
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
622
        osutils.pumpfile(from_file, to_file,
 
623
                         num_bytes_to_read, self.block_size)
629
624
        self.assertEqual(from_file.get_max_read_size(), num_bytes_to_read)
630
625
        self.assertEqual(from_file.get_read_count(), 1)
631
626
 
632
627
        # read (max + 1) bytes and verify read size was limited
633
628
        num_bytes_to_read = self.block_size + 1
634
629
        from_file.reset_read_count()
635
 
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
630
        osutils.pumpfile(from_file, to_file,
 
631
                         num_bytes_to_read, self.block_size)
636
632
        self.assertEqual(from_file.get_max_read_size(), self.block_size)
637
633
        self.assertEqual(from_file.get_read_count(), 2)
638
634
 
639
635
        # finish reading the rest of the data
640
636
        num_bytes_to_read = self.test_data_len - to_file.tell()
641
 
        osutils.pumpfile(from_file, to_file, num_bytes_to_read, self.block_size)
 
637
        osutils.pumpfile(from_file, to_file,
 
638
                         num_bytes_to_read, self.block_size)
642
639
 
643
640
        # report error if the data wasn't equal (we only report the size due
644
641
        # to the length of the data)
711
708
 
712
709
    def test_report_activity(self):
713
710
        activity = []
 
711
 
714
712
        def log_activity(length, direction):
715
713
            activity.append((length, direction))
716
714
        from_file = BytesIO(self.test_data)
734
732
        del activity[:]
735
733
        osutils.pumpfile(from_file, to_file, buff_size=500, read_length=1028,
736
734
                         report_activity=log_activity, direction='read')
737
 
        self.assertEqual([(500, 'read'), (500, 'read'), (28, 'read')], activity)
738
 
 
 
735
        self.assertEqual(
 
736
            [(500, 'read'), (500, 'read'), (28, 'read')], activity)
739
737
 
740
738
 
741
739
class TestPumpStringFile(tests.TestCase):
783
781
class TestSafeUnicode(tests.TestCase):
784
782
 
785
783
    def test_from_ascii_string(self):
786
 
        self.assertEqual(u'foobar', osutils.safe_unicode('foobar'))
 
784
        self.assertEqual(u'foobar', osutils.safe_unicode(b'foobar'))
787
785
 
788
786
    def test_from_unicode_string_ascii_contents(self):
789
787
        self.assertEqual(u'bargam', osutils.safe_unicode(u'bargam'))
792
790
        self.assertEqual(u'bargam\xae', osutils.safe_unicode(u'bargam\xae'))
793
791
 
794
792
    def test_from_utf8_string(self):
795
 
        self.assertEqual(u'foo\xae', osutils.safe_unicode('foo\xc2\xae'))
 
793
        self.assertEqual(u'foo\xae', osutils.safe_unicode(b'foo\xc2\xae'))
796
794
 
797
795
    def test_bad_utf8_string(self):
798
796
        self.assertRaises(errors.BzrBadParameterNotUnicode,
799
797
                          osutils.safe_unicode,
800
 
                          '\xbb\xbb')
 
798
                          b'\xbb\xbb')
801
799
 
802
800
 
803
801
class TestSafeUtf8(tests.TestCase):
804
802
 
805
803
    def test_from_ascii_string(self):
806
 
        f = 'foobar'
807
 
        self.assertEqual('foobar', osutils.safe_utf8(f))
 
804
        f = b'foobar'
 
805
        self.assertEqual(b'foobar', osutils.safe_utf8(f))
808
806
 
809
807
    def test_from_unicode_string_ascii_contents(self):
810
 
        self.assertEqual('bargam', osutils.safe_utf8(u'bargam'))
 
808
        self.assertEqual(b'bargam', osutils.safe_utf8(u'bargam'))
811
809
 
812
810
    def test_from_unicode_string_unicode_contents(self):
813
 
        self.assertEqual('bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
 
811
        self.assertEqual(b'bargam\xc2\xae', osutils.safe_utf8(u'bargam\xae'))
814
812
 
815
813
    def test_from_utf8_string(self):
816
 
        self.assertEqual('foo\xc2\xae', osutils.safe_utf8('foo\xc2\xae'))
 
814
        self.assertEqual(b'foo\xc2\xae', osutils.safe_utf8(b'foo\xc2\xae'))
817
815
 
818
816
    def test_bad_utf8_string(self):
819
817
        self.assertRaises(errors.BzrBadParameterNotUnicode,
820
 
                          osutils.safe_utf8, '\xbb\xbb')
 
818
                          osutils.safe_utf8, b'\xbb\xbb')
821
819
 
822
820
 
823
821
class TestSafeRevisionId(tests.TestCase):
824
822
 
825
823
    def test_from_ascii_string(self):
826
824
        # this shouldn't give a warning because it's getting an ascii string
827
 
        self.assertEqual('foobar', osutils.safe_revision_id('foobar'))
 
825
        self.assertEqual(b'foobar', osutils.safe_revision_id(b'foobar'))
828
826
 
829
827
    def test_from_unicode_string_ascii_contents(self):
830
828
        self.assertRaises(TypeError,
832
830
 
833
831
    def test_from_unicode_string_unicode_contents(self):
834
832
        self.assertRaises(TypeError,
835
 
                         osutils.safe_revision_id, u'bargam\xae')
 
833
                          osutils.safe_revision_id, u'bargam\xae')
836
834
 
837
835
    def test_from_utf8_string(self):
838
 
        self.assertEqual('foo\xc2\xae',
839
 
                         osutils.safe_revision_id('foo\xc2\xae'))
 
836
        self.assertEqual(b'foo\xc2\xae',
 
837
                         osutils.safe_revision_id(b'foo\xc2\xae'))
840
838
 
841
839
    def test_none(self):
842
840
        """Currently, None is a valid revision_id"""
846
844
class TestSafeFileId(tests.TestCase):
847
845
 
848
846
    def test_from_ascii_string(self):
849
 
        self.assertEqual('foobar', osutils.safe_file_id('foobar'))
 
847
        self.assertEqual(b'foobar', osutils.safe_file_id(b'foobar'))
850
848
 
851
849
    def test_from_unicode_string_ascii_contents(self):
852
850
        self.assertRaises(TypeError, osutils.safe_file_id, u'bargam')
856
854
                          osutils.safe_file_id, u'bargam\xae')
857
855
 
858
856
    def test_from_utf8_string(self):
859
 
        self.assertEqual('foo\xc2\xae',
860
 
                         osutils.safe_file_id('foo\xc2\xae'))
 
857
        self.assertEqual(b'foo\xc2\xae',
 
858
                         osutils.safe_file_id(b'foo\xc2\xae'))
861
859
 
862
860
    def test_none(self):
863
861
        """Currently, None is a valid revision_id"""
870
868
        class DisconnectedSocket(object):
871
869
            def __init__(self, err):
872
870
                self.err = err
 
871
 
873
872
            def send(self, content):
874
873
                raise self.err
 
874
 
875
875
            def close(self):
876
876
                pass
877
877
        # All of these should be treated as ConnectionReset
882
882
        for err in errs:
883
883
            sock = DisconnectedSocket(err)
884
884
            self.assertRaises(errors.ConnectionReset,
885
 
                osutils.send_all, sock, b'some more content')
 
885
                              osutils.send_all, sock, b'some more content')
886
886
 
887
887
    def test_send_with_no_progress(self):
888
888
        # See https://bugs.launchpad.net/bzr/+bug/1047309
891
891
        class NoSendingSocket(object):
892
892
            def __init__(self):
893
893
                self.call_count = 0
 
894
 
894
895
            def send(self, bytes):
895
896
                self.call_count += 1
896
897
                if self.call_count > 100:
909
910
 
910
911
    def test_normpath(self):
911
912
        self.assertEqual('/etc/shadow', osutils._posix_normpath('/etc/shadow'))
912
 
        self.assertEqual('/etc/shadow', osutils._posix_normpath('//etc/shadow'))
913
 
        self.assertEqual('/etc/shadow', osutils._posix_normpath('///etc/shadow'))
 
913
        self.assertEqual(
 
914
            '/etc/shadow', osutils._posix_normpath('//etc/shadow'))
 
915
        self.assertEqual(
 
916
            '/etc/shadow', osutils._posix_normpath('///etc/shadow'))
914
917
 
915
918
 
916
919
class TestWin32Funcs(tests.TestCase):
938
941
                         osutils._win32_pathjoin('path/to/', 'foo'))
939
942
 
940
943
    def test_pathjoin_late_bugfix(self):
941
 
        if sys.version_info < (2, 7, 6):
942
 
            expected = '/foo'
943
 
        else:
944
 
            expected = 'C:/foo'
 
944
        expected = 'C:/foo'
945
945
        self.assertEqual(expected,
946
946
                         osutils._win32_pathjoin('C:/path/to/', '/foo'))
947
947
        self.assertEqual(expected,
985
985
 
986
986
    def test_minimum_path_selection(self):
987
987
        self.assertEqual(set(),
988
 
            osutils.minimum_path_selection([]))
 
988
                         osutils.minimum_path_selection([]))
989
989
        self.assertEqual({'a'},
990
 
            osutils.minimum_path_selection(['a']))
 
990
                         osutils.minimum_path_selection(['a']))
991
991
        self.assertEqual({'a', 'b'},
992
 
            osutils.minimum_path_selection(['a', 'b']))
993
 
        self.assertEqual({'a/', 'b'},
994
 
            osutils.minimum_path_selection(['a/', 'b']))
995
 
        self.assertEqual({'a/', 'b'},
996
 
            osutils.minimum_path_selection(['a/c', 'a/', 'b']))
 
992
                         osutils.minimum_path_selection(['a', 'b']))
 
993
        self.assertEqual({'a/', 'b'},
 
994
                         osutils.minimum_path_selection(['a/', 'b']))
 
995
        self.assertEqual({'a/', 'b'},
 
996
                         osutils.minimum_path_selection(['a/c', 'a/', 'b']))
997
997
        self.assertEqual({'a-b', 'a', 'a0b'},
998
 
            osutils.minimum_path_selection(['a-b', 'a/b', 'a0b', 'a']))
 
998
                         osutils.minimum_path_selection(['a-b', 'a/b', 'a0b', 'a']))
999
999
 
1000
1000
    def test_mkdtemp(self):
1001
1001
        tmpdir = osutils._win32_mkdtemp(dir='.')
1002
1002
        self.assertFalse('\\' in tmpdir)
1003
1003
 
1004
1004
    def test_rename(self):
1005
 
        a = open('a', 'wb')
1006
 
        a.write('foo\n')
1007
 
        a.close()
1008
 
        b = open('b', 'wb')
1009
 
        b.write('baz\n')
1010
 
        b.close()
 
1005
        with open('a', 'wb') as a:
 
1006
            a.write(b'foo\n')
 
1007
        with open('b', 'wb') as b:
 
1008
            b.write(b'baz\n')
1011
1009
 
1012
1010
        osutils._win32_rename('b', 'a')
1013
1011
        self.assertPathExists('a')
1014
1012
        self.assertPathDoesNotExist('b')
1015
 
        self.assertFileEqual('baz\n', 'a')
 
1013
        self.assertFileEqual(b'baz\n', 'a')
1016
1014
 
1017
1015
    def test_rename_missing_file(self):
1018
 
        a = open('a', 'wb')
1019
 
        a.write('foo\n')
1020
 
        a.close()
 
1016
        with open('a', 'wb') as a:
 
1017
            a.write(b'foo\n')
1021
1018
 
1022
1019
        try:
1023
1020
            osutils._win32_rename('b', 'a')
1024
1021
        except (IOError, OSError) as e:
1025
1022
            self.assertEqual(errno.ENOENT, e.errno)
1026
 
        self.assertFileEqual('foo\n', 'a')
 
1023
        self.assertFileEqual(b'foo\n', 'a')
1027
1024
 
1028
1025
    def test_rename_missing_dir(self):
1029
1026
        os.mkdir('a')
1052
1049
        check(['a', 'b'], 'a/b')
1053
1050
        check(['a', 'b'], 'a/./b')
1054
1051
        check(['a', '.b'], 'a/.b')
1055
 
        check(['a', '.b'], 'a\\.b')
 
1052
        if os.path.sep == '\\':
 
1053
            check(['a', '.b'], 'a\\.b')
 
1054
        else:
 
1055
            check(['a\\.b'], 'a\\.b')
1056
1056
 
1057
1057
        self.assertRaises(errors.BzrError, osutils.splitpath, 'a/../b')
1058
1058
 
1086
1086
class TestChunksToLines(tests.TestCase):
1087
1087
 
1088
1088
    def test_smoketest(self):
1089
 
        self.assertEqual(['foo\n', 'bar\n', 'baz\n'],
1090
 
                         osutils.chunks_to_lines(['foo\nbar', '\nbaz\n']))
1091
 
        self.assertEqual(['foo\n', 'bar\n', 'baz\n'],
1092
 
                         osutils.chunks_to_lines(['foo\n', 'bar\n', 'baz\n']))
 
1089
        self.assertEqual([b'foo\n', b'bar\n', b'baz\n'],
 
1090
                         osutils.chunks_to_lines([b'foo\nbar', b'\nbaz\n']))
 
1091
        self.assertEqual([b'foo\n', b'bar\n', b'baz\n'],
 
1092
                         osutils.chunks_to_lines([b'foo\n', b'bar\n', b'baz\n']))
1093
1093
 
1094
1094
    def test_osutils_binding(self):
1095
1095
        from . import test__chunks_to_lines
1109
1109
                         osutils.split_lines(u'foo\nbar\xae\n'))
1110
1110
 
1111
1111
    def test_split_with_carriage_returns(self):
1112
 
        self.assertEqual(['foo\rbar\n'],
1113
 
                         osutils.split_lines('foo\rbar\n'))
 
1112
        self.assertEqual([b'foo\rbar\n'],
 
1113
                         osutils.split_lines(b'foo\rbar\n'))
1114
1114
 
1115
1115
 
1116
1116
class TestWalkDirs(tests.TestCaseInTempDir):
1131
1131
            ]
1132
1132
        self.build_tree(tree)
1133
1133
        expected_dirblocks = [
1134
 
                (('', '.'),
1135
 
                 [('0file', '0file', 'file'),
1136
 
                  ('1dir', '1dir', 'directory'),
1137
 
                  ('2file', '2file', 'file'),
1138
 
                 ]
1139
 
                ),
1140
 
                (('1dir', './1dir'),
1141
 
                 [('1dir/0file', '0file', 'file'),
1142
 
                  ('1dir/1dir', '1dir', 'directory'),
1143
 
                 ]
1144
 
                ),
1145
 
                (('1dir/1dir', './1dir/1dir'),
1146
 
                 [
1147
 
                 ]
1148
 
                ),
 
1134
            (('', '.'),
 
1135
             [('0file', '0file', 'file'),
 
1136
              ('1dir', '1dir', 'directory'),
 
1137
              ('2file', '2file', 'file'),
 
1138
              ]
 
1139
             ),
 
1140
            (('1dir', './1dir'),
 
1141
             [('1dir/0file', '0file', 'file'),
 
1142
              ('1dir/1dir', '1dir', 'directory'),
 
1143
              ]
 
1144
             ),
 
1145
            (('1dir/1dir', './1dir/1dir'),
 
1146
             [
 
1147
                ]
 
1148
             ),
1149
1149
            ]
1150
1150
        result = []
1151
1151
        found_bzrdir = False
1180
1180
        # (It would be ok if it happened earlier but at the moment it
1181
1181
        # doesn't.)
1182
1182
        e = self.assertRaises(OSError, list, osutils._walkdirs_utf8("."))
1183
 
        self.assertEqual('./test-unreadable', e.filename)
 
1183
        self.assertEqual('./test-unreadable', osutils.safe_unicode(e.filename))
1184
1184
        self.assertEqual(errno.EACCES, e.errno)
1185
1185
        # Ensure the message contains the file name
1186
1186
        self.assertContainsRe(str(e), "\\./test-unreadable")
1187
1187
 
1188
 
 
1189
1188
    def test_walkdirs_encoding_error(self):
1190
1189
        # <https://bugs.launchpad.net/bzr/+bug/488519>
1191
1190
        # walkdirs didn't raise a useful message when the filenames
1206
1205
        self.build_tree(tree)
1207
1206
 
1208
1207
        # rename the 1file to a latin-1 filename
1209
 
        os.rename("./1file", "\xe8file")
1210
 
        if "\xe8file" not in os.listdir("."):
 
1208
        os.rename(b"./1file", b"\xe8file")
 
1209
        if b"\xe8file" not in os.listdir("."):
1211
1210
            self.skipTest("Lack filesystem that preserves arbitrary bytes")
1212
1211
 
1213
1212
        self._save_platform_info()
1215
1214
 
1216
1215
        # this should raise on error
1217
1216
        def attempt():
1218
 
            for dirdetail, dirblock in osutils.walkdirs('.'):
 
1217
            for dirdetail, dirblock in osutils.walkdirs(b'.'):
1219
1218
                pass
1220
1219
 
1221
1220
        self.assertRaises(errors.BadFilenameEncoding, attempt)
1231
1230
            ]
1232
1231
        self.build_tree(tree)
1233
1232
        expected_dirblocks = [
1234
 
                (('', '.'),
1235
 
                 [('0file', '0file', 'file'),
1236
 
                  ('1dir', '1dir', 'directory'),
1237
 
                  ('2file', '2file', 'file'),
1238
 
                 ]
1239
 
                ),
1240
 
                (('1dir', './1dir'),
1241
 
                 [('1dir/0file', '0file', 'file'),
1242
 
                  ('1dir/1dir', '1dir', 'directory'),
1243
 
                 ]
1244
 
                ),
1245
 
                (('1dir/1dir', './1dir/1dir'),
1246
 
                 [
1247
 
                 ]
1248
 
                ),
 
1233
            (('', '.'),
 
1234
             [('0file', '0file', 'file'),
 
1235
              ('1dir', '1dir', 'directory'),
 
1236
              ('2file', '2file', 'file'),
 
1237
              ]
 
1238
             ),
 
1239
            (('1dir', './1dir'),
 
1240
             [('1dir/0file', '0file', 'file'),
 
1241
              ('1dir/1dir', '1dir', 'directory'),
 
1242
              ]
 
1243
             ),
 
1244
            (('1dir/1dir', './1dir/1dir'),
 
1245
             [
 
1246
                ]
 
1247
             ),
1249
1248
            ]
1250
1249
        result = []
1251
1250
        found_bzrdir = False
1252
 
        for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
1253
 
            if len(dirblock) and dirblock[0][1] == '.bzr':
 
1251
        for dirdetail, dirblock in osutils._walkdirs_utf8(b'.'):
 
1252
            if len(dirblock) and dirblock[0][1] == b'.bzr':
1254
1253
                # this tests the filtering of selected paths
1255
1254
                found_bzrdir = True
1256
1255
                del dirblock[0]
 
1256
            dirdetail = (dirdetail[0].decode('utf-8'),
 
1257
                         osutils.safe_unicode(dirdetail[1]))
 
1258
            dirblock = [
 
1259
                (entry[0].decode('utf-8'), entry[1].decode('utf-8'), entry[2])
 
1260
                for entry in dirblock]
1257
1261
            result.append((dirdetail, dirblock))
1258
1262
 
1259
1263
        self.assertTrue(found_bzrdir)
1278
1282
        self.overrideAttr(osutils, '_fs_enc')
1279
1283
        self.overrideAttr(osutils, '_selected_dir_reader')
1280
1284
 
1281
 
    def assertDirReaderIs(self, expected):
 
1285
    def assertDirReaderIs(self, expected, top):
1282
1286
        """Assert the right implementation for _walkdirs_utf8 is chosen."""
1283
1287
        # Force it to redetect
1284
1288
        osutils._selected_dir_reader = None
1285
1289
        # Nothing to list, but should still trigger the selection logic
1286
 
        self.assertEqual([(('', '.'), [])], list(osutils._walkdirs_utf8('.')))
 
1290
        self.assertEqual([((b'', top), [])], list(osutils._walkdirs_utf8('.')))
1287
1291
        self.assertIsInstance(osutils._selected_dir_reader, expected)
1288
1292
 
1289
1293
    def test_force_walkdirs_utf8_fs_utf8(self):
1290
1294
        self.requireFeature(UTF8DirReaderFeature)
1291
1295
        self._save_platform_info()
1292
1296
        osutils._fs_enc = 'utf-8'
1293
 
        self.assertDirReaderIs(
1294
 
            UTF8DirReaderFeature.module.UTF8DirReader)
 
1297
        self.assertDirReaderIs(UTF8DirReaderFeature.module.UTF8DirReader, b".")
1295
1298
 
1296
1299
    def test_force_walkdirs_utf8_fs_ascii(self):
1297
1300
        self.requireFeature(UTF8DirReaderFeature)
1298
1301
        self._save_platform_info()
1299
1302
        osutils._fs_enc = 'ascii'
1300
1303
        self.assertDirReaderIs(
1301
 
            UTF8DirReaderFeature.module.UTF8DirReader)
 
1304
            UTF8DirReaderFeature.module.UTF8DirReader, b".")
1302
1305
 
1303
1306
    def test_force_walkdirs_utf8_fs_latin1(self):
1304
1307
        self._save_platform_info()
1305
1308
        osutils._fs_enc = 'iso-8859-1'
1306
 
        self.assertDirReaderIs(osutils.UnicodeDirReader)
 
1309
        self.assertDirReaderIs(osutils.UnicodeDirReader, ".")
1307
1310
 
1308
1311
    def test_force_walkdirs_utf8_nt(self):
1309
1312
        # Disabled because the thunk of the whole walkdirs api is disabled.
1310
1313
        self.requireFeature(test__walkdirs_win32.win32_readdir_feature)
1311
1314
        self._save_platform_info()
1312
1315
        from .._walkdirs_win32 import Win32ReadDir
1313
 
        self.assertDirReaderIs(Win32ReadDir)
 
1316
        self.assertDirReaderIs(Win32ReadDir, ".")
1314
1317
 
1315
1318
    def test_unicode_walkdirs(self):
1316
1319
        """Walkdirs should always return unicode paths."""
1327
1330
            ]
1328
1331
        self.build_tree(tree)
1329
1332
        expected_dirblocks = [
1330
 
                ((u'', u'.'),
1331
 
                 [(name0, name0, 'file', './' + name0),
1332
 
                  (name1, name1, 'directory', './' + name1),
1333
 
                  (name2, name2, 'file', './' + name2),
1334
 
                 ]
1335
 
                ),
1336
 
                ((name1, './' + name1),
1337
 
                 [(name1 + '/' + name0, name0, 'file', './' + name1
1338
 
                                                        + '/' + name0),
1339
 
                  (name1 + '/' + name1, name1, 'directory', './' + name1
1340
 
                                                            + '/' + name1),
1341
 
                 ]
1342
 
                ),
1343
 
                ((name1 + '/' + name1, './' + name1 + '/' + name1),
1344
 
                 [
1345
 
                 ]
1346
 
                ),
 
1333
            ((u'', u'.'),
 
1334
             [(name0, name0, 'file', './' + name0),
 
1335
              (name1, name1, 'directory', './' + name1),
 
1336
              (name2, name2, 'file', './' + name2),
 
1337
              ]
 
1338
             ),
 
1339
            ((name1, './' + name1),
 
1340
             [(name1 + '/' + name0, name0, 'file', './' + name1
 
1341
               + '/' + name0),
 
1342
              (name1 + '/' + name1, name1, 'directory', './' + name1
 
1343
               + '/' + name1),
 
1344
              ]
 
1345
             ),
 
1346
            ((name1 + '/' + name1, './' + name1 + '/' + name1),
 
1347
             [
 
1348
                ]
 
1349
             ),
1347
1350
            ]
1348
1351
        result = list(osutils.walkdirs('.'))
1349
1352
        self._filter_out_stat(result)
1350
1353
        self.assertEqual(expected_dirblocks, result)
1351
 
        result = list(osutils.walkdirs(u'./'+name1, name1))
 
1354
        result = list(osutils.walkdirs(u'./' + name1, name1))
1352
1355
        self._filter_out_stat(result)
1353
1356
        self.assertEqual(expected_dirblocks[1:], result)
1354
1357
 
1374
1377
        name2 = name2.encode('utf8')
1375
1378
 
1376
1379
        expected_dirblocks = [
1377
 
                (('', '.'),
1378
 
                 [(name0, name0, 'file', './' + name0),
1379
 
                  (name1, name1, 'directory', './' + name1),
1380
 
                  (name2, name2, 'file', './' + name2),
1381
 
                 ]
1382
 
                ),
1383
 
                ((name1, './' + name1),
1384
 
                 [(name1 + '/' + name0, name0, 'file', './' + name1
1385
 
                                                        + '/' + name0),
1386
 
                  (name1 + '/' + name1, name1, 'directory', './' + name1
1387
 
                                                            + '/' + name1),
1388
 
                 ]
1389
 
                ),
1390
 
                ((name1 + '/' + name1, './' + name1 + '/' + name1),
1391
 
                 [
1392
 
                 ]
1393
 
                ),
 
1380
            ((b'', b'.'),
 
1381
             [(name0, name0, 'file', b'./' + name0),
 
1382
              (name1, name1, 'directory', b'./' + name1),
 
1383
              (name2, name2, 'file', b'./' + name2),
 
1384
              ]
 
1385
             ),
 
1386
            ((name1, b'./' + name1),
 
1387
             [(name1 + b'/' + name0, name0, 'file', b'./' + name1
 
1388
               + b'/' + name0),
 
1389
              (name1 + b'/' + name1, name1, 'directory', b'./' + name1
 
1390
               + b'/' + name1),
 
1391
              ]
 
1392
             ),
 
1393
            ((name1 + b'/' + name1, b'./' + name1 + b'/' + name1),
 
1394
             [
 
1395
                ]
 
1396
             ),
1394
1397
            ]
1395
1398
        result = []
1396
1399
        # For ease in testing, if walkdirs_utf8 returns Unicode, assert that
1397
1400
        # all abspaths are Unicode, and encode them back into utf8.
1398
1401
        for dirdetail, dirblock in osutils._walkdirs_utf8('.'):
1399
 
            self.assertIsInstance(dirdetail[0], str)
1400
 
            if isinstance(dirdetail[1], unicode):
 
1402
            self.assertIsInstance(dirdetail[0], bytes)
 
1403
            if isinstance(dirdetail[1], str):
1401
1404
                dirdetail = (dirdetail[0], dirdetail[1].encode('utf8'))
1402
1405
                dirblock = [list(info) for info in dirblock]
1403
1406
                for info in dirblock:
1404
 
                    self.assertIsInstance(info[4], unicode)
 
1407
                    self.assertIsInstance(info[4], str)
1405
1408
                    info[4] = info[4].encode('utf8')
1406
1409
            new_dirblock = []
1407
1410
            for info in dirblock:
1408
 
                self.assertIsInstance(info[0], str)
1409
 
                self.assertIsInstance(info[1], str)
1410
 
                self.assertIsInstance(info[4], str)
 
1411
                self.assertIsInstance(info[0], bytes)
 
1412
                self.assertIsInstance(info[1], bytes)
 
1413
                self.assertIsInstance(info[4], bytes)
1411
1414
                # Remove the stat information
1412
1415
                new_dirblock.append((info[0], info[1], info[2], info[4]))
1413
1416
            result.append((dirdetail, new_dirblock))
1441
1444
        # All of the abspaths should be in unicode, all of the relative paths
1442
1445
        # should be in utf8
1443
1446
        expected_dirblocks = [
1444
 
                (('', '.'),
1445
 
                 [(name0, name0, 'file', './' + name0u),
1446
 
                  (name1, name1, 'directory', './' + name1u),
1447
 
                  (name2, name2, 'file', './' + name2u),
1448
 
                 ]
1449
 
                ),
1450
 
                ((name1, './' + name1u),
1451
 
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
1452
 
                                                        + '/' + name0u),
1453
 
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
1454
 
                                                            + '/' + name1u),
1455
 
                 ]
1456
 
                ),
1457
 
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
1458
 
                 [
1459
 
                 ]
1460
 
                ),
 
1447
            ((b'', '.'),
 
1448
             [(name0, name0, 'file', './' + name0u),
 
1449
              (name1, name1, 'directory', './' + name1u),
 
1450
              (name2, name2, 'file', './' + name2u),
 
1451
              ]
 
1452
             ),
 
1453
            ((name1, './' + name1u),
 
1454
             [(name1 + b'/' + name0, name0, 'file', './' + name1u
 
1455
               + '/' + name0u),
 
1456
              (name1 + b'/' + name1, name1, 'directory', './' + name1u
 
1457
               + '/' + name1u),
 
1458
              ]
 
1459
             ),
 
1460
            ((name1 + b'/' + name1, './' + name1u + '/' + name1u),
 
1461
             [
 
1462
                ]
 
1463
             ),
1461
1464
            ]
1462
1465
        result = list(osutils._walkdirs_utf8('.'))
1463
1466
        self._filter_out_stat(result)
1487
1490
        # All of the abspaths should be in unicode, all of the relative paths
1488
1491
        # should be in utf8
1489
1492
        expected_dirblocks = [
1490
 
                (('', '.'),
1491
 
                 [(name0, name0, 'file', './' + name0u),
1492
 
                  (name1, name1, 'directory', './' + name1u),
1493
 
                  (name2, name2, 'file', './' + name2u),
1494
 
                 ]
1495
 
                ),
1496
 
                ((name1, './' + name1u),
1497
 
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
1498
 
                                                        + '/' + name0u),
1499
 
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
1500
 
                                                            + '/' + name1u),
1501
 
                 ]
1502
 
                ),
1503
 
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
1504
 
                 [
1505
 
                 ]
1506
 
                ),
 
1493
            (('', '.'),
 
1494
             [(name0, name0, 'file', './' + name0u),
 
1495
              (name1, name1, 'directory', './' + name1u),
 
1496
              (name2, name2, 'file', './' + name2u),
 
1497
              ]
 
1498
             ),
 
1499
            ((name1, './' + name1u),
 
1500
             [(name1 + '/' + name0, name0, 'file', './' + name1u
 
1501
               + '/' + name0u),
 
1502
              (name1 + '/' + name1, name1, 'directory', './' + name1u
 
1503
               + '/' + name1u),
 
1504
              ]
 
1505
             ),
 
1506
            ((name1 + '/' + name1, './' + name1u + '/' + name1u),
 
1507
             [
 
1508
                ]
 
1509
             ),
1507
1510
            ]
1508
1511
        result = list(osutils._walkdirs_utf8(u'.'))
1509
1512
        self._filter_out_stat(result)
1530
1533
        # I hate to sleep() here, but I'm trying to make the ctime different
1531
1534
        # from the mtime
1532
1535
        time.sleep(2)
1533
 
        f = open(name0u, 'ab')
1534
 
        try:
1535
 
            f.write('just a small update')
1536
 
        finally:
1537
 
            f.close()
 
1536
        with open(name0u, 'ab') as f:
 
1537
            f.write(b'just a small update')
1538
1538
 
1539
1539
        result = Win32ReadDir().read_dir('', u'.')
1540
1540
        entry = result[0]
1633
1633
        # using the comparison routine shoudl work too:
1634
1634
        self.assertEqual(
1635
1635
            dir_sorted_paths,
1636
 
            sorted(original_paths, cmp=osutils.compare_paths_prefix_order))
 
1636
            sorted(original_paths, key=osutils.path_prefix_key))
1637
1637
 
1638
1638
 
1639
1639
class TestCopyTree(tests.TestCaseInTempDir):
1662
1662
    def test_copy_tree_handlers(self):
1663
1663
        processed_files = []
1664
1664
        processed_links = []
 
1665
 
1665
1666
        def file_handler(from_path, to_path):
1666
1667
            processed_files.append(('f', from_path, to_path))
 
1668
 
1667
1669
        def dir_handler(from_path, to_path):
1668
1670
            processed_files.append(('d', from_path, to_path))
 
1671
 
1669
1672
        def link_handler(from_path, to_path):
1670
1673
            processed_links.append((from_path, to_path))
1671
1674
        handlers = {'file': file_handler,
1672
1675
                    'directory': dir_handler,
1673
1676
                    'symlink': link_handler,
1674
 
                   }
 
1677
                    }
1675
1678
 
1676
1679
        self.build_tree(['source/', 'source/a', 'source/b/', 'source/b/c'])
1677
1680
        if osutils.has_symlinks():
1682
1685
                          ('f', 'source/a', 'target/a'),
1683
1686
                          ('d', 'source/b', 'target/b'),
1684
1687
                          ('f', 'source/b/c', 'target/b/c'),
1685
 
                         ], processed_files)
 
1688
                          ], processed_files)
1686
1689
        self.assertPathDoesNotExist('target')
1687
1690
        if osutils.has_symlinks():
1688
1691
            self.assertEqual([('source/lnk', 'target/lnk')], processed_links)
1697
1700
        self.assertEqual(None, os.environ.get('BRZ_TEST_ENV_VAR'),
1698
1701
                         'Environment was not cleaned up properly.'
1699
1702
                         ' Variable BRZ_TEST_ENV_VAR should not exist.')
 
1703
 
1700
1704
        def cleanup():
1701
1705
            if 'BRZ_TEST_ENV_VAR' in os.environ:
1702
1706
                del os.environ['BRZ_TEST_ENV_VAR']
1726
1730
                'Cannot find a unicode character that works in encoding %s'
1727
1731
                % (osutils.get_user_encoding(),))
1728
1732
 
1729
 
        old = osutils.set_or_unset_env('BRZ_TEST_ENV_VAR', uni_val)
1730
 
        self.assertEqual(env_val, os.environ.get('BRZ_TEST_ENV_VAR'))
 
1733
        osutils.set_or_unset_env('BRZ_TEST_ENV_VAR', uni_val)
 
1734
        self.assertEqual(uni_val, os.environ.get('BRZ_TEST_ENV_VAR'))
1731
1735
 
1732
1736
    def test_unset(self):
1733
1737
        """Test that passing None will remove the env var"""
1735
1739
        old = osutils.set_or_unset_env('BRZ_TEST_ENV_VAR', None)
1736
1740
        self.assertEqual('foo', old)
1737
1741
        self.assertEqual(None, os.environ.get('BRZ_TEST_ENV_VAR'))
1738
 
        self.assertFalse('BRZ_TEST_ENV_VAR' in os.environ)
 
1742
        self.assertNotIn('BRZ_TEST_ENV_VAR', os.environ)
1739
1743
 
1740
1744
 
1741
1745
class TestSizeShaFile(tests.TestCaseInTempDir):
1742
1746
 
1743
1747
    def test_sha_empty(self):
1744
 
        self.build_tree_contents([('foo', '')])
1745
 
        expected_sha = osutils.sha_string('')
 
1748
        self.build_tree_contents([('foo', b'')])
 
1749
        expected_sha = osutils.sha_string(b'')
1746
1750
        f = open('foo')
1747
1751
        self.addCleanup(f.close)
1748
1752
        size, sha = osutils.size_sha_file(f)
1750
1754
        self.assertEqual(expected_sha, sha)
1751
1755
 
1752
1756
    def test_sha_mixed_endings(self):
1753
 
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
 
1757
        text = b'test\r\nwith\nall\rpossible line endings\r\n'
1754
1758
        self.build_tree_contents([('foo', text)])
1755
1759
        expected_sha = osutils.sha_string(text)
1756
1760
        f = open('foo', 'rb')
1763
1767
class TestShaFileByName(tests.TestCaseInTempDir):
1764
1768
 
1765
1769
    def test_sha_empty(self):
1766
 
        self.build_tree_contents([('foo', '')])
1767
 
        expected_sha = osutils.sha_string('')
 
1770
        self.build_tree_contents([('foo', b'')])
 
1771
        expected_sha = osutils.sha_string(b'')
1768
1772
        self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1769
1773
 
1770
1774
    def test_sha_mixed_endings(self):
1771
 
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
 
1775
        text = b'test\r\nwith\nall\rpossible line endings\r\n'
1772
1776
        self.build_tree_contents([('foo', text)])
1773
1777
        expected_sha = osutils.sha_string(text)
1774
1778
        self.assertEqual(expected_sha, osutils.sha_file_by_name('foo'))
1785
1789
        self.assertContainsRe(text, "class TextUIFactory")
1786
1790
        # test unsupported package
1787
1791
        self.assertRaises(errors.BzrError, osutils.resource_string, 'zzzz',
1788
 
            'yyy.xx')
 
1792
                          'yyy.xx')
1789
1793
        # test unknown resource
1790
1794
        self.assertRaises(IOError, osutils.resource_string, 'breezy', 'yyy.xx')
1791
1795
 
1812
1816
            '2file'
1813
1817
            ]
1814
1818
        expected_dirblocks = [
1815
 
                (('', '.'),
1816
 
                 [('0file', '0file', 'file'),
1817
 
                  ('1dir', '1dir', 'directory'),
1818
 
                  ('2file', '2file', 'file'),
1819
 
                 ]
1820
 
                ),
1821
 
                (('1dir', './1dir'),
1822
 
                 [('1dir/0file', '0file', 'file'),
1823
 
                  ('1dir/1dir', '1dir', 'directory'),
1824
 
                 ]
1825
 
                ),
1826
 
                (('1dir/1dir', './1dir/1dir'),
1827
 
                 [
1828
 
                 ]
1829
 
                ),
 
1819
            ((b'', '.'),
 
1820
             [(b'0file', b'0file', 'file', './0file'),
 
1821
              (b'1dir', b'1dir', 'directory', './1dir'),
 
1822
              (b'2file', b'2file', 'file', './2file'),
 
1823
              ]
 
1824
             ),
 
1825
            ((b'1dir', './1dir'),
 
1826
             [(b'1dir/0file', b'0file', 'file', './1dir/0file'),
 
1827
              (b'1dir/1dir', b'1dir', 'directory', './1dir/1dir'),
 
1828
              ]
 
1829
             ),
 
1830
            ((b'1dir/1dir', './1dir/1dir'),
 
1831
             [
 
1832
                ]
 
1833
             ),
1830
1834
            ]
1831
1835
        return tree, expected_dirblocks
1832
1836
 
1836
1840
        result = list(osutils._walkdirs_utf8('.'))
1837
1841
        # Filter out stat and abspath
1838
1842
        self.assertEqual(expected_dirblocks,
1839
 
                         [(dirinfo, [line[0:3] for line in block])
1840
 
                          for dirinfo, block in result])
 
1843
                         self._filter_out(result))
1841
1844
 
1842
1845
    def test_walk_sub_dir(self):
1843
1846
        tree, expected_dirblocks = self._get_ascii_tree()
1844
1847
        self.build_tree(tree)
1845
1848
        # you can search a subdir only, with a supplied prefix.
1846
 
        result = list(osutils._walkdirs_utf8('./1dir', '1dir'))
 
1849
        result = list(osutils._walkdirs_utf8(b'./1dir', b'1dir'))
1847
1850
        # Filter out stat and abspath
1848
1851
        self.assertEqual(expected_dirblocks[1:],
1849
 
                         [(dirinfo, [line[0:3] for line in block])
1850
 
                          for dirinfo, block in result])
 
1852
                         self._filter_out(result))
1851
1853
 
1852
1854
    def _get_unicode_tree(self):
1853
1855
        name0u = u'0file-\xb6'
1864
1866
        name1 = name1u.encode('UTF-8')
1865
1867
        name2 = name2u.encode('UTF-8')
1866
1868
        expected_dirblocks = [
1867
 
                (('', '.'),
1868
 
                 [(name0, name0, 'file', './' + name0u),
1869
 
                  (name1, name1, 'directory', './' + name1u),
1870
 
                  (name2, name2, 'file', './' + name2u),
1871
 
                 ]
1872
 
                ),
1873
 
                ((name1, './' + name1u),
1874
 
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
1875
 
                                                        + '/' + name0u),
1876
 
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
1877
 
                                                            + '/' + name1u),
1878
 
                 ]
1879
 
                ),
1880
 
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
1881
 
                 [
1882
 
                 ]
1883
 
                ),
 
1869
            ((b'', '.'),
 
1870
             [(name0, name0, 'file', './' + name0u),
 
1871
              (name1, name1, 'directory', './' + name1u),
 
1872
              (name2, name2, 'file', './' + name2u),
 
1873
              ]
 
1874
             ),
 
1875
            ((name1, './' + name1u),
 
1876
             [(name1 + b'/' + name0, name0, 'file', './' + name1u
 
1877
               + '/' + name0u),
 
1878
              (name1 + b'/' + name1, name1, 'directory', './' + name1u
 
1879
               + '/' + name1u),
 
1880
              ]
 
1881
             ),
 
1882
            ((name1 + b'/' + name1, './' + name1u + '/' + name1u),
 
1883
             [
 
1884
                ]
 
1885
             ),
1884
1886
            ]
1885
1887
        return tree, expected_dirblocks
1886
1888
 
1894
1896
            dirinfo = (dirinfo[0], self._native_to_unicode(dirinfo[1]))
1895
1897
            details = []
1896
1898
            for line in block:
1897
 
                details.append(line[0:3] + (self._native_to_unicode(line[4]), ))
 
1899
                details.append(
 
1900
                    line[0:3] + (self._native_to_unicode(line[4]), ))
1898
1901
            filtered_dirblocks.append((dirinfo, details))
1899
1902
        return filtered_dirblocks
1900
1903
 
1911
1914
        target = u'target\N{Euro Sign}'
1912
1915
        link_name = u'l\N{Euro Sign}nk'
1913
1916
        os.symlink(target, link_name)
1914
 
        target_utf8 = target.encode('UTF-8')
1915
1917
        link_name_utf8 = link_name.encode('UTF-8')
1916
1918
        expected_dirblocks = [
1917
 
                (('', '.'),
1918
 
                 [(link_name_utf8, link_name_utf8,
1919
 
                   'symlink', './' + link_name),],
1920
 
                 )]
 
1919
            ((b'', '.'),
 
1920
             [(link_name_utf8, link_name_utf8,
 
1921
               'symlink', './' + link_name), ],
 
1922
             )]
1921
1923
        result = list(osutils._walkdirs_utf8('.'))
1922
1924
        self.assertEqual(expected_dirblocks, self._filter_out(result))
1923
1925
 
1931
1933
    But prior python versions failed to properly encode the passed unicode
1932
1934
    string.
1933
1935
    """
1934
 
    _test_needs_features = [features.SymlinkFeature, features.UnicodeFilenameFeature]
 
1936
    _test_needs_features = [features.SymlinkFeature,
 
1937
                            features.UnicodeFilenameFeature]
1935
1938
 
1936
1939
    def setUp(self):
1937
1940
        super(tests.TestCaseInTempDir, self).setUp()
1940
1943
        os.symlink(self.target, self.link)
1941
1944
 
1942
1945
    def test_os_readlink_link_encoding(self):
1943
 
        self.assertEqual(self.target,  os.readlink(self.link))
 
1946
        self.assertEqual(self.target, os.readlink(self.link))
1944
1947
 
1945
1948
    def test_os_readlink_link_decoding(self):
1946
1949
        self.assertEqual(self.target.encode(osutils._fs_enc),
1947
 
                          os.readlink(self.link.encode(osutils._fs_enc)))
 
1950
                         os.readlink(self.link.encode(osutils._fs_enc)))
1948
1951
 
1949
1952
 
1950
1953
class TestConcurrency(tests.TestCase):
1977
1980
 
1978
1981
    def _try_loading(self):
1979
1982
        try:
1980
 
            import breezy._fictional_extension_py
 
1983
            import breezy._fictional_extension_py  # noqa: F401
1981
1984
        except ImportError as e:
1982
1985
            osutils.failed_to_load_extension(e)
1983
1986
            return True
1989
1992
    def test_failure_to_load(self):
1990
1993
        self._try_loading()
1991
1994
        self.assertLength(1, osutils._extension_load_failures)
1992
 
        self.assertEqual(osutils._extension_load_failures[0],
1993
 
            "No module named _fictional_extension_py")
 
1995
        self.assertEqual(
 
1996
            osutils._extension_load_failures[0],
 
1997
            "No module named 'breezy._fictional_extension_py'")
1994
1998
 
1995
1999
    def test_report_extension_load_failures_no_warning(self):
1996
2000
        self.assertTrue(self._try_loading())
1997
 
        warnings, result = self.callCatchWarnings(osutils.report_extension_load_failures)
 
2001
        warnings, result = self.callCatchWarnings(
 
2002
            osutils.report_extension_load_failures)
1998
2003
        # it used to give a Python warning; it no longer does
1999
2004
        self.assertLength(0, warnings)
2000
2005
 
2005
2010
        osutils.report_extension_load_failures()
2006
2011
        self.assertContainsRe(
2007
2012
            log.getvalue(),
2008
 
            r"brz: warning: some compiled extensions could not be loaded; "
2009
 
            "see ``brz help missing-extensions``\n"
 
2013
            br"brz: warning: some compiled extensions could not be loaded; "
 
2014
            b"see ``brz help missing-extensions``\n"
2010
2015
            )
2011
2016
 
2012
2017
 
2083
2088
        termios = term_ios_feature.module
2084
2089
        # bug 63539 is about a termios without TIOCGWINSZ attribute
2085
2090
        try:
2086
 
            orig = termios.TIOCGWINSZ
 
2091
            termios.TIOCGWINSZ
2087
2092
        except AttributeError:
2088
2093
            # We won't remove TIOCGWINSZ, because it doesn't exist anyway :)
2089
2094
            pass
2112
2117
    def test_copy_ownership_from_path(self):
2113
2118
        """copy_ownership_from_path test with specified src."""
2114
2119
        ownsrc = '/'
2115
 
        f = open('test_file', 'wt')
 
2120
        open('test_file', 'wt').close()
2116
2121
        osutils.copy_ownership_from_path('test_file', ownsrc)
2117
2122
 
2118
2123
        s = os.stat(ownsrc)
2122
2127
 
2123
2128
    def test_copy_ownership_nonesrc(self):
2124
2129
        """copy_ownership_from_path test with src=None."""
2125
 
        f = open('test_file', 'wt')
 
2130
        open('test_file', 'wt').close()
2126
2131
        # should use parent dir for permissions
2127
2132
        osutils.copy_ownership_from_path('test_file')
2128
2133
 
2137
2142
    def test_is_unicode(self):
2138
2143
        self.overrideEnv('BRZ_TEST_PATH', './anywhere at all/')
2139
2144
        path = osutils.path_from_environ('BRZ_TEST_PATH')
2140
 
        self.assertIsInstance(path, unicode)
 
2145
        self.assertIsInstance(path, str)
2141
2146
        self.assertEqual(u'./anywhere at all/', path)
2142
2147
 
2143
2148
    def test_posix_path_env_ascii(self):
2144
2149
        self.overrideEnv('BRZ_TEST_PATH', '/tmp')
2145
2150
        home = osutils._posix_path_from_environ('BRZ_TEST_PATH')
2146
 
        self.assertIsInstance(home, unicode)
 
2151
        self.assertIsInstance(home, str)
2147
2152
        self.assertEqual(u'/tmp', home)
2148
2153
 
2149
2154
    def test_posix_path_env_unicode(self):
2151
2156
        self.overrideEnv('BRZ_TEST_PATH', '/home/\xa7test')
2152
2157
        self.overrideAttr(osutils, "_fs_enc", "iso8859-1")
2153
2158
        self.assertEqual(u'/home/\xa7test',
2154
 
            osutils._posix_path_from_environ('BRZ_TEST_PATH'))
 
2159
                         osutils._posix_path_from_environ('BRZ_TEST_PATH'))
2155
2160
        osutils._fs_enc = "iso8859-5"
2156
 
        self.assertEqual(u'/home/\u0407test',
2157
 
            osutils._posix_path_from_environ('BRZ_TEST_PATH'))
2158
 
        osutils._fs_enc = "utf-8"
2159
 
        self.assertRaises(errors.BadFilenameEncoding,
2160
 
            osutils._posix_path_from_environ, 'BRZ_TEST_PATH')
 
2161
        # In Python 3, os.environ returns unicode.
 
2162
        self.assertEqual(u'/home/\xa7test',
 
2163
                         osutils._posix_path_from_environ('BRZ_TEST_PATH'))
2161
2164
 
2162
2165
 
2163
2166
class TestGetHomeDir(tests.TestCase):
2164
2167
 
2165
2168
    def test_is_unicode(self):
2166
2169
        home = osutils._get_home_dir()
2167
 
        self.assertIsInstance(home, unicode)
 
2170
        self.assertIsInstance(home, str)
2168
2171
 
2169
2172
    def test_posix_homeless(self):
2170
2173
        self.overrideEnv('HOME', None)
2171
2174
        home = osutils._get_home_dir()
2172
 
        self.assertIsInstance(home, unicode)
 
2175
        self.assertIsInstance(home, str)
2173
2176
 
2174
2177
    def test_posix_home_ascii(self):
2175
2178
        self.overrideEnv('HOME', '/home/test')
2176
2179
        home = osutils._posix_get_home_dir()
2177
 
        self.assertIsInstance(home, unicode)
 
2180
        self.assertIsInstance(home, str)
2178
2181
        self.assertEqual(u'/home/test', home)
2179
2182
 
2180
2183
    def test_posix_home_unicode(self):
2183
2186
        self.overrideAttr(osutils, "_fs_enc", "iso8859-1")
2184
2187
        self.assertEqual(u'/home/\xa7test', osutils._posix_get_home_dir())
2185
2188
        osutils._fs_enc = "iso8859-5"
2186
 
        self.assertEqual(u'/home/\u0407test', osutils._posix_get_home_dir())
2187
 
        osutils._fs_enc = "utf-8"
2188
 
        self.assertRaises(errors.BadFilenameEncoding,
2189
 
            osutils._posix_get_home_dir)
 
2189
        # In python 3, os.environ returns unicode
 
2190
        self.assertEqual(u'/home/\xa7test', osutils._posix_get_home_dir())
2190
2191
 
2191
2192
 
2192
2193
class TestGetuserUnicode(tests.TestCase):
2193
2194
 
2194
2195
    def test_is_unicode(self):
2195
2196
        user = osutils.getuser_unicode()
2196
 
        self.assertIsInstance(user, unicode)
 
2197
        self.assertIsInstance(user, str)
2197
2198
 
2198
2199
    def envvar_to_override(self):
2199
2200
        if sys.platform == "win32":
2200
2201
            # Disable use of platform calls on windows so envvar is used
2201
2202
            self.overrideAttr(win32utils, 'has_ctypes', False)
2202
 
            return 'USERNAME' # only variable used on windows
2203
 
        return 'LOGNAME' # first variable checked by getpass.getuser()
 
2203
            return 'USERNAME'  # only variable used on windows
 
2204
        return 'LOGNAME'  # first variable checked by getpass.getuser()
2204
2205
 
2205
2206
    def test_ascii_user(self):
2206
2207
        self.overrideEnv(self.envvar_to_override(), 'jrandom')
2215
2216
                % (osutils.get_user_encoding(),))
2216
2217
        uni_username = u'jrandom' + uni_val
2217
2218
        encoded_username = uni_username.encode(ue)
2218
 
        self.overrideEnv(self.envvar_to_override(), encoded_username)
 
2219
        self.overrideEnv(self.envvar_to_override(), uni_username)
2219
2220
        self.assertEqual(uni_username, osutils.getuser_unicode())
2220
2221
 
2221
2222
 
2254
2255
    def test_windows(self):
2255
2256
        if sys.platform != 'win32':
2256
2257
            raise tests.TestSkipped('test requires win32')
2257
 
        self.assertTrue(osutils.find_executable_on_path('explorer') is not None)
 
2258
        self.assertTrue(osutils.find_executable_on_path(
 
2259
            'explorer') is not None)
2258
2260
        self.assertTrue(
2259
2261
            osutils.find_executable_on_path('explorer.exe') is not None)
2260
2262
        self.assertTrue(
2262
2264
        self.assertTrue(
2263
2265
            osutils.find_executable_on_path('THIS SHOULD NOT EXIST') is None)
2264
2266
        self.assertTrue(osutils.find_executable_on_path('file.txt') is None)
2265
 
        
 
2267
 
2266
2268
    def test_windows_app_path(self):
2267
2269
        if sys.platform != 'win32':
2268
2270
            raise tests.TestSkipped('test requires win32')
2269
2271
        # Override PATH env var so that exe can only be found on App Path
2270
2272
        self.overrideEnv('PATH', '')
2271
2273
        # Internt Explorer is always registered in the App Path
2272
 
        self.assertTrue(osutils.find_executable_on_path('iexplore') is not None)
 
2274
        self.assertTrue(osutils.find_executable_on_path(
 
2275
            'iexplore') is not None)
2273
2276
 
2274
2277
    def test_other(self):
2275
2278
        if sys.platform == 'win32':
2303
2306
        import pywintypes
2304
2307
        self.assertTrue(osutils.is_environment_error(
2305
2308
            pywintypes.error(errno.EINVAL, "Invalid parameter", "Caller")))
 
2309
 
 
2310
 
 
2311
class SupportsExecutableTests(tests.TestCaseInTempDir):
 
2312
 
 
2313
    def test_returns_bool(self):
 
2314
        self.assertIsInstance(osutils.supports_executable(self.test_dir), bool)
 
2315
 
 
2316
 
 
2317
class SupportsSymlinksTests(tests.TestCaseInTempDir):
 
2318
 
 
2319
    def test_returns_bool(self):
 
2320
        self.assertIsInstance(osutils.supports_symlinks(self.test_dir), bool)
 
2321
 
 
2322
 
 
2323
class MtabReader(tests.TestCaseInTempDir):
 
2324
 
 
2325
    def test_read_mtab(self):
 
2326
        self.build_tree_contents([('mtab', """\
 
2327
/dev/mapper/blah--vg-root / ext4 rw,relatime,errors=remount-ro 0 0
 
2328
/dev/mapper/blah--vg-home /home vfat rw,relatime 0 0
 
2329
# comment
 
2330
 
 
2331
iminvalid
 
2332
""")])
 
2333
        self.assertEqual(
 
2334
            list(osutils.read_mtab('mtab')),
 
2335
            [(b'/', 'ext4'),
 
2336
             (b'/home', 'vfat')])
 
2337
 
 
2338
 
 
2339
class GetFsTypeTests(tests.TestCaseInTempDir):
 
2340
 
 
2341
    def test_returns_string_or_none(self):
 
2342
        ret = osutils.get_fs_type(self.test_dir)
 
2343
        self.assertTrue(isinstance(ret, str) or ret is None)
 
2344
 
 
2345
    def test_returns_most_specific(self):
 
2346
        self.overrideAttr(
 
2347
            osutils, '_FILESYSTEM_FINDER',
 
2348
            osutils.FilesystemFinder(
 
2349
                [(b'/', 'ext4'), (b'/home', 'vfat'),
 
2350
                 (b'/home/jelmer', 'ext2')]))
 
2351
        self.assertEqual(osutils.get_fs_type(b'/home/jelmer/blah'), 'ext2')
 
2352
        self.assertEqual(osutils.get_fs_type('/home/jelmer/blah'), 'ext2')
 
2353
        self.assertEqual(osutils.get_fs_type(b'/home/jelmer'), 'ext2')
 
2354
        self.assertEqual(osutils.get_fs_type(b'/home/martin'), 'vfat')
 
2355
        self.assertEqual(osutils.get_fs_type(b'/home'), 'vfat')
 
2356
        self.assertEqual(osutils.get_fs_type(b'/other'), 'ext4')
 
2357
 
 
2358
    def test_returns_none(self):
 
2359
        self.overrideAttr(
 
2360
            osutils, '_FILESYSTEM_FINDER',
 
2361
            osutils.FilesystemFinder([]))
 
2362
        self.assertIs(osutils.get_fs_type('/home/jelmer/blah'), None)
 
2363
        self.assertIs(osutils.get_fs_type(b'/home/jelmer/blah'), None)
 
2364
        self.assertIs(osutils.get_fs_type('/home/jelmer'), None)