~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: Robert Collins
  • Date: 2007-07-04 08:08:13 UTC
  • mfrom: (2572 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2587.
  • Revision ID: robertc@robertcollins.net-20070704080813-wzebx0r88fvwj5rq
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import sys
20
20
 
21
21
from bzrlib import (
 
22
    errors,
 
23
    generate_ids,
 
24
    symbol_versioning,
22
25
    tests,
23
26
    urlutils,
24
27
    )
37
40
                              find_interesting, build_tree, get_backup_name)
38
41
 
39
42
 
40
 
class TestTreeTransform(TestCaseInTempDir):
 
43
class TestTreeTransform(tests.TestCaseWithTransport):
41
44
 
42
45
    def setUp(self):
43
46
        super(TestTreeTransform, self).setUp()
44
 
        self.wt = BzrDir.create_standalone_workingtree('.')
 
47
        self.wt = self.make_branch_and_tree('.', format='dirstate-with-subtree')
45
48
        os.chdir('..')
46
49
 
47
50
    def get_transform(self):
48
51
        transform = TreeTransform(self.wt)
49
52
        #self.addCleanup(transform.finalize)
50
 
        return transform, transform.trans_id_tree_file_id(self.wt.get_root_id())
 
53
        return transform, transform.root
51
54
 
52
55
    def test_existing_limbo(self):
