~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_osutils.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-05-05 19:55:59 UTC
  • mfrom: (4331.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090505195559-0qmeyyua7e407sym
(vila) Parametrize tests against dir readers and fix some unicode
        symlink latent bugs

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
UTF8DirReaderFeature = _UTF8DirReaderFeature()
54
54
 
55
55
 
56
 
class TestOSUtils(tests.TestCaseInTempDir):
 
56
def _already_unicode(s):
 
57
    return s
 
58
 
 
59
 
 
60
def _fs_enc_to_unicode(s):
 
61
    return s.decode(osutils._fs_enc)
 
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.Win32ReadDirFeature.available():
 
87
        try:
 
88
            from bzrlib import _walkdirs_win32
 
89
            # TODO: check on windows, it may be that we need to use/add
 
90
            # safe_unicode instead of _fs_enc_to_unicode
 
91
            scenarios.append(
 
92
                ('win32',
 
93
                 dict(_dir_reader_class=_walkdirs_win32.Win32ReadDir,
 
94
                      _native_to_unicode=_fs_enc_to_unicode)))
 
95
        except ImportError:
 
96
            pass
 
97
    return scenarios
 
98
 
 
99
 
 
100
def load_tests(basic_tests, module, loader):
 
101
    suite = loader.suiteClass()
 
102
    dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
 
103
        basic_tests, tests.condition_isinstance(TestDirReader))
 
104
    tests.multiply_tests(dir_reader_tests, dir_reader_scenarios(), suite)
 
105
    suite.addTest(remaining_tests)
 
106
    return suite
 
107
 
 
108
 
 
109
class TestContainsWhitespace(tests.TestCase):
57
110
 
58
111
    def test_contains_whitespace(self):
59
112
        self.failUnless(osutils.contains_whitespace(u' '))
69
122
        self.failIf(osutils.contains_whitespace(u'hellothere'))
70
123
        self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
71
124
 
 
125
 
 
126
class TestRename(tests.TestCaseInTempDir):
 
127
 
72
128
    def test_fancy_rename(self):
73
129
        # This should work everywhere
74
130
        def rename(a, b):
112
168
        shape = sorted(os.listdir('.'))
113
169
        self.assertEquals(['A', 'B'], shape)
114
170
 
 
171
 
 
172
class TestRandChars(tests.TestCase):
 
173
 
115
174
    def test_01_rand_chars_empty(self):
116
175
        result = osutils.rand_chars(0)
117
176
        self.assertEqual(result, '')
122
181
        self.assertEqual(type(result), str)
123
182
        self.assertContainsRe(result, r'^[a-z0-9]{100}$')
124
183
 
 
184
 
 
185
class TestIsInside(tests.TestCase):
 
186
 
125
187
    def test_is_inside(self):
126
188
        is_inside = osutils.is_inside
127
189
        self.assertTrue(is_inside('src', 'src/foo.c'))
156
218
                         (['src'], 'srccontrol/foo')]:
157
219
            self.assertFalse(osutils.is_inside_or_parent_of_any(dirs, fn))
158
220
 
 
221
 
 
222
class TestRmTree(tests.TestCaseInTempDir):
 
223
 
159
224
    def test_rmtree(self):
160
225
        # Check to remove tree with read-only files/dirs
161
226
        os.mkdir('dir')
174
239
        self.failIfExists('dir/file')
175
240
        self.failIfExists('dir')
176
241
 
 
242
 
 
243
class TestKind(tests.TestCaseInTempDir):
 
244
 
177
245
    def test_file_kind(self):
178
246
        self.build_tree(['file', 'dir/'])
179
247
        self.assertEquals('file', osutils.file_kind('file'))
209
277
                os.remove('socket')
210
278
 
211
279
    def test_kind_marker(self):
212
 
        self.assertEqual(osutils.kind_marker('file'), '')
213
 
        self.assertEqual(osutils.kind_marker('directory'), '/')
214
 
        self.assertEqual(osutils.kind_marker('symlink'), '@')
215
 
        self.assertEqual(osutils.kind_marker('tree-reference'), '+')
 
280
        self.assertEqual("", osutils.kind_marker("file"))
 
281
        self.assertEqual("/", osutils.kind_marker('directory'))
 
282
        self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
 
283
        self.assertEqual("@", osutils.kind_marker("symlink"))
 
