1623
1851
self.st_ino = ino
1624
1852
self.st_mode = mode
1627
class TestUpdateEntry(TestCaseWithDirState):
1628
"""Test the DirState.update_entry functions"""
1630
def get_state_with_a(self):
1631
"""Create a DirState tracking a single object named 'a'"""
1632
state = InstrumentedDirState.initialize('dirstate')
1633
self.addCleanup(state.unlock)
1634
state.add('a', 'a-id', 'file', None, '')
1635
entry = state._get_entry(0, path_utf8='a')
1638
def test_update_entry(self):
1639
state, entry = self.get_state_with_a()
1640
self.build_tree(['a'])
1641
# Add one where we don't provide the stat or sha already
1642
self.assertEqual(('', 'a', 'a-id'), entry[0])
1643
self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
1645
# Flush the buffers to disk
1647
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1648
state._dirblock_state)
1650
stat_value = os.lstat('a')
1651
packed_stat = dirstate.pack_stat(stat_value)
1652
link_or_sha1 = state.update_entry(entry, abspath='a',
1653
stat_value=stat_value)
1654
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1657
# The dirblock entry should not cache the file's sha1
1658
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1660
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1661
state._dirblock_state)
1662
mode = stat_value.st_mode
1663
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
1666
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1667
state._dirblock_state)
1669
# If we do it again right away, we don't know if the file has changed
1670
# so we will re-read the file. Roll the clock back so the file is
1671
# guaranteed to look too new.
1672
state.adjust_time(-10)
1674
link_or_sha1 = state.update_entry(entry, abspath='a',
1675
stat_value=stat_value)
1676
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1677
('sha1', 'a'), ('is_exec', mode, False),
1679
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1681
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1682
state._dirblock_state)
1683
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1687
# However, if we move the clock forward so the file is considered
1688
# "stable", it should just cache the value.
1689
state.adjust_time(+20)
1690
link_or_sha1 = state.update_entry(entry, abspath='a',
1691
stat_value=stat_value)
1692
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1694
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1695
('sha1', 'a'), ('is_exec', mode, False),
1696
('sha1', 'a'), ('is_exec', mode, False),
1698
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1701
# Subsequent calls will just return the cached value
1702
link_or_sha1 = state.update_entry(entry, abspath='a',
1703
stat_value=stat_value)
1704
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1706
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1707
('sha1', 'a'), ('is_exec', mode, False),
1708
('sha1', 'a'), ('is_exec', mode, False),
1710
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1713
def test_update_entry_symlink(self):
1714
"""Update entry should read symlinks."""
1715
self.requireFeature(SymlinkFeature)
1716
state, entry = self.get_state_with_a()
1718
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1719
state._dirblock_state)
1720
os.symlink('target', 'a')
1722
state.adjust_time(-10) # Make the symlink look new
1723
stat_value = os.lstat('a')
1724
packed_stat = dirstate.pack_stat(stat_value)
1725
link_or_sha1 = state.update_entry(entry, abspath='a',
1726
stat_value=stat_value)
1727
self.assertEqual('target', link_or_sha1)
1728
self.assertEqual([('read_link', 'a', '')], state._log)
1729
# Dirblock is not updated (the link is too new)
1730
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1732
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1733
state._dirblock_state)
1735
# Because the stat_value looks new, we should re-read the target
1736
link_or_sha1 = state.update_entry(entry, abspath='a',
1737
stat_value=stat_value)
1738
self.assertEqual('target', link_or_sha1)
1739
self.assertEqual([('read_link', 'a', ''),
1740
('read_link', 'a', ''),
1742
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1744
state.adjust_time(+20) # Skip into the future, all files look old
1745
link_or_sha1 = state.update_entry(entry, abspath='a',
1746
stat_value=stat_value)
1747
self.assertEqual('target', link_or_sha1)
1748
# We need to re-read the link because only now can we cache it
1749
self.assertEqual([('read_link', 'a', ''),
1750
('read_link', 'a', ''),
1751
('read_link', 'a', ''),
1753
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1756
# Another call won't re-read the link
1757
self.assertEqual([('read_link', 'a', ''),
1758
('read_link', 'a', ''),
1759
('read_link', 'a', ''),
1761
link_or_sha1 = state.update_entry(entry, abspath='a',
1762
stat_value=stat_value)
1763
self.assertEqual('target', link_or_sha1)
1764
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1767
def do_update_entry(self, state, entry, abspath):
1768
stat_value = os.lstat(abspath)
1769
return state.update_entry(entry, abspath, stat_value)
1771
def test_update_entry_dir(self):
1772
state, entry = self.get_state_with_a()
1773
self.build_tree(['a/'])
1774
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1776
def test_update_entry_dir_unchanged(self):
1777
state, entry = self.get_state_with_a()
1778
self.build_tree(['a/'])
1779
state.adjust_time(+20)
1780
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1781
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1782
state._dirblock_state)
1784
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1785
state._dirblock_state)
1786
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1787
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1788
state._dirblock_state)
1790
def test_update_entry_file_unchanged(self):
1791
state, entry = self.get_state_with_a()
1792
self.build_tree(['a'])
1793
sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1794
state.adjust_time(+20)
1795
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1796
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1797
state._dirblock_state)
1799
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1800
state._dirblock_state)
1801
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1802
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1803
state._dirblock_state)
1805
def create_and_test_file(self, state, entry):
1806
"""Create a file at 'a' and verify the state finds it.
1808
The state should already be versioning *something* at 'a'. This makes
1809
sure that state.update_entry recognizes it as a file.
1811
self.build_tree(['a'])
1812
stat_value = os.lstat('a')
1813
packed_stat = dirstate.pack_stat(stat_value)
1815
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1816
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1818
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1822
def create_and_test_dir(self, state, entry):
1823
"""Create a directory at 'a' and verify the state finds it.
1825
The state should already be versioning *something* at 'a'. This makes
1826
sure that state.update_entry recognizes it as a directory.
1828
self.build_tree(['a/'])
1829
stat_value = os.lstat('a')
1830
packed_stat = dirstate.pack_stat(stat_value)
1832
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1833
self.assertIs(None, link_or_sha1)
1834
self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1838
def create_and_test_symlink(self, state, entry):
1839
"""Create a symlink at 'a' and verify the state finds it.
1841
The state should already be versioning *something* at 'a'. This makes
1842
sure that state.update_entry recognizes it as a symlink.
1844
This should not be called if this platform does not have symlink
1847
# caller should care about skipping test on platforms without symlinks
1848
os.symlink('path/to/foo', 'a')
1850
stat_value = os.lstat('a')
1851
packed_stat = dirstate.pack_stat(stat_value)
1853
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1854
self.assertEqual('path/to/foo', link_or_sha1)
1855
self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1859
def test_update_file_to_dir(self):
1860
"""If a file changes to a directory we return None for the sha.
1861
We also update the inventory record.
1863
state, entry = self.get_state_with_a()
1864
# The file sha1 won't be cached unless the file is old
1865
state.adjust_time(+10)
1866
self.create_and_test_file(state, entry)
1868
self.create_and_test_dir(state, entry)
1870
def test_update_file_to_symlink(self):
1871
"""File becomes a symlink"""
1872
self.requireFeature(SymlinkFeature)
1873
state, entry = self.get_state_with_a()
1874
# The file sha1 won't be cached unless the file is old
1875
state.adjust_time(+10)
1876
self.create_and_test_file(state, entry)
1878
self.create_and_test_symlink(state, entry)
1880
def test_update_dir_to_file(self):
1881
"""Directory becoming a file updates the entry."""
1882
state, entry = self.get_state_with_a()
1883
# The file sha1 won't be cached unless the file is old
1884
state.adjust_time(+10)
1885
self.create_and_test_dir(state, entry)
1887
self.create_and_test_file(state, entry)
1889
def test_update_dir_to_symlink(self):
1890
"""Directory becomes a symlink"""
1891
self.requireFeature(SymlinkFeature)
1892
state, entry = self.get_state_with_a()
1893
# The symlink target won't be cached if it isn't old
1894
state.adjust_time(+10)
1895
self.create_and_test_dir(state, entry)
1897
self.create_and_test_symlink(state, entry)
1899
def test_update_symlink_to_file(self):
1900
"""Symlink becomes a file"""
1901
self.requireFeature(SymlinkFeature)
1902
state, entry = self.get_state_with_a()
1903
# The symlink and file info won't be cached unless old
1904
state.adjust_time(+10)
1905
self.create_and_test_symlink(state, entry)
1907
self.create_and_test_file(state, entry)
1909
def test_update_symlink_to_dir(self):
1910
"""Symlink becomes a directory"""
1911
self.requireFeature(SymlinkFeature)
1912
state, entry = self.get_state_with_a()
1913
# The symlink target won't be cached if it isn't old
1914
state.adjust_time(+10)
1915
self.create_and_test_symlink(state, entry)
1917
self.create_and_test_dir(state, entry)
1919
def test__is_executable_win32(self):
1920
state, entry = self.get_state_with_a()
1921
self.build_tree(['a'])
1923
# Make sure we are using the win32 implementation of _is_executable
1924
state._is_executable = state._is_executable_win32
1926
# The file on disk is not executable, but we are marking it as though
1927
# it is. With _is_executable_win32 we ignore what is on disk.
1928
entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1930
stat_value = os.lstat('a')
1931
packed_stat = dirstate.pack_stat(stat_value)
1933
state.adjust_time(-10) # Make sure everything is new
1934
state.update_entry(entry, abspath='a', stat_value=stat_value)
1936
# The row is updated, but the executable bit stays set.
1937
self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
1940
# Make the disk object look old enough to cache
1941
state.adjust_time(+20)
1942
digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1943
state.update_entry(entry, abspath='a', stat_value=stat_value)
1944
self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
1947
class TestPackStat(TestCaseWithTransport):
1856
return _FakeStat(st.st_size, st.st_mtime, st.st_ctime, st.st_dev,
1857
st.st_ino, st.st_mode)
1860
class TestPackStat(tests.TestCaseWithTransport):
1949
1862
def assertPackStat(self, expected, stat_value):
1950
1863
"""Check the packed and serialized form of a stat value."""
2476
2388
state._discard_merge_parents()
2477
2389
state._validate()
2478
2390
self.assertEqual(exp_dirblocks, state._dirblocks)
2393
class Test_InvEntryToDetails(tests.TestCase):
2395
def assertDetails(self, expected, inv_entry):
2396
details = dirstate.DirState._inv_entry_to_details(inv_entry)
2397
self.assertEqual(expected, details)
2398
# details should always allow join() and always be a plain str when
2400
(minikind, fingerprint, size, executable, tree_data) = details
2401
self.assertIsInstance(minikind, str)
2402
self.assertIsInstance(fingerprint, str)
2403
self.assertIsInstance(tree_data, str)
2405
def test_unicode_symlink(self):
2406
inv_entry = inventory.InventoryLink('link-file-id',
2407
u'nam\N{Euro Sign}e',
2409
inv_entry.revision = 'link-revision-id'
2410
target = u'link-targ\N{Euro Sign}t'
2411
inv_entry.symlink_target = target
2412
self.assertDetails(('l', target.encode('UTF-8'), 0, False,
2413
'link-revision-id'), inv_entry)
2416
class TestSHA1Provider(tests.TestCaseInTempDir):
2418
def test_sha1provider_is_an_interface(self):
2419
p = dirstate.SHA1Provider()
2420
self.assertRaises(NotImplementedError, p.sha1, "foo")
2421
self.assertRaises(NotImplementedError, p.stat_and_sha1, "foo")
2423
def test_defaultsha1provider_sha1(self):
2424
text = 'test\r\nwith\nall\rpossible line endings\r\n'
2425
self.build_tree_contents([('foo', text)])
2426
expected_sha = osutils.sha_string(text)
2427
p = dirstate.DefaultSHA1Provider()
2428
self.assertEqual(expected_sha, p.sha1('foo'))
2430
def test_defaultsha1provider_stat_and_sha1(self):
2431
text = 'test\r\nwith\nall\rpossible line endings\r\n'
2432
self.build_tree_contents([('foo', text)])
2433
expected_sha = osutils.sha_string(text)
2434
p = dirstate.DefaultSHA1Provider()
2435
statvalue, sha1 = p.stat_and_sha1('foo')
2436
self.assertTrue(len(statvalue) >= 10)
2437
self.assertEqual(len(text), statvalue.st_size)
2438
self.assertEqual(expected_sha, sha1)
2441
class _Repo(object):
2442
"""A minimal api to get InventoryRevisionTree to work."""
2445
default_format = controldir.format_registry.make_bzrdir('default')
2446
self._format = default_format.repository_format
2448
def lock_read(self):
2455
class TestUpdateBasisByDelta(tests.TestCase):
2457
def path_to_ie(self, path, file_id, rev_id, dir_ids):
2458
if path.endswith('/'):
2463
dirname, basename = osutils.split(path)
2465
dir_id = dir_ids[dirname]
2467
dir_id = osutils.basename(dirname) + '-id'
2469
ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2470
dir_ids[path] = file_id
2472
ie = inventory.InventoryFile(file_id, basename, dir_id)
2475
ie.revision = rev_id
2478
def create_tree_from_shape(self, rev_id, shape):
2479
dir_ids = {'': 'root-id'}
2480
inv = inventory.Inventory('root-id', rev_id)
2483
path, file_id = info
2486
path, file_id, ie_rev_id = info
2488
# Replace the root entry
2489
del inv._byid[inv.root.file_id]
2490
inv.root.file_id = file_id
2491
inv._byid[file_id] = inv.root
2492
dir_ids[''] = file_id
2494
inv.add(self.path_to_ie(path, file_id, ie_rev_id, dir_ids))
2495
return revisiontree.InventoryRevisionTree(_Repo(), inv, rev_id)
2497
def create_empty_dirstate(self):
2498
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2499
self.addCleanup(os.remove, path)
2501
state = dirstate.DirState.initialize(path)
2502
self.addCleanup(state.unlock)
2505
def create_inv_delta(self, delta, rev_id):
2506
"""Translate a 'delta shape' into an actual InventoryDelta"""
2507
dir_ids = {'': 'root-id'}
2509
for old_path, new_path, file_id in delta:
2510
if old_path is not None and old_path.endswith('/'):
2511
# Don't have to actually do anything for this, because only
2512
# new_path creates InventoryEntries
2513
old_path = old_path[:-1]
2514
if new_path is None: # Delete
2515
inv_delta.append((old_path, None, file_id, None))
2517
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2518
inv_delta.append((old_path, new_path, file_id, ie))
2521
def assertUpdate(self, active, basis, target):
2522
"""Assert that update_basis_by_delta works how we want.
2524
Set up a DirState object with active_shape for tree 0, basis_shape for
2525
tree 1. Then apply the delta from basis_shape to target_shape,
2526
and assert that the DirState is still valid, and that its stored
2527
content matches the target_shape.
2529
active_tree = self.create_tree_from_shape('active', active)
2530
basis_tree = self.create_tree_from_shape('basis', basis)
2531
target_tree = self.create_tree_from_shape('target', target)
2532
state = self.create_empty_dirstate()
2533
state.set_state_from_scratch(active_tree.root_inventory,
2534
[('basis', basis_tree)], [])
2535
delta = target_tree.root_inventory._make_delta(
2536
basis_tree.root_inventory)
2537
state.update_basis_by_delta(delta, 'target')
2539
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2541
# The target now that delta has been applied should match the
2543
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2544
# And the dirblock state should be identical to the state if we created
2546
state2 = self.create_empty_dirstate()
2547
state2.set_state_from_scratch(active_tree.root_inventory,
2548
[('target', target_tree)], [])
2549
self.assertEqual(state2._dirblocks, state._dirblocks)
2552
def assertBadDelta(self, active, basis, delta):
2553
"""Test that we raise InconsistentDelta when appropriate.
2555
:param active: The active tree shape
2556
:param basis: The basis tree shape
2557
:param delta: A description of the delta to apply. Similar to the form
2558
for regular inventory deltas, but omitting the InventoryEntry.
2559
So adding a file is: (None, 'path', 'file-id')
2560
Adding a directory is: (None, 'path/', 'dir-id')
2561
Renaming a dir is: ('old/', 'new/', 'dir-id')
2564
active_tree = self.create_tree_from_shape('active', active)
2565
basis_tree = self.create_tree_from_shape('basis', basis)
2566
inv_delta = self.create_inv_delta(delta, 'target')
2567
state = self.create_empty_dirstate()
2568
state.set_state_from_scratch(active_tree.root_inventory,
2569
[('basis', basis_tree)], [])
2570
self.assertRaises(errors.InconsistentDelta,
2571
state.update_basis_by_delta, inv_delta, 'target')
2573
## state.update_basis_by_delta(inv_delta, 'target')
2574
## except errors.InconsistentDelta, e:
2575
## import pdb; pdb.set_trace()
2577
## import pdb; pdb.set_trace()
2578
self.assertTrue(state._changes_aborted)
2580
def test_remove_file_matching_active_state(self):
2581
state = self.assertUpdate(
2583
basis =[('file', 'file-id')],
2587
def test_remove_file_present_in_active_state(self):
2588
state = self.assertUpdate(
2589
active=[('file', 'file-id')],
2590
basis =[('file', 'file-id')],
2594
def test_remove_file_present_elsewhere_in_active_state(self):
2595
state = self.assertUpdate(
2596
active=[('other-file', 'file-id')],
2597
basis =[('file', 'file-id')],
2601
def test_remove_file_active_state_has_diff_file(self):
2602
state = self.assertUpdate(
2603
active=[('file', 'file-id-2')],
2604
basis =[('file', 'file-id')],
2608
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2609
state = self.assertUpdate(
2610
active=[('file', 'file-id-2'),
2611
('other-file', 'file-id')],
2612
basis =[('file', 'file-id')],
2616
def test_add_file_matching_active_state(self):
2617
state = self.assertUpdate(
2618
active=[('file', 'file-id')],
2620
target=[('file', 'file-id')],
2623
def test_add_file_in_empty_dir_not_matching_active_state(self):
2624
state = self.assertUpdate(
2626
basis=[('dir/', 'dir-id')],
2627
target=[('dir/', 'dir-id', 'basis'), ('dir/file', 'file-id')],
2630
def test_add_file_missing_in_active_state(self):
2631
state = self.assertUpdate(
2634
target=[('file', 'file-id')],
2637
def test_add_file_elsewhere_in_active_state(self):
2638
state = self.assertUpdate(
2639
active=[('other-file', 'file-id')],
2641
target=[('file', 'file-id')],
2644
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2645
state = self.assertUpdate(
2646
active=[('other-file', 'file-id'),
2647
('file', 'file-id-2')],
2649
target=[('file', 'file-id')],
2652
def test_rename_file_matching_active_state(self):
2653
state = self.assertUpdate(
2654
active=[('other-file', 'file-id')],
2655
basis =[('file', 'file-id')],
2656
target=[('other-file', 'file-id')],
2659
def test_rename_file_missing_in_active_state(self):
2660
state = self.assertUpdate(
2662
basis =[('file', 'file-id')],
2663
target=[('other-file', 'file-id')],
2666
def test_rename_file_present_elsewhere_in_active_state(self):
2667
state = self.assertUpdate(
2668
active=[('third', 'file-id')],
2669
basis =[('file', 'file-id')],
2670
target=[('other-file', 'file-id')],
2673
def test_rename_file_active_state_has_diff_source_file(self):
2674
state = self.assertUpdate(
2675
active=[('file', 'file-id-2')],
2676
basis =[('file', 'file-id')],
2677
target=[('other-file', 'file-id')],
2680
def test_rename_file_active_state_has_diff_target_file(self):
2681
state = self.assertUpdate(
2682
active=[('other-file', 'file-id-2')],
2683
basis =[('file', 'file-id')],
2684
target=[('other-file', 'file-id')],
2687
def test_rename_file_active_has_swapped_files(self):
2688
state = self.assertUpdate(
2689
active=[('file', 'file-id'),
2690
('other-file', 'file-id-2')],
2691
basis= [('file', 'file-id'),
2692
('other-file', 'file-id-2')],
2693
target=[('file', 'file-id-2'),
2694
('other-file', 'file-id')])
2696
def test_rename_file_basis_has_swapped_files(self):
2697
state = self.assertUpdate(
2698
active=[('file', 'file-id'),
2699
('other-file', 'file-id-2')],
2700
basis= [('file', 'file-id-2'),
2701
('other-file', 'file-id')],
2702
target=[('file', 'file-id'),
2703
('other-file', 'file-id-2')])
2705
def test_rename_directory_with_contents(self):
2706
state = self.assertUpdate( # active matches basis
2707
active=[('dir1/', 'dir-id'),
2708
('dir1/file', 'file-id')],
2709
basis= [('dir1/', 'dir-id'),
2710
('dir1/file', 'file-id')],
2711
target=[('dir2/', 'dir-id'),
2712
('dir2/file', 'file-id')])
2713
state = self.assertUpdate( # active matches target
2714
active=[('dir2/', 'dir-id'),
2715
('dir2/file', 'file-id')],
2716
basis= [('dir1/', 'dir-id'),
2717
('dir1/file', 'file-id')],
2718
target=[('dir2/', 'dir-id'),
2719
('dir2/file', 'file-id')])
2720
state = self.assertUpdate( # active empty
2722
basis= [('dir1/', 'dir-id'),
2723
('dir1/file', 'file-id')],
2724
target=[('dir2/', 'dir-id'),
2725
('dir2/file', 'file-id')])
2726
state = self.assertUpdate( # active present at other location
2727
active=[('dir3/', 'dir-id'),
2728
('dir3/file', 'file-id')],
2729
basis= [('dir1/', 'dir-id'),
2730
('dir1/file', 'file-id')],
2731
target=[('dir2/', 'dir-id'),
2732
('dir2/file', 'file-id')])
2733
state = self.assertUpdate( # active has different ids
2734
active=[('dir1/', 'dir1-id'),
2735
('dir1/file', 'file1-id'),
2736
('dir2/', 'dir2-id'),
2737
('dir2/file', 'file2-id')],
2738
basis= [('dir1/', 'dir-id'),
2739
('dir1/file', 'file-id')],
2740
target=[('dir2/', 'dir-id'),
2741
('dir2/file', 'file-id')])
2743
def test_invalid_file_not_present(self):
2744
state = self.assertBadDelta(
2745
active=[('file', 'file-id')],
2746
basis= [('file', 'file-id')],
2747
delta=[('other-file', 'file', 'file-id')])
2749
def test_invalid_new_id_same_path(self):
2750
# The bad entry comes after
2751
state = self.assertBadDelta(
2752
active=[('file', 'file-id')],
2753
basis= [('file', 'file-id')],
2754
delta=[(None, 'file', 'file-id-2')])
2755
# The bad entry comes first
2756
state = self.assertBadDelta(
2757
active=[('file', 'file-id-2')],
2758
basis=[('file', 'file-id-2')],
2759
delta=[(None, 'file', 'file-id')])
2761
def test_invalid_existing_id(self):
2762
state = self.assertBadDelta(
2763
active=[('file', 'file-id')],
2764
basis= [('file', 'file-id')],
2765
delta=[(None, 'file', 'file-id')])
2767
def test_invalid_parent_missing(self):
2768
state = self.assertBadDelta(
2771
delta=[(None, 'path/path2', 'file-id')])
2772
# Note: we force the active tree to have the directory, by knowing how
2773
# path_to_ie handles entries with missing parents
2774
state = self.assertBadDelta(
2775
active=[('path/', 'path-id')],
2777
delta=[(None, 'path/path2', 'file-id')])
2778
state = self.assertBadDelta(
2779
active=[('path/', 'path-id'),
2780
('path/path2', 'file-id')],
2782
delta=[(None, 'path/path2', 'file-id')])
2784
def test_renamed_dir_same_path(self):
2785
# We replace the parent directory, with another parent dir. But the C
2786
# file doesn't look like it has been moved.
2787
state = self.assertUpdate(# Same as basis
2788
active=[('dir/', 'A-id'),
2790
basis= [('dir/', 'A-id'),
2792
target=[('dir/', 'C-id'),
2794
state = self.assertUpdate(# Same as target
2795
active=[('dir/', 'C-id'),
2797
basis= [('dir/', 'A-id'),
2799
target=[('dir/', 'C-id'),
2801
state = self.assertUpdate(# empty active
2803
basis= [('dir/', 'A-id'),
2805
target=[('dir/', 'C-id'),
2807
state = self.assertUpdate(# different active
2808
active=[('dir/', 'D-id'),
2810
basis= [('dir/', 'A-id'),
2812
target=[('dir/', 'C-id'),
2815
def test_parent_child_swap(self):
2816
state = self.assertUpdate(# Same as basis
2817
active=[('A/', 'A-id'),
2820
basis= [('A/', 'A-id'),
2823
target=[('A/', 'B-id'),
2826
state = self.assertUpdate(# Same as target
2827
active=[('A/', 'B-id'),
2830
basis= [('A/', 'A-id'),
2833
target=[('A/', 'B-id'),
2836
state = self.assertUpdate(# empty active
2838
basis= [('A/', 'A-id'),
2841
target=[('A/', 'B-id'),
2844
state = self.assertUpdate(# different active
2845
active=[('D/', 'A-id'),
2848
basis= [('A/', 'A-id'),
2851
target=[('A/', 'B-id'),
2855
def test_change_root_id(self):
2856
state = self.assertUpdate( # same as basis
2857
active=[('', 'root-id'),
2858
('file', 'file-id')],
2859
basis= [('', 'root-id'),
2860
('file', 'file-id')],
2861
target=[('', 'target-root-id'),
2862
('file', 'file-id')])
2863
state = self.assertUpdate( # same as target
2864
active=[('', 'target-root-id'),
2865
('file', 'file-id')],
2866
basis= [('', 'root-id'),
2867
('file', 'file-id')],
2868
target=[('', 'target-root-id'),
2869
('file', 'root-id')])
2870
state = self.assertUpdate( # all different
2871
active=[('', 'active-root-id'),
2872
('file', 'file-id')],
2873
basis= [('', 'root-id'),
2874
('file', 'file-id')],
2875
target=[('', 'target-root-id'),
2876
('file', 'root-id')])
2878
def test_change_file_absent_in_active(self):
2879
state = self.assertUpdate(
2881
basis= [('file', 'file-id')],
2882
target=[('file', 'file-id')])
2884
def test_invalid_changed_file(self):
2885
state = self.assertBadDelta( # Not present in basis
2886
active=[('file', 'file-id')],
2888
delta=[('file', 'file', 'file-id')])
2889
state = self.assertBadDelta( # present at another location in basis
2890
active=[('file', 'file-id')],
2891
basis= [('other-file', 'file-id')],
2892
delta=[('file', 'file', 'file-id')])