~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_dirstate.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-06-05 04:05:05 UTC
  • mfrom: (3473.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080605040505-i9kqxg2fps2qjdi0
Add the 'alias' command (Tim Penhey)

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
import bisect
20
20
import os
 
21
import time
21
22
 
22
23
from bzrlib import (
23
24
    dirstate,
24
25
    errors,
25
 
    inventory,
26
26
    osutils,
27
 
    revision as _mod_revision,
28
27
    )
29
28
from bzrlib.memorytree import MemoryTree
30
29
from bzrlib.tests import (
563
562
        state.lock_read()
564
563
        try:
565
564
            entry = state._get_entry(0, path_utf8='a-file')
566
 
            # The current size should be 0 (default)
567
 
            self.assertEqual(0, entry[1][0][2])
 
565
            # The current sha1 sum should be empty
 
566
            self.assertEqual('', entry[1][0][1])
568
567
            # We should have a real entry.
569
568
            self.assertNotEqual((None, None), entry)
570
569
            # Make sure everything is old enough
571
570
            state._sha_cutoff_time()
572
571
            state._cutoff_time += 10
573
 
            # Change the file length
574
 
            self.build_tree_contents([('a-file', 'shorter')])
575
 
            sha1sum = dirstate.update_entry(state, entry, 'a-file',
576
 
                os.lstat('a-file'))
577
 
            # new file, no cached sha:
578
 
            self.assertEqual(None, sha1sum)
 
572
            sha1sum = state.update_entry(entry, 'a-file', os.lstat('a-file'))
 
573
            # We should have gotten a real sha1
 
574
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
 
575
                             sha1sum)
579
576
 
580
577
            # The dirblock has been updated
581
 
            self.assertEqual(7, entry[1][0][2])
 
578
            self.assertEqual(sha1sum, entry[1][0][1])
582
579
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
583
580
                             state._dirblock_state)
584
581
 
594
591
        state.lock_read()
595
592
        try:
596
593
            entry = state._get_entry(0, path_utf8='a-file')
597
 
            self.assertEqual(7, entry[1][0][2])
 
594
            self.assertEqual(sha1sum, entry[1][0][1])
598
595
        finally:
599
596
            state.unlock()
600
597
 
613
610
        state.lock_read()
614
611
        try:
615
612
            entry = state._get_entry(0, path_utf8='a-file')
616
 
            sha1sum = dirstate.update_entry(state, entry, 'a-file',
617
 
                os.lstat('a-file'))
618
 
            # No sha - too new
619
 
            self.assertEqual(None, sha1sum)
 
613
            sha1sum = state.update_entry(entry, 'a-file', os.lstat('a-file'))
 
614
            # We should have gotten a real sha1
 
615
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
 
616
                             sha1sum)
620
617
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
621
618
                             state._dirblock_state)
622
619
 
968
965
            state.set_parent_trees(
969
966
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
970
967
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
971
 
                 ('ghost-rev', tree2.branch.repository.revision_tree(
972
 
                                   _mod_revision.NULL_REVISION))),
 
968
                 ('ghost-rev', tree2.branch.repository.revision_tree(None))),
973
969
                ['ghost-rev'])
974
970
            self.assertEqual([revid1, revid2, 'ghost-rev'],
975
971
                             state.get_parent_ids())
1606
1602
 
1607
1603
        # *really* cheesy way to just get an empty tree
1608
1604
        repo = self.make_repository('repo')
1609
 
        empty_tree = repo.revision_tree(_mod_revision.NULL_REVISION)
 
1605
        empty_tree = repo.revision_tree(None)
1610
1606
        state.set_parent_trees([('null:', empty_tree)], [])
1611
1607
 
1612
1608
        dirblock_names = [d[0] for d in state._dirblocks]
1667
1663
        self.st_mode = mode
1668
1664
 
1669
1665
 
 
1666
class TestUpdateEntry(TestCaseWithDirState):
 
1667
    """Test the DirState.update_entry functions"""
 
1668
 
 
1669
    def get_state_with_a(self):
 
1670
        """Create a DirState tracking a single object named 'a'"""
 
1671
        state = InstrumentedDirState.initialize('dirstate')
 
1672
        self.addCleanup(state.unlock)
 
1673
        state.add('a', 'a-id', 'file', None, '')
 
1674
        entry = state._get_entry(0, path_utf8='a')
 
1675
        return state, entry
 
1676
 
 
1677
    def test_update_entry(self):
 
1678
        state, entry = self.get_state_with_a()
 
1679
        self.build_tree(['a'])
 
1680
        # Add one where we don't provide the stat or sha already
 
1681
        self.assertEqual(('', 'a', 'a-id'), entry[0])
 
1682
        self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
 
1683
                         entry[1])
 
1684
        # Flush the buffers to disk
 