284
        self.assertEqual("+", osutils.kind_marker("tree-reference"))
 
285
        self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
 
286
 
 
287
 
 
288
class TestUmask(tests.TestCaseInTempDir):
216
289
 
217
290
    def test_get_umask(self):
218
291
        if sys.platform == 'win32':
231
304
        os.umask(0027)
232
305
        self.assertEqual(0027, osutils.get_umask())
233
306
 
 
307
 
 
308
class TestDateTime(tests.TestCase):
 
309
 
234
310
    def assertFormatedDelta(self, expected, seconds):
235
311
        """Assert osutils.format_delta formats as expected"""
236
312
        actual = osutils.format_delta(seconds)
277
353
        # Instead blackbox.test_locale should check for localized
278
354
        # dates once they do occur in output strings.
279
355
 
 
356
    def test_local_time_offset(self):
 
357
        """Test that local_time_offset() returns a sane value."""
 
358
        offset = osutils.local_time_offset()
 
359
        self.assertTrue(isinstance(offset, int))
 
360
        # Test that the offset is no more than a eighteen hours in
 
361
        # either direction.
 
362
        # Time zone handling is system specific, so it is difficult to
 
363
        # do more specific tests, but a value outside of this range is
 
364
        # probably wrong.
 
365
        eighteen_hours = 18 * 3600
 
366
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
367
 
 
368
    def test_local_time_offset_with_timestamp(self):
 
369
        """Test that local_time_offset() works with a timestamp."""
 
370
        offset = osutils.local_time_offset(1000000000.1234567)
 
371
        self.assertTrue(isinstance(offset, int))
 
372
        eighteen_hours = 18 * 3600
 
373
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
 
374
 
 
375
 
 
376
class TestLinks(tests.TestCaseInTempDir):
 
377
 
280
378
    def test_dereference_path(self):
281
379
        self.requireFeature(tests.SymlinkFeature)
282
380
        cwd = osutils.realpath('.')
325
423
            osutils.make_readonly('dangling')
326
424
            osutils.make_writable('dangling')
327
425
 
328
 
    def test_kind_marker(self):
329
 
        self.assertEqual("", osutils.kind_marker("file"))
330
 
        self.assertEqual("/", osutils.kind_marker(osutils._directory_kind))
331
 
        self.assertEqual("@", osutils.kind_marker("symlink"))
332
 
        self.assertRaises(errors.BzrError, osutils.kind_marker, "unknown")
333
 
 
334
426
    def test_host_os_dereferences_symlinks(self):
335
427
        osutils.host_os_dereferences_symlinks()
336
428
 
813
905
 
814
906
class TestWalkDirs(tests.TestCaseInTempDir):
815
907
 
 
908
    def assertExpectedBlocks(self, expected, result):
 
909
        self.assertEqual(expected,
 
910
                         [(dirinfo, [line[0:3] for line in block])
 
911
                          for dirinfo, block in result])
 
912
 
816
913
    def test_walkdirs(self):