53
56
        limbo_name = urlutils.local_path_from_url(
124
127
        self.assertEqual(self.wt.path2id('oz/dorothy'), 'dorothy-id')
125
128
        self.assertEqual(self.wt.path2id('oz/dorothy/toto'), 'toto-id')
126
129
 
127
 
        self.assertEqual('toto-contents', 
 
130
        self.assertEqual('toto-contents',
128
131
                         self.wt.get_file_byname('oz/dorothy/toto').read())
129
132
        self.assertIs(self.wt.is_executable('toto-id'), False)
130
133
 
 
134
    def test_tree_reference(self):
 
135
        transform, root = self.get_transform()
 
136
        tree = transform._tree
 
137
        trans_id = transform.new_directory('reference', root, 'subtree-id')
 
138
        transform.set_tree_reference('subtree-revision', trans_id)
 
139
        transform.apply()
 
140
        tree.lock_read()
 
141
        self.addCleanup(tree.unlock)
 
142
        self.assertEqual('subtree-revision',
 
143
                         tree.inventory['subtree-id'].reference_revision)
 
144
 
131
145
    def test_conflicts(self):
132
146
        transform, root = self.get_transform()
133
147
        trans_id = transform.new_file('name', root, 'contents', 
197
211
        transform3.delete_contents(oz_id)
198
212
        self.assertEqual(transform3.find_conflicts(), 
199
213
                         [('missing parent', oz_id)])
200
 
        root_id = transform3.trans_id_tree_file_id('TREE_ROOT')
 
214
        root_id = transform3.root
201
215
        tip_id = transform3.trans_id_tree_file_id('tip-id')
202
216
        transform3.adjust_path('tip', root_id, tip_id)
203
217
        transform3.apply()
229
243
    def test_name_invariants(self):
230
244
        create_tree, root = self.get_transform()
231
245
        # prepare tree
232
 
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
 
246
        root = create_tree.root
233
247
        create_tree.new_file('name1', root, 'hello1', 'name1')
234
248
        create_tree.new_file('name2', root, 'hello2', 'name2')
235
249
        ddir = create_tree.new_directory('dying_directory', root, 'ddir')
239
253
        create_tree.apply()
240
254
 
241
255
        mangle_tree,root = self.get_transform()
242
 
        root = mangle_tree.trans_id_tree_file_id('TREE_ROOT')
 
256
        root = mangle_tree.root
243
257
        #swap names
244
258
        name1 = mangle_tree.trans_id_tree_file_id('name1')
245
259
        name2 = mangle_tree.trans_id_tree_file_id('name2')
324
338
    def test_move_dangling_ie(self):
325
339
        create_tree, root = self.get_transform()
326
340
        # prepare tree
327
 
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
 
341
        root = create_tree.root
328
342
        create_tree.new_file('name1', root, 'hello1', 'name1')
329
343
        create_tree.apply()
330
344
        delete_contents, root = self.get_transform()
340
354
    def test_replace_dangling_ie(self):
341
355
        create_tree, root = self.get_transform()
342
356
        # prepare tree
343
 
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
 
357
        root = create_tree.root
344
358
        create_tree.new_file('name1', root, 'hello1', 'name1')
345
359
        create_tree.apply()
346
360
        delete_contents = TreeTransform(self.wt)
380
394
        self.assertEqual(os.readlink(self.wt.abspath('oz/wizard')),
381
395
                         'wizard-target')
382
396
 
383
 
 
384
397
    def get_conflicted(self):
385
398
        create,root = self.get_transform()
386
399
        create.new_file('dorothy', root, 'dorothy', 'dorothy-id')
514
527
        create.new_file('vfile', root, 'myfile-text', 'myfile-id')
515
528
        create.new_file('uvfile', root, 'othertext')
516
529
        create.apply()
517
 
        self.assertEqual(find_interesting(wt, wt, ['vfile']),
518
 
                         set(['myfile-id']))
519
 
        self.assertRaises(PathsNotVersionedError, find_interesting, wt, wt,
520
 
                          ['uvfile'])
 
530
        result = self.applyDeprecated(symbol_versioning.zero_fifteen,
 
531
            find_interesting, wt, wt, ['vfile'])
 
532
        self.assertEqual(result, set(['myfile-id']))
521
533
 
522
534
    def test_set_executability_order(self):
523
535
        """Ensure that executability behaves the same, no matter what order.
532
544
        wt = transform._tree
533
545
        transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
534
546
                           True)
535
 
        sac = transform.new_file('set_after_creation', root, 'Set after creation', 'sac')
 
547
        sac = transform.new_file('set_after_creation', root,
 
548
                                 'Set after creation', 'sac')
536
549
        transform.set_executability(True, sac)
537
 
        uws = transform.new_file('unset_without_set', root, 'Unset badly', 'uws')
 
550
        uws = transform.new_file('unset_without_set', root, 'Unset badly',
 
551
                                 'uws')
538
552
        self.assertRaises(KeyError, transform.set_executability, None, uws)
539
553
        transform.apply()
540
554
        self.assertTrue(wt.is_executable('soc'))
585
599
        bar1_abspath = self.wt.abspath('bar')
586
600
        self.assertEqual([bar1_abspath], stat_paths)
587
601
 
 
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)
 
606
        transform.apply()
 
607
        transform, root = self.get_transform()
 
608
        try:
 
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()))
 
620
        finally:
 
621
            transform.finalize()
 
622
 
 
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')
 
627
        transform.apply()
 
628
        transform, root = self.get_transform()
 
629
        try:
 
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()))
 
635
        finally:
 
636
            transform.finalize()
 
637
 
 
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')
 
644
        transform.apply()
 
645
        transform, root = self.get_transform()
 
646
        try:
 
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()))
 
651
 
 
652
            #content deletion
 
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()))
 
657
 
 
658
            #content change
 
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)
 
668
 
 
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()
 
679
 
 
680
            #execute bit
 
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)
 
687
 
 
688
            # filename
 
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 = {}
 
696
 
 
697
            # parent directory
 
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 = {}
 
706
 
 
707
        finally:
 
708
            transform.finalize()
 
709
 
 
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
 
716
        # works.
 
717
        transform, root = self.get_transform()
 
718
        transform.new_file('file1', root, 'blah', 'id-1')
 
719
        transform.new_file('file2', root, 'blah', 'id-2')
 
720
        transform.apply()
 
721
        transform, root = self.get_transform()
 
722
        try:
 
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()))
 
733
        finally:
 
734
            transform.finalize()
 
735
 
 
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')
 
742
        transform.apply()
 
743
        transform, root = self.get_transform()
 
744
        transform.delete_contents(transform.trans_id_tree_path('floater'))
 
745
        transform.apply()
 
746
        transform, root = self.get_transform()
 
747
        floater = transform.trans_id_tree_path('floater')
 
748
        try:
 
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()))
 
753
        finally:
 
754
            transform.finalize()
 
755
 
 
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')
 
762
        transform.apply()
 
763
        transform, root = self.get_transform()
 
764
        try:
 
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()))
 
775
        finally:
 
776
            transform.finalize()
 
777
 
 
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)
 
782
        transform.apply()
 
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)
 
788
        transform2.apply()
 
789
        self.assertEqual(transform2.rename_count, 2)
 
790
 
 
791
    def test_change_parent(self):
 
792
        """Ensure that after we change a parent, the results are still right.
 
793
 
 
794
        Renames and parent changes on pending transforms can happen as part
 
795
        of conflict resolution, and are explicitly permitted by the
 
796
        TreeTransform API.
 
797
 
 
798
        This test ensures they work correctly with the rename-avoidance
 
799
        optimization.
 
800
        """
 
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)
 
806
        transform.apply()
 
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)
 
812
 
 
813
    def test_cancel_parent(self):
 
814
        """Cancelling a parent doesn't cause deletion of a non-empty directory
 
815
 
 
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.
 
819
        """
 
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')
 
824
        try:
 
825
            transform.cancel_creation(parent1)
 
826
        except OSError:
 
827
            self.fail('Failed to move child1 before deleting parent1')
 
828
        transform.cancel_creation(child2)
 
829
        transform.create_directory(parent1)
 
830
        try:
 
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.
 
835
        except OSError:
 
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)
 
839
        transform.apply()
 
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)
 
844
 
 
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)
 
853
        try:
 
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.
 
857
        except OSError:
 
858
            self.fail('Transform still thinks child1 is a child of parent1')
 
859
        transform.finalize()
 
860
 
 
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')
 
865
        try:
 
866
            transform.create_directory(parent)
 
867
        except KeyError:
 
868
            self.fail("Can't handle contents with no name")
 
869
        transform.finalize()
 
870
 
 
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')
 
875
        try:
 
876
            transform.create_directory(parent)
 
877
        except KeyError:
 
878
            self.fail("Can't handle contents with no name")
 
879
        child = transform.new_directory('child', parent)
 
880
        transform.adjust_path('parent', root, parent)
 
881
        transform.apply()
 
882
        self.failUnlessExists(self.wt.abspath('parent/child'))
 
883
        self.assertEqual(1, transform.rename_count)
 
884
 
 
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)
 
890
        try:
 
891
            child2 = transform.new_directory('child', parent)
 
892
        except OSError:
 
893
            self.fail('Tranform tried to use the same limbo name twice')
 
894
        transform.adjust_path('child2', parent, child2)
 
895
        transform.apply()
 
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
 
900
        # as part of apply.
 
901
        self.assertEqual(2, transform.rename_count)
 
902
 
 
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)
 
910
        transform.apply()
 
911
        # limbo/new-1 => parent
 
912
        self.assertEqual(1, transform.rename_count)
 
913
 
 
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)
 
923
        transform.apply()
 
924
        # limbo/new-1 => parent2, limbo/new-2 => parent2/child1
 
925
        self.assertEqual(2, transform.rename_count)
 
926
 
 
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)
 
932
        try:
 
933
            transform.finalize()
 
934
        except OSError:
 
935
            self.fail('Tried to remove parent before child1')
 
936
 
 
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)
 
943
        transform.finalize()
 
944
 
588
945
 
589
946
class TransformGroup(object):
590
 
    def __init__(self, dirname):
 
947
    def __init__(self, dirname, root_id):
591
948
        self.name = dirname
592
949
        os.mkdir(dirname)
593
950
        self.wt = BzrDir.create_standalone_workingtree(dirname)
 
951
        self.wt.set_root_id(root_id)
594
952
        self.b = self.wt.branch
595
953
        self.tt = TreeTransform(self.wt)
596
954
        self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
597
955
 
 
956
 
598
957
def conflict_text(tree, merge):
599
958
    template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
600
959
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
602
961
 
603
962
class TestTransformMerge(TestCaseInTempDir):
604
963
    def test_text_merge(self):
605
 
        base = TransformGroup("base")
 
964
        root_id = generate_ids.gen_root_id()
 
965
        base = TransformGroup("base", root_id)
606
966
        base.tt.new_file('a', base.root, 'a\nb\nc\nd\be\n', 'a')
607
967
        base.tt.new_file('b', base.root, 'b1', 'b')
608
968
        base.tt.new_file('c', base.root, 'c', 'c')
612
972
        base.tt.new_directory('g', base.root, 'g')
613
973
        base.tt.new_directory('h', base.root, 'h')
614
974
        base.tt.apply()
615
 
        other = TransformGroup("other")
 
975
        other = TransformGroup("other", root_id)
616
976
        other.tt.new_file('a', other.root, 'y\nb\nc\nd\be\n', 'a')
617
977
        other.tt.new_file('b', other.root, 'b2', 'b')
618
978
        other.tt.new_file('c', other.root, 'c2', 'c')
623
983
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
624
984
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
625
985
        other.tt.apply()
626
 
        this = TransformGroup("this")
 
986
        this = TransformGroup("this", root_id)
627
987
        this.tt.new_file('a', this.root, 'a\nb\nc\nd\bz\n', 'a')
628
988
        this.tt.new_file('b', this.root, 'b', 'b')
629
989
        this.tt.new_file('c', this.root, 'c', 'c')
680
1040
    def test_file_merge(self):
681
1041
        if not has_symlinks():
682
1042
            raise TestSkipped('Symlinks are not supported on this platform')
683
 
        base = TransformGroup("BASE")
684
 
        this = TransformGroup("THIS")
685
 
        other = TransformGroup("OTHER")
 
1043
        root_id = generate_ids.gen_root_id()
 
1044
        base = TransformGroup("BASE", root_id)
 
1045
        this = TransformGroup("THIS", root_id)
 
1046
        other = TransformGroup("OTHER", root_id)
686
1047
        for tg in this, base, other:
687
1048
            tg.tt.new_directory('a', tg.root, 'a')
688
1049
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
720
1081
        self.assertIs(os.path.lexists(this.wt.abspath('h.OTHER')), True)
721
1082
 
722
1083
    def test_filename_merge(self):
723
 
        base = TransformGroup("BASE")
724
 
        this = TransformGroup("THIS")
725
 
        other = TransformGroup("OTHER")
 
1084
        root_id = generate_ids.gen_root_id()
 
1085
        base = TransformGroup("BASE", root_id)
 
1086
        this = TransformGroup("THIS", root_id)
 
1087
        other = TransformGroup("OTHER", root_id)
726
1088
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a') 
727
1089
                                   for t in [base, this, other]]
728
1090
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b') 
752
1114
        self.assertEqual(this.wt.id2path('f'), pathjoin('b/f1'))
753
1115
 
754
1116
    def test_filename_merge_conflicts(self):
755
 
        base = TransformGroup("BASE")
756
 
        this = TransformGroup("THIS")
757
 
        other = TransformGroup("OTHER")
 
1117
        root_id = generate_ids.gen_root_id()
 
1118
        base = TransformGroup("BASE", root_id)
 
1119
        this = TransformGroup("THIS", root_id)
 
1120
        other = TransformGroup("OTHER", root_id)
758
1121
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a') 
759
1122
                                   for t in [base, this, other]]
760
1123
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b') 
795
1158
        a.add(['foo', 'foo/bar', 'foo/baz'])
796
1159
        a.commit('initial commit')
797
1160
        b = BzrDir.create_standalone_workingtree('b')
798
 
        build_tree(a.basis_tree(), b)
 
1161
        basis = a.basis_tree()
 
1162
        basis.lock_read()
 
1163
        self.addCleanup(basis.unlock)
 
1164
        build_tree(basis, b)
799
1165
        self.assertIs(os.path.isdir('b/foo'), True)
800
1166
        self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
801
1167
        self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
802
1168
 
 
1169
    def test_build_with_references(self):
 
1170
        tree = self.make_branch_and_tree('source',
 
1171
            format='dirstate-with-subtree')
 
1172
        subtree = self.make_branch_and_tree('source/subtree',
 
1173
            format='dirstate-with-subtree')
 
1174
        tree.add_reference(subtree)
 
1175
        tree.commit('a revision')
 
1176
        tree.branch.create_checkout('target')
 
1177
        self.failUnlessExists('target')
 
1178
        self.failUnlessExists('target/subtree')
 
1179
 
803
1180
    def test_file_conflict_handling(self):
804
1181
        """Ensure that when building trees, conflict handling is done"""
805
1182
        source = self.make_branch_and_tree('source')
904
1281
        target = self.make_branch_and_tree('target')
905
1282
        self.build_tree(['target/name'])
906
1283
        target.add('name')
907
 
        self.assertRaises(AssertionError, build_tree, source.basis_tree(),
908
 
                          target)
 
1284
        self.assertRaises(errors.WorkingTreeAlreadyPopulated, 
 
1285
            build_tree, source.basis_tree(), target)
 
1286
 
 
1287
    def test_build_tree_rename_count(self):
 
1288
        source = self.make_branch_and_tree('source')
 
1289
        self.build_tree(['source/file1', 'source/dir1/'])
 
1290
        source.add(['file1', 'dir1'])
 
1291
        source.commit('add1')
 
1292
        target1 = self.make_branch_and_tree('target1')
 
1293
        transform_result = build_tree(source.basis_tree(), target1)
 
1294
        self.assertEqual(2, transform_result.rename_count)
 
1295
 
 
1296
        self.build_tree(['source/dir1/file2'])
 
1297
        source.add(['dir1/file2'])
 
1298
        source.commit('add3')
 
1299
        target2 = self.make_branch_and_tree('target2')
 
1300
        transform_result = build_tree(source.basis_tree(), target2)
 
1301
        # children of non-root directories should not be renamed
 
1302
        self.assertEqual(2, transform_result.rename_count)
909
1303
 
910
1304
 
911
1305
class MockTransform(object):
919
1313
                return True
920
1314
        return False
921
1315
 
 
1316
 
922
1317
class MockEntry(object):
923
1318
    def __init__(self):
924
1319
        object.__init__(self)