1685
        state.save()
 
1686
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1687
                         state._dirblock_state)
 
1688
 
 
1689
        stat_value = os.lstat('a')
 
1690
        packed_stat = dirstate.pack_stat(stat_value)
 
1691
        link_or_sha1 = state.update_entry(entry, abspath='a',
 
1692
                                          stat_value=stat_value)
 
1693
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
1694
                         link_or_sha1)
 
1695
 
 
1696
        # The dirblock entry should not cache the file's sha1
 
1697
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
 
1698
                         entry[1])
 
1699
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
1700
                         state._dirblock_state)
 
1701
        mode = stat_value.st_mode
 
1702
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
 
1703
 
 
1704
        state.save()
 
1705
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1706
                         state._dirblock_state)
 
1707
 
 
1708
        # If we do it again right away, we don't know if the file has changed
 
1709
        # so we will re-read the file. Roll the clock back so the file is
 
1710
        # guaranteed to look too new.
 
1711
        state.adjust_time(-10)
 
1712
 
 
1713
        link_or_sha1 = state.update_entry(entry, abspath='a',
 
1714
                                          stat_value=stat_value)
 
1715
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
 
1716
                          ('sha1', 'a'), ('is_exec', mode, False),
 
1717
                         ], state._log)
 
1718
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
1719
                         link_or_sha1)
 
1720
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
1721
                         state._dirblock_state)
 
1722
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
 
1723
                         entry[1])
 
1724
        state.save()
 
1725
 
 
1726
        # However, if we move the clock forward so the file is considered
 
1727
        # "stable", it should just cache the value.
 
1728
        state.adjust_time(+20)
 
1729
        link_or_sha1 = state.update_entry(entry, abspath='a',
 
1730
                                          stat_value=stat_value)
 
1731
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
1732
                         link_or_sha1)
 
1733
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
 
1734
                          ('sha1', 'a'), ('is_exec', mode, False),
 
1735
                          ('sha1', 'a'), ('is_exec', mode, False),
 
1736
                         ], state._log)
 
1737
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
 
1738
                         entry[1])
 
1739
 
 
1740
        # Subsequent calls will just return the cached value
 
1741
        link_or_sha1 = state.update_entry(entry, abspath='a',
 
1742
                                          stat_value=stat_value)
 
1743
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
1744
                         link_or_sha1)
 
1745
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
 
1746
                          ('sha1', 'a'), ('is_exec', mode, False),
 
1747
                          ('sha1', 'a'), ('is_exec', mode, False),
 
1748
                         ], state._log)
 
1749
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
 
1750
                         entry[1])
 
1751
 
 
1752
    def test_update_entry_symlink(self):
 
1753
        """Update entry should read symlinks."""
 
1754
        self.requireFeature(SymlinkFeature)
 
1755
        state, entry = self.get_state_with_a()
 
1756
        state.save()
 
1757
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1758
                         state._dirblock_state)
 
1759
        os.symlink('target', 'a')
 
1760
 
 
1761
        state.adjust_time(-10) # Make the symlink look new
 
1762
        stat_value = os.lstat('a')
 
1763
        packed_stat = dirstate.pack_stat(stat_value)
 
1764
        link_or_sha1 = state.update_entry(entry, abspath='a',
 
1765
                                          stat_value=stat_value)
 
1766
        self.assertEqual('target', link_or_sha1)
 
1767
        self.assertEqual([('read_link', 'a', '')], state._log)
 
1768
        # Dirblock is not updated (the link is too new)
 
1769
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
 
1770
                         entry[1])
 
1771
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
1772
                         state._dirblock_state)
 
1773
 
 
1774
        # Because the stat_value looks new, we should re-read the target
 
1775
        link_or_sha1 = state.update_entry(entry, abspath='a',
 
1776
                                          stat_value=stat_value)
 
1777
        self.assertEqual('target', link_or_sha1)
 
1778
        self.assertEqual([('read_link', 'a', ''),
 
1779
                          ('read_link', 'a', ''),
 
1780
                         ], state._log)
 
1781
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
 
1782
                         entry[1])
 
1783
        state.adjust_time(+20) # Skip into the future, all files look old
 
1784
        link_or_sha1 = state.update_entry(entry, abspath='a',
 
1785
                                          stat_value=stat_value)
 
1786
        self.assertEqual('target', link_or_sha1)
 
1787
        # We need to re-read the link because only now can we cache it
 
1788
        self.assertEqual([('read_link', 'a', ''),
 
1789
                          ('read_link', 'a', ''),
 
1790
                          ('read_link', 'a', ''),
 
1791
                         ], state._log)
 
1792
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
 
1793
                         entry[1])
 
1794
 
 
1795
        # Another call won't re-read the link
 
