599
585
bar1_abspath = self.wt.abspath('bar')
600
586
self.assertEqual([bar1_abspath], stat_paths)
602
def test_iter_changes(self):
603
self.wt.set_root_id('eert_toor')
604
transform, root = self.get_transform()
605
transform.new_file('old', root, 'blah', 'id-1', True)
607
transform, root = self.get_transform()
609
self.assertEqual([], list(transform._iter_changes()))
610
old = transform.trans_id_tree_file_id('id-1')
611
transform.unversion_file(old)
612
self.assertEqual([('id-1', ('old', None), False, (True, False),
613
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
614
(True, True))], list(transform._iter_changes()))
615
transform.new_directory('new', root, 'id-1')
616
self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
617
('eert_toor', 'eert_toor'), ('old', 'new'),
618
('file', 'directory'),
619
(True, False))], list(transform._iter_changes()))
623
def test_iter_changes_new(self):
624
self.wt.set_root_id('eert_toor')
625
transform, root = self.get_transform()
626
transform.new_file('old', root, 'blah')
628
transform, root = self.get_transform()
630
old = transform.trans_id_tree_path('old')
631
transform.version_file('id-1', old)
632
self.assertEqual([('id-1', (None, 'old'), False, (False, True),
633
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
634
(False, False))], list(transform._iter_changes()))
638
def test_iter_changes_modifications(self):
639
self.wt.set_root_id('eert_toor')
640
transform, root = self.get_transform()
641
transform.new_file('old', root, 'blah', 'id-1')
642
transform.new_file('new', root, 'blah')
643
transform.new_directory('subdir', root, 'subdir-id')
645
transform, root = self.get_transform()
647
old = transform.trans_id_tree_path('old')
648
subdir = transform.trans_id_tree_file_id('subdir-id')
649
new = transform.trans_id_tree_path('new')
650
self.assertEqual([], list(transform._iter_changes()))
653
transform.delete_contents(old)
654
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
655
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
656
(False, False))], list(transform._iter_changes()))
659
transform.create_file('blah', old)
660
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
661
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
662
(False, False))], list(transform._iter_changes()))
663
transform.cancel_deletion(old)
664
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
665
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
666
(False, False))], list(transform._iter_changes()))
667
transform.cancel_creation(old)
669
# move file_id to a different file
670
self.assertEqual([], list(transform._iter_changes()))
671
transform.unversion_file(old)
672
transform.version_file('id-1', new)
673
transform.adjust_path('old', root, new)
674
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
675
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
676
(False, False))], list(transform._iter_changes()))
677
transform.cancel_versioning(new)
678
transform._removed_id = set()
681
self.assertEqual([], list(transform._iter_changes()))
682
transform.set_executability(True, old)
683
self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
684
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
685
(False, True))], list(transform._iter_changes()))
686
transform.set_executability(None, old)
689
self.assertEqual([], list(transform._iter_changes()))
690
transform.adjust_path('new', root, old)
691
transform._new_parent = {}
692
self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
693
('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
694
(False, False))], list(transform._iter_changes()))
695
transform._new_name = {}
698
self.assertEqual([], list(transform._iter_changes()))
699
transform.adjust_path('new', subdir, old)
700
transform._new_name = {}
701
self.assertEqual([('id-1', ('old', 'subdir/old'), False,
702
(True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
703
('file', 'file'), (False, False))],
704
list(transform._iter_changes()))
705
transform._new_path = {}
710
def test_iter_changes_modified_bleed(self):
711
self.wt.set_root_id('eert_toor')
712
"""Modified flag should not bleed from one change to another"""
713
# unfortunately, we have no guarantee that file1 (which is modified)
714
# will be applied before file2. And if it's applied after file2, it
715
# obviously can't bleed into file2's change output. But for now, it
717
transform, root = self.get_transform()
718
transform.new_file('file1', root, 'blah', 'id-1')
719
transform.new_file('file2', root, 'blah', 'id-2')
721
transform, root = self.get_transform()
723
transform.delete_contents(transform.trans_id_file_id('id-1'))
724
transform.set_executability(True,
725
transform.trans_id_file_id('id-2'))
726
self.assertEqual([('id-1', (u'file1', u'file1'), True, (True, True),
727
('eert_toor', 'eert_toor'), ('file1', u'file1'),
728
('file', None), (False, False)),
729
('id-2', (u'file2', u'file2'), False, (True, True),
730
('eert_toor', 'eert_toor'), ('file2', u'file2'),
731
('file', 'file'), (False, True))],
732
list(transform._iter_changes()))
736
def test_iter_changes_move_missing(self):
737
"""Test moving ids with no files around"""
738
self.wt.set_root_id('toor_eert')
739
# Need two steps because versioning a non-existant file is a conflict.
740
transform, root = self.get_transform()
741
transform.new_directory('floater', root, 'floater-id')
743
transform, root = self.get_transform()
744
transform.delete_contents(transform.trans_id_tree_path('floater'))
746
transform, root = self.get_transform()
747
floater = transform.trans_id_tree_path('floater')
749
transform.adjust_path('flitter', root, floater)
750
self.assertEqual([('floater-id', ('floater', 'flitter'), False,
751
(True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
752
(None, None), (False, False))], list(transform._iter_changes()))
756
def test_iter_changes_pointless(self):
757
"""Ensure that no-ops are not treated as modifications"""
758
self.wt.set_root_id('eert_toor')
759
transform, root = self.get_transform()
760
transform.new_file('old', root, 'blah', 'id-1')
761
transform.new_directory('subdir', root, 'subdir-id')
763
transform, root = self.get_transform()
765
old = transform.trans_id_tree_path('old')
766
subdir = transform.trans_id_tree_file_id('subdir-id')
767
self.assertEqual([], list(transform._iter_changes()))
768
transform.delete_contents(subdir)
769
transform.create_directory(subdir)
770
transform.set_executability(False, old)
771
transform.unversion_file(old)
772
transform.version_file('id-1', old)
773
transform.adjust_path('old', root, old)
774
self.assertEqual([], list(transform._iter_changes()))
778
def test_rename_count(self):
779
transform, root = self.get_transform()
780
transform.new_file('name1', root, 'contents')
781
self.assertEqual(transform.rename_count, 0)
783
self.assertEqual(transform.rename_count, 1)
784
transform2, root = self.get_transform()
785
transform2.adjust_path('name2', root,
786
transform2.trans_id_tree_path('name1'))
787
self.assertEqual(transform2.rename_count, 0)
789
self.assertEqual(transform2.rename_count, 2)
791
def test_change_parent(self):
792
"""Ensure that after we change a parent, the results are still right.
794
Renames and parent changes on pending transforms can happen as part
795
of conflict resolution, and are explicitly permitted by the
798
This test ensures they work correctly with the rename-avoidance
801
transform, root = self.get_transform()
802
parent1 = transform.new_directory('parent1', root)
803
child1 = transform.new_file('child1', parent1, 'contents')
804
parent2 = transform.new_directory('parent2', root)
805
transform.adjust_path('child1', parent2, child1)
807
self.failIfExists(self.wt.abspath('parent1/child1'))
808
self.failUnlessExists(self.wt.abspath('parent2/child1'))
809
# rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
810
# no rename for child1 (counting only renames during apply)
811
self.failUnlessEqual(2, transform.rename_count)
813
def test_cancel_parent(self):
814
"""Cancelling a parent doesn't cause deletion of a non-empty directory
816
This is like the test_change_parent, except that we cancel the parent
817
before adjusting the path. The transform must detect that the
818
directory is non-empty, and move children to safe locations.
820
transform, root = self.get_transform()
821
parent1 = transform.new_directory('parent1', root)
822
child1 = transform.new_file('child1', parent1, 'contents')
823
child2 = transform.new_file('child2', parent1, 'contents')
825
transform.cancel_creation(parent1)
827
self.fail('Failed to move child1 before deleting parent1')
828
transform.cancel_creation(child2)
829
transform.create_directory(parent1)
831
transform.cancel_creation(parent1)
832
# If the transform incorrectly believes that child2 is still in
833
# parent1's limbo directory, it will try to rename it and fail
834
# because was already moved by the first cancel_creation.
836
self.fail('Transform still thinks child2 is a child of parent1')
837
parent2 = transform.new_directory('parent2', root)
838
transform.adjust_path('child1', parent2, child1)
840
self.failIfExists(self.wt.abspath('parent1'))
841
self.failUnlessExists(self.wt.abspath('parent2/child1'))
842
# rename limbo/new-3 => parent2, rename limbo/new-2 => child1
843
self.failUnlessEqual(2, transform.rename_count)
845
def test_adjust_and_cancel(self):
846
"""Make sure adjust_path keeps track of limbo children properly"""
847
transform, root = self.get_transform()
848
parent1 = transform.new_directory('parent1', root)
849
child1 = transform.new_file('child1', parent1, 'contents')
850
parent2 = transform.new_directory('parent2', root)
851
transform.adjust_path('child1', parent2, child1)
852
transform.cancel_creation(child1)
854
transform.cancel_creation(parent1)
855
# if the transform thinks child1 is still in parent1's limbo
856
# directory, it will attempt to move it and fail.
858
self.fail('Transform still thinks child1 is a child of parent1')
861
def test_noname_contents(self):
862
"""TreeTransform should permit deferring naming files."""
863
transform, root = self.get_transform()
864
parent = transform.trans_id_file_id('parent-id')
866
transform.create_directory(parent)
868
self.fail("Can't handle contents with no name")
871
def test_noname_contents_nested(self):
872
"""TreeTransform should permit deferring naming files."""
873
transform, root = self.get_transform()
874
parent = transform.trans_id_file_id('parent-id')
876
transform.create_directory(parent)
878
self.fail("Can't handle contents with no name")
879
child = transform.new_directory('child', parent)
880
transform.adjust_path('parent', root, parent)
882
self.failUnlessExists(self.wt.abspath('parent/child'))
883
self.assertEqual(1, transform.rename_count)
885
def test_reuse_name(self):
886
"""Avoid reusing the same limbo name for different files"""
887
transform, root = self.get_transform()
888
parent = transform.new_directory('parent', root)
889
child1 = transform.new_directory('child', parent)
891
child2 = transform.new_directory('child', parent)
893
self.fail('Tranform tried to use the same limbo name twice')
894
transform.adjust_path('child2', parent, child2)
896
# limbo/new-1 => parent, limbo/new-3 => parent/child2
897
# child2 is put into top-level limbo because child1 has already
898
# claimed the direct limbo path when child2 is created. There is no
899
# advantage in renaming files once they're in top-level limbo, except
901
self.assertEqual(2, transform.rename_count)
903
def test_reuse_when_first_moved(self):
904
"""Don't avoid direct paths when it is safe to use them"""
905
transform, root = self.get_transform()
906
parent = transform.new_directory('parent', root)
907
child1 = transform.new_directory('child', parent)
908
transform.adjust_path('child1', parent, child1)
909
child2 = transform.new_directory('child', parent)
911
# limbo/new-1 => parent
912
self.assertEqual(1, transform.rename_count)
914
def test_reuse_after_cancel(self):
915
"""Don't avoid direct paths when it is safe to use them"""
916
transform, root = self.get_transform()
917
parent2 = transform.new_directory('parent2', root)
918
child1 = transform.new_directory('child1', parent2)
919
transform.cancel_creation(parent2)
920
transform.create_directory(parent2)
921
child2 = transform.new_directory('child1', parent2)
922
transform.adjust_path('child2', parent2, child1)
924
# limbo/new-1 => parent2, limbo/new-2 => parent2/child1
925
self.assertEqual(2, transform.rename_count)
927
def test_finalize_order(self):
928
"""Finalize must be done in child-to-parent order"""
929
transform, root = self.get_transform()
930
parent = transform.new_directory('parent', root)
931
child = transform.new_directory('child', parent)
935
self.fail('Tried to remove parent before child1')
937
def test_cancel_with_cancelled_child_should_succeed(self):
938
transform, root = self.get_transform()
939
parent = transform.new_directory('parent', root)
940
child = transform.new_directory('child', parent)
941
transform.cancel_creation(child)
942
transform.cancel_creation(parent)
946
589
class TransformGroup(object):
947
def __init__(self, dirname, root_id):
590
def __init__(self, dirname):
948
591
self.name = dirname
949
592
os.mkdir(dirname)
950
593
self.wt = BzrDir.create_standalone_workingtree(dirname)
951
self.wt.set_root_id(root_id)
952
594
self.b = self.wt.branch
953
595
self.tt = TreeTransform(self.wt)
954
596
self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
957
598
def conflict_text(tree, merge):
958
599
template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
959
600
return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)