817
914
        tree = [
818
915
            '.bzr',
850
947
            result.append((dirdetail, dirblock))
851
948
 
852
949
        self.assertTrue(found_bzrdir)
853
 
        self.assertEqual(expected_dirblocks,
854
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
950
        self.assertExpectedBlocks(expected_dirblocks, result)
855
951
        # you can search a subdir only, with a supplied prefix.
856
952
        result = []
857
953
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
858
954
            result.append(dirblock)
859
 
        self.assertEqual(expected_dirblocks[1:],
860
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
955
        self.assertExpectedBlocks(expected_dirblocks[1:], result)
861
956
 
862
957
    def test_walkdirs_os_error(self):
863
958
        # <https://bugs.edge.launchpad.net/bzr/+bug/338653>
869
964
        os.mkdir("test-unreadable")
870
965
        os.chmod("test-unreadable", 0000)
871
966
        # must chmod it back so that it can be removed
872
 
        self.addCleanup(lambda: os.chmod("test-unreadable", 0700))
 
967
        self.addCleanup(os.chmod, "test-unreadable", 0700)
873
968
        # The error is not raised until the generator is actually evaluated.
874
969
        # (It would be ok if it happened earlier but at the moment it
875
970
        # doesn't.)
916
1011
            result.append((dirdetail, dirblock))
917
1012
 
918
1013
        self.assertTrue(found_bzrdir)
919
 
        self.assertEqual(expected_dirblocks,
920
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1014
        self.assertExpectedBlocks(expected_dirblocks, result)
 
1015
 
921
1016
        # you can search a subdir only, with a supplied prefix.
922
1017
        result = []
923
1018
        for dirblock in osutils.walkdirs('./1dir', '1dir'):
924
1019
            result.append(dirblock)
925
 
        self.assertEqual(expected_dirblocks[1:],
926
 
            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
 
1020
        self.assertExpectedBlocks(expected_dirblocks[1:], result)
927
1021
 
928
1022
    def _filter_out_stat(self, result):
929
1023
        """Filter out the stat value from the walkdirs result"""
944
1038
            osutils._selected_dir_reader = cur_dir_reader
945
1039
        self.addCleanup(restore)
946
1040
 
947
 
    def assertReadFSDirIs(self, expected):
 
1041
    def assertDirReaderIs(self, expected):
948
1042
        """Assert the right implementation for _walkdirs_utf8 is chosen."""
949
1043
        # Force it to redetect
950
1044
        osutils._selected_dir_reader = None
957
1051
        self._save_platform_info()
958
1052
        win32utils.winver = None # Avoid the win32 detection code
959
1053
        osutils._fs_enc = 'UTF-8'
960
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1054
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
961
1055
 
962
1056
    def test_force_walkdirs_utf8_fs_ascii(self):
963
1057
        self.requireFeature(UTF8DirReaderFeature)
964
1058
        self._save_platform_info()
965
1059
        win32utils.winver = None # Avoid the win32 detection code
966
1060
        osutils._fs_enc = 'US-ASCII'
967
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1061
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
968
1062
 
969
1063
    def test_force_walkdirs_utf8_fs_ANSI(self):
970
1064
        self.requireFeature(UTF8DirReaderFeature)
971
1065
        self._save_platform_info()
972
1066
        win32utils.winver = None # Avoid the win32 detection code
973
1067
        osutils._fs_enc = 'ANSI_X3.4-1968'
974
 
        self.assertReadFSDirIs(UTF8DirReaderFeature.reader)
 
1068
        self.assertDirReaderIs(UTF8DirReaderFeature.reader)
975
1069
 
976
1070
    def test_force_walkdirs_utf8_fs_latin1(self):
977
1071
        self._save_platform_info()
978
1072
        win32utils.winver = None # Avoid the win32 detection code
979
1073
        osutils._fs_enc = 'latin1'
980
 
        self.assertReadFSDirIs(osutils.UnicodeDirReader)
 
1074
        self.assertDirReaderIs(osutils.UnicodeDirReader)
981
1075
 
982
1076
    def test_force_walkdirs_utf8_nt(self):
983
1077
        # Disabled because the thunk of the whole walkdirs api is disabled.
985
1079
        self._save_platform_info()
986
1080
        win32utils.winver = 'Windows NT'
987
1081
        from bzrlib._walkdirs_win32 import Win32ReadDir
988
 
        self.assertReadFSDirIs(Win32ReadDir)
 
1082
        self.assertDirReaderIs(Win32ReadDir)
989
1083
 
990
1084
    def test_force_walkdirs_utf8_98(self):
991
1085
        self.requireFeature(test__walkdirs_win32.Win32ReadDirFeature)
992
1086
        self._save_platform_info()
993
1087
        win32utils.winver = 'Windows 98'
994
 
        self.assertReadFSDirIs(osutils.UnicodeDirReader)
 
1088
        self.assertDirReaderIs(osutils.UnicodeDirReader)
995
1089
 
996
1090
    def test_unicode_walkdirs(self):
997
1091
        """Walkdirs should always return unicode paths."""
1420
1514
        self.failIf('BZR_TEST_ENV_VAR' in os.environ)
1421
1515
 
1422
1516
 
1423
 
class TestLocalTimeOffset(tests.TestCase):
1424
 
 
1425
 
    def test_local_time_offset(self):
1426
 
        """Test that local_time_offset() returns a sane value."""
1427
 
        offset = osutils.local_time_offset()
1428
 
        self.assertTrue(isinstance(offset, int))
1429
 
        # Test that the offset is no more than a eighteen hours in
1430
 
        # either direction.
1431
 
        # Time zone handling is system specific, so it is difficult to
1432
 
        # do more specific tests, but a value outside of this range is
1433
 
        # probably wrong.
1434
 
        eighteen_hours = 18 * 3600
1435
 
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1436
 
 
1437
 
    def test_local_time_offset_with_timestamp(self):
1438
 
        """Test that local_time_offset() works with a timestamp."""
1439
 
        offset = osutils.local_time_offset(1000000000.1234567)
1440
 
        self.assertTrue(isinstance(offset, int))
1441
 
        eighteen_hours = 18 * 3600
1442
 
        self.assertTrue(-eighteen_hours < offset < eighteen_hours)
1443
 
 
1444
 
 
1445
1517
class TestSizeShaFile(tests.TestCaseInTempDir):
1446
1518
 
1447
1519
    def test_sha_empty(self):
1510
1582
            "Invalid regular expression in test case: '*': "
1511
1583
            "nothing to repeat",
1512
1584
            str(err))
 
1585
 
 
1586
 
 
1587
class TestDirReader(tests.TestCaseInTempDir):
 
1588
 
 
1589
    # Set by load_tests
 
1590
    _dir_reader_class = None
 
1591
    _native_to_unicode = None
 
1592
 
 
1593
    def setUp(self):
 
1594
        tests.TestCaseInTempDir.setUp(self)
 
1595
 
 
1596
        # Save platform specific info and reset it
 
1597
        cur_dir_reader = osutils._selected_dir_reader
 
1598
 
 
1599
        def restore():
 
1600
            osutils._selected_dir_reader = cur_dir_reader
 
1601
        self.addCleanup(restore)
 
1602
 
 
1603
        osutils._selected_dir_reader = self._dir_reader_class()
 
1604
 
 
1605
    def _get_ascii_tree(self):
 
1606
        tree = [
 
1607
            '0file',
 
1608
            '1dir/',
 
1609
            '1dir/0file',
 
1610
            '1dir/1dir/',
 
1611
            '2file'
 
1612
            ]
 
1613
        expected_dirblocks = [
 
1614
                (('', '.'),
 
1615
                 [('0file', '0file', 'file'),
 
1616
                  ('1dir', '1dir', 'directory'),
 
1617
                  ('2file', '2file', 'file'),
 
1618
                 ]
 
1619
                ),
 
1620
                (('1dir', './1dir'),
 
1621
                 [('1dir/0file', '0file', 'file'),
 
1622
                  ('1dir/1dir', '1dir', 'directory'),
 
1623
                 ]
 
1624
                ),
 
1625
                (('1dir/1dir', './1dir/1dir'),
 
1626
                 [
 
1627
                 ]
 
1628
                ),
 
1629
            ]
 
1630
        return tree, expected_dirblocks
 
1631
 
 
1632
    def test_walk_cur_dir(self):
 
1633
        tree, expected_dirblocks = self._get_ascii_tree()
 
1634
        self.build_tree(tree)
 
1635
        result = list(osutils._walkdirs_utf8('.'))
 
1636
        # Filter out stat and abspath
 
1637
        self.assertEqual(expected_dirblocks,
 
1638
                         [(dirinfo, [line[0:3] for line in block])
 
1639
                          for dirinfo, block in result])
 
1640
 
 
1641
    def test_walk_sub_dir(self):
 
1642
        tree, expected_dirblocks = self._get_ascii_tree()
 
1643
        self.build_tree(tree)
 
1644
        # you can search a subdir only, with a supplied prefix.
 
1645
        result = list(osutils._walkdirs_utf8('./1dir', '1dir'))
 
1646
        # Filter out stat and abspath
 
1647
        self.assertEqual(expected_dirblocks[1:],
 
1648
                         [(dirinfo, [line[0:3] for line in block])
 
1649
                          for dirinfo, block in result])
 
1650
 
 
1651
    def _get_unicode_tree(self):
 
1652
        name0u = u'0file-\xb6'
 
1653
        name1u = u'1dir-\u062c\u0648'
 
1654
        name2u = u'2file-\u0633'
 
1655
        tree = [
 
1656
            name0u,
 
1657
            name1u + '/',
 
1658
            name1u + '/' + name0u,
 
1659
            name1u + '/' + name1u + '/',
 
1660
            name2u,
 
1661
            ]
 
1662
        name0 = name0u.encode('UTF-8')
 
1663
        name1 = name1u.encode('UTF-8')
 
1664
        name2 = name2u.encode('UTF-8')
 
1665
        expected_dirblocks = [
 
1666
                (('', '.'),
 
1667
                 [(name0, name0, 'file', './' + name0u),
 
1668
                  (name1, name1, 'directory', './' + name1u),
 
1669
                  (name2, name2, 'file', './' + name2u),
 
1670
                 ]
 
1671
                ),
 
1672
                ((name1, './' + name1u),
 
1673
                 [(name1 + '/' + name0, name0, 'file', './' + name1u
 
1674
                                                        + '/' + name0u),
 
1675
                  (name1 + '/' + name1, name1, 'directory', './' + name1u
 
1676
                                                            + '/' + name1u),
 
1677
                 ]
 
1678
                ),
 
1679
                ((name1 + '/' + name1, './' + name1u + '/' + name1u),
 
1680
                 [
 
1681
                 ]
 
1682
                ),
 
1683
            ]
 
1684
        return tree, expected_dirblocks
 
1685
 
 
1686
    def _filter_out(self, raw_dirblocks):
 
1687
        """Filter out a walkdirs_utf8 result.
 
1688
 
 
1689
        stat field is removed, all native paths are converted to unicode
 
1690
        """
 
1691
        filtered_dirblocks = []
 
1692
        for dirinfo, block in raw_dirblocks:
 
1693
            dirinfo = (dirinfo[0], self._native_to_unicode(dirinfo[1]))
 
1694
            details = []
 
1695
            for line in block:
 
1696
                details.append(line[0:3] + (self._native_to_unicode(line[4]), ))
 
1697
            filtered_dirblocks.append((dirinfo, details))
 
1698
        return filtered_dirblocks
 
1699
 
 
1700
    def test_walk_unicode_tree(self):
 
1701
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1702
        tree, expected_dirblocks = self._get_unicode_tree()
 
1703
        self.build_tree(tree)
 
1704
        result = list(osutils._walkdirs_utf8('.'))
 
1705
        self.assertEqual(expected_dirblocks, self._filter_out(result))
 
1706
 
 
1707
    def test_symlink(self):
 
1708
        self.requireFeature(tests.SymlinkFeature)
 
1709
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1710
        target = u'target\N{Euro Sign}'
 
1711
        link_name = u'l\N{Euro Sign}nk'
 
1712
        os.symlink(target, link_name)
 
1713
        target_utf8 = target.encode('UTF-8')
 
1714
        link_name_utf8 = link_name.encode('UTF-8')
 
1715
        expected_dirblocks = [
 
1716
                (('', '.'),
 
1717
                 [(link_name_utf8, link_name_utf8,
 
1718
                   'symlink', './' + link_name),],
 
1719
                 )]
 
1720
        result = list(osutils._walkdirs_utf8('.'))
 
1721
        self.assertEqual(expected_dirblocks, self._filter_out(result))
 
1722
 
 
1723
 
 
1724
class TestReadLink(tests.TestCaseInTempDir):
 
1725
    """Exposes os.readlink() problems and the osutils solution.
 
1726
 
 
1727
    The only guarantee offered by os.readlink(), starting with 2.6, is that a
 
1728
    unicode string will be returned if a unicode string is passed.
 
1729
 
 
1730
    But prior python versions failed to properly encode the passed unicode
 
1731
    string.
 
1732
    """
 
1733
    _test_needs_features = [tests.SymlinkFeature, tests.UnicodeFilenameFeature]
 
1734
 
 
1735
    def setUp(self):
 
1736
        super(tests.TestCaseInTempDir, self).setUp()
 
1737
        self.link = u'l\N{Euro Sign}ink'
 
1738
        self.target = u'targe\N{Euro Sign}t'
 
1739
        os.symlink(self.target, self.link)
 
1740
 
 
1741
    def test_os_readlink_link_encoding(self):
 
1742
        if sys.version_info < (2, 6):
 
1743
            self.assertRaises(UnicodeEncodeError, os.readlink, self.link)
 
1744
        else:
 
1745
            self.assertEquals(self.target,  os.readlink(self.link))
 
1746
 
 
1747
    def test_os_readlink_link_decoding(self):
 
1748
        self.assertEquals(self.target.encode(osutils._fs_enc),
 
1749
                          os.readlink(self.link.encode(osutils._fs_enc)))