1796
        self.assertEqual([('read_link', 'a', ''),
 
1797
                          ('read_link', 'a', ''),
 
1798
                          ('read_link', 'a', ''),
 
1799
                         ], state._log)
 
1800
        link_or_sha1 = state.update_entry(entry, abspath='a',
 
1801
                                          stat_value=stat_value)
 
1802
        self.assertEqual('target', link_or_sha1)
 
1803
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
 
1804
                         entry[1])
 
1805
 
 
1806
    def do_update_entry(self, state, entry, abspath):
 
1807
        stat_value = os.lstat(abspath)
 
1808
        return state.update_entry(entry, abspath, stat_value)
 
1809
 
 
1810
    def test_update_entry_dir(self):
 
1811
        state, entry = self.get_state_with_a()
 
1812
        self.build_tree(['a/'])
 
1813
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1814
 
 
1815
    def test_update_entry_dir_unchanged(self):
 
1816
        state, entry = self.get_state_with_a()
 
1817
        self.build_tree(['a/'])
 
1818
        state.adjust_time(+20)
 
1819
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1820
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
1821
                         state._dirblock_state)
 
1822
        state.save()
 
1823
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1824
                         state._dirblock_state)
 
1825
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1826
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1827
                         state._dirblock_state)
 
1828
 
 
1829
    def test_update_entry_file_unchanged(self):
 
1830
        state, entry = self.get_state_with_a()
 
1831
        self.build_tree(['a'])
 
1832
        sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
 
1833
        state.adjust_time(+20)
 
1834
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
 
1835
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
1836
                         state._dirblock_state)
 
1837
        state.save()
 
1838
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1839
                         state._dirblock_state)
 
1840
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
 
1841
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1842
                         state._dirblock_state)
 
1843
 
 
1844
    def create_and_test_file(self, state, entry):
 
1845
        """Create a file at 'a' and verify the state finds it.
 
1846
 
 
1847
        The state should already be versioning *something* at 'a'. This makes
 
1848
        sure that state.update_entry recognizes it as a file.
 
1849
        """
 
1850
        self.build_tree(['a'])
 
1851
        stat_value = os.lstat('a')
 
1852
        packed_stat = dirstate.pack_stat(stat_value)
 
1853
 
 
1854
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
 
1855
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
1856
                         link_or_sha1)
 
1857
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
 
1858
                         entry[1])
 
1859
        return packed_stat
 
1860
 
 
1861
    def create_and_test_dir(self, state, entry):
 
1862
        """Create a directory at 'a' and verify the state finds it.
 
1863
 
 
1864
        The state should already be versioning *something* at 'a'. This makes
 
1865
        sure that state.update_entry recognizes it as a directory.
 
1866
        """
 
1867
        self.build_tree(['a/'])
 
1868
        stat_value = os.lstat('a')
 
1869
        packed_stat = dirstate.pack_stat(stat_value)
 
1870
 
 
1871
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
 
1872
        self.assertIs(None, link_or_sha1)
 
1873
        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
 
1874
 
 
1875
        return packed_stat
 
1876
 
 
1877
    def create_and_test_symlink(self, state, entry):
 
1878
        """Create a symlink at 'a' and verify the state finds it.
 
1879
 
 
1880
        The state should already be versioning *something* at 'a'. This makes
 
1881
        sure that state.update_entry recognizes it as a symlink.
 
1882
 
 
1883
        This should not be called if this platform does not have symlink
 
1884
        support.
 
1885
        """
 
1886
        # caller should care about skipping test on platforms without symlinks
 
1887
        os.symlink('path/to/foo', 'a')
 
1888
 
 
1889
        stat_value = os.lstat('a')
 
1890
        packed_stat = dirstate.pack_stat(stat_value)
 
1891
 
 
1892
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
 
1893
        self.assertEqual('path/to/foo', link_or_sha1)
 
1894
        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
 
1895
                         entry[1])
 
1896
        return packed_stat
 
1897
 
 
1898
    def test_update_file_to_dir(self):
 
1899
        """If a file changes to a directory we return None for the sha.
 
1900
        We also update the inventory record.
 
1901
        """
 
1902
        state, entry = self.get_state_with_a()
 
1903
        # The file sha1 won't be cached unless the file is old
 
1904
        state.adjust_time(+10)
 
1905
        self.create_and_test_file(state, entry)
 
1906
        os.remove('a')
 
1907
        self.create_and_test_dir(state, entry)
 
1908
 
 
1909
    def test_update_file_to_symlink(self):
 
1910
        """File becomes a symlink"""
 
1911
        self.requireFeature(SymlinkFeature)
 
1912
        state, entry = self.get_state_with_a()
 
1913
        # The file sha1 won't be cached unless the file is old
 
1914
        state.adjust_time(+10)
 
1915
        self.create_and_test_file(state, entry)
 
1916
        os.remove('a')
 
