574
574
changes = [c[1] for c in tree._iter_changes(basis)]
575
575
self.assertEqual([], changes)
576
576
self.assertEqual(['', 'versioned', 'versioned2'], returned)
579
class TestCorruptDirstate(TestCaseWithTransport):
580
"""Tests for how we handle when the dirstate has been corrupted."""
582
def create_wt4(self):
583
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
584
control.create_repository()
585
control.create_branch()
586
tree = workingtree_4.WorkingTreeFormat4().initialize(control)
589
def test_invalid_rename(self):
590
tree = self.create_wt4()
591
# Create a corrupted dirstate
594
tree.commit('init') # We need a parent, or we always compare with NULL
595
state = tree.current_dirstate()
596
state._read_dirblocks_if_needed()
597
# Now add in an invalid entry, a rename with a dangling pointer
598
state._dirblocks[1][1].append((('', 'foo', 'foo-id'),
599
[('f', '', 0, False, ''),
600
('r', 'bar', 0 , False, '')]))
601
self.assertListRaises(errors.CorruptDirstate,
602
tree._iter_changes, tree.basis_tree())
606
def get_simple_dirblocks(self, state):
607
"""Extract the simple information from the DirState.
609
This returns the dirblocks, only with the sha1sum and stat details
613
for block in state._dirblocks:
614
simple_block = (block[0], [])
615
for entry in block[1]:
616
# Include the key for each entry, and for each parent include
617
# just the minikind, so we know if it was
618
# present/absent/renamed/etc
619
simple_block[1].append((entry[0], [i[0] for i in entry[1]]))
620
simple_blocks.append(simple_block)
623
def test_update_basis_with_invalid_delta(self):
624
"""When given an invalid delta, it should abort, and not be saved."""
625
self.build_tree(['dir/', 'dir/file'])
626
tree = self.create_wt4()
628
self.addCleanup(tree.unlock)
629
tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
630
first_revision_id = tree.commit('init')
632
root_id = tree.path2id('')
633
state = tree.current_dirstate()
634
state._read_dirblocks_if_needed()
636
('', [(('', '', root_id), ['d', 'd'])]),
637
('', [(('', 'dir', 'dir-id'), ['d', 'd'])]),
638
('dir', [(('dir', 'file', 'file-id'), ['f', 'f'])]),
639
], self.get_simple_dirblocks(state))
641
tree.remove(['dir/file'])
643
('', [(('', '', root_id), ['d', 'd'])]),
644
('', [(('', 'dir', 'dir-id'), ['d', 'd'])]),
645
('dir', [(('dir', 'file', 'file-id'), ['a', 'f'])]),
646
], self.get_simple_dirblocks(state))
647
# Make sure the removal is written to disk
650
# self.assertRaises(Exception, tree.update_basis_by_delta,
651
new_dir = inventory.InventoryDirectory('dir-id', 'new-dir', root_id)
652
new_dir.revision = 'new-revision-id'
653
new_file = inventory.InventoryFile('file-id', 'new-file', root_id)
654
new_file.revision = 'new-revision-id'
655
self.assertRaises(errors.InconsistentDelta,
656
tree.update_basis_by_delta, 'new-revision-id',
657
[('dir', 'new-dir', 'dir-id', new_dir),
658
('dir/file', 'new-dir/new-file', 'file-id', new_file),
662
# Now when we re-read the file it should not have been modified
665
self.assertEqual(first_revision_id, tree.last_revision())
666
state = tree.current_dirstate()
667
state._read_dirblocks_if_needed()
669
('', [(('', '', root_id), ['d', 'd'])]),
670
('', [(('', 'dir', 'dir-id'), ['d', 'd'])]),
671
('dir', [(('dir', 'file', 'file-id'), ['a', 'f'])]),
672
], self.get_simple_dirblocks(state))