1917
        self.create_and_test_symlink(state, entry)
 
1918
 
 
1919
    def test_update_dir_to_file(self):
 
1920
        """Directory becoming a file updates the entry."""
 
1921
        state, entry = self.get_state_with_a()
 
1922
        # The file sha1 won't be cached unless the file is old
 
1923
        state.adjust_time(+10)
 
1924
        self.create_and_test_dir(state, entry)
 
1925
        os.rmdir('a')
 
1926
        self.create_and_test_file(state, entry)
 
1927
 
 
1928
    def test_update_dir_to_symlink(self):
 
1929
        """Directory becomes a symlink"""
 
1930
        self.requireFeature(SymlinkFeature)
 
1931
        state, entry = self.get_state_with_a()
 
1932
        # The symlink target won't be cached if it isn't old
 
1933
        state.adjust_time(+10)
 
1934
        self.create_and_test_dir(state, entry)
 
1935
        os.rmdir('a')
 
1936
        self.create_and_test_symlink(state, entry)
 
1937
 
 
1938
    def test_update_symlink_to_file(self):
 
1939
        """Symlink becomes a file"""
 
1940
        self.requireFeature(SymlinkFeature)
 
1941
        state, entry = self.get_state_with_a()
 
1942
        # The symlink and file info won't be cached unless old
 
1943
        state.adjust_time(+10)
 
1944
        self.create_and_test_symlink(state, entry)
 
1945
        os.remove('a')
 
1946
        self.create_and_test_file(state, entry)
 
1947
 
 
1948
    def test_update_symlink_to_dir(self):
 
1949
        """Symlink becomes a directory"""
 
1950
        self.requireFeature(SymlinkFeature)
 
1951
        state, entry = self.get_state_with_a()
 
1952
        # The symlink target won't be cached if it isn't old
 
1953
        state.adjust_time(+10)
 
1954
        self.create_and_test_symlink(state, entry)
 
1955
        os.remove('a')
 
1956
        self.create_and_test_dir(state, entry)
 
1957
 
 
1958
    def test__is_executable_win32(self):
 
1959
        state, entry = self.get_state_with_a()
 
1960
        self.build_tree(['a'])
 
1961
 
 
1962
        # Make sure we are using the win32 implementation of _is_executable
 
1963
        state._is_executable = state._is_executable_win32
 
1964
 
 
1965
        # The file on disk is not executable, but we are marking it as though
 
1966
        # it is. With _is_executable_win32 we ignore what is on disk.
 
1967
        entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
 
1968
 
 
1969
        stat_value = os.lstat('a')
 
1970
        packed_stat = dirstate.pack_stat(stat_value)
 
1971
 
 
1972
        state.adjust_time(-10) # Make sure everything is new
 
1973
        state.update_entry(entry, abspath='a', stat_value=stat_value)
 
1974
 
 
1975
        # The row is updated, but the executable bit stays set.
 
1976
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
 
1977
                         entry[1])
 
1978
 
 
1979
        # Make the disk object look old enough to cache
 
1980
        state.adjust_time(+20)
 
1981
        digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
 
1982
        state.update_entry(entry, abspath='a', stat_value=stat_value)
 
1983
        self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
 
1984
 
 
1985
 
1670
1986
class TestPackStat(TestCaseWithTransport):
1671
1987
 
1672
1988
    def assertPackStat(self, expected, stat_value):
2198
2514
        state._discard_merge_parents()
2199
2515
        state._validate()
2200
2516
        self.assertEqual(exp_dirblocks, state._dirblocks)
2201
 
 
2202
 
 
2203
 
class Test_InvEntryToDetails(TestCaseWithDirState):
2204
 
 
2205
 
    def assertDetails(self, expected, inv_entry):
2206
 
        details = dirstate.DirState._inv_entry_to_details(inv_entry)
2207
 
        self.assertEqual(expected, details)
2208
 
        # details should always allow join() and always be a plain str when
2209
 
        # finished
2210
 
        (minikind, fingerprint, size, executable, tree_data) = details
2211
 
        self.assertIsInstance(minikind, str)
2212
 
        self.assertIsInstance(fingerprint, str)
2213
 
        self.assertIsInstance(tree_data, str)
2214
 
 
2215
 
    def test_unicode_symlink(self):
2216
 
        # In general, the code base doesn't support a target that contains
2217
 
        # non-ascii characters. So we just assert tha 
2218
 
        inv_entry = inventory.InventoryLink('link-file-id', 'name',
2219
 
                                            'link-parent-id')
2220
 
        inv_entry.revision = 'link-revision-id'
2221
 
        inv_entry.symlink_target = u'link-target'
2222
 
        details = self.assertDetails(('l', 'link-target', 0, False,
2223
 
                                      'link-revision-id'), inv_entry)