~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: John Arbash Meinel
  • Date: 2006-08-14 16:16:53 UTC
  • mto: (1946.2.6 reduce-knit-churn)
  • mto: This revision was merged to the branch mainline in revision 1919.
  • Revision ID: john@arbash-meinel.com-20060814161653-54cdcdadcd4e9003
Remove bogus entry from BRANCH.TODO

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
import os
18
 
import stat
19
 
import sys
20
18
 
21
 
from bzrlib import (
22
 
    tests,
23
 
    urlutils,
24
 
    )
25
19
from bzrlib.bzrdir import BzrDir
26
20
from bzrlib.conflicts import (DuplicateEntry, DuplicateID, MissingParent,
27
 
                              UnversionedParent, ParentLoop, DeletingParent,)
 
21
                              UnversionedParent, ParentLoop)
28
22
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
29
23
                           ReusingTransform, CantMoveRoot, 
30
24
                           PathsNotVersionedError, ExistingLimbo,
35
29
from bzrlib.transform import (TreeTransform, ROOT_PARENT, FinalPaths, 
36
30
                              resolve_conflicts, cook_conflicts, 
37
31
                              find_interesting, build_tree, get_backup_name)
38
 
from bzrlib.workingtree import gen_root_id
39
 
 
 
32
import bzrlib.urlutils as urlutils
40
33
 
41
34
class TestTreeTransform(TestCaseInTempDir):
42
35
 
48
41
    def get_transform(self):
49
42
        transform = TreeTransform(self.wt)
50
43
        #self.addCleanup(transform.finalize)
51
 
        return transform, transform.root
 
44
        return transform, transform.trans_id_tree_file_id(self.wt.get_root_id())
52
45
 
53
46
    def test_existing_limbo(self):
54
47
        limbo_name = urlutils.local_path_from_url(
198
191
        transform3.delete_contents(oz_id)
199
192
        self.assertEqual(transform3.find_conflicts(), 
200
193
                         [('missing parent', oz_id)])
201
 
        root_id = transform3.root
 
194
        root_id = transform3.trans_id_tree_file_id('TREE_ROOT')
202
195
        tip_id = transform3.trans_id_tree_file_id('tip-id')
203
196
        transform3.adjust_path('tip', root_id, tip_id)
204
197
        transform3.apply()
230
223
    def test_name_invariants(self):
231
224
        create_tree, root = self.get_transform()
232
225
        # prepare tree
233
 
        root = create_tree.root
 
226
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
234
227
        create_tree.new_file('name1', root, 'hello1', 'name1')
235
228
        create_tree.new_file('name2', root, 'hello2', 'name2')
236
229
        ddir = create_tree.new_directory('dying_directory', root, 'ddir')
240
233
        create_tree.apply()
241
234
 
242
235
        mangle_tree,root = self.get_transform()
243
 
        root = mangle_tree.root
 
236
        root = mangle_tree.trans_id_tree_file_id('TREE_ROOT')
244
237
        #swap names
245
238
        name1 = mangle_tree.trans_id_tree_file_id('name1')
246
239
        name2 = mangle_tree.trans_id_tree_file_id('name2')
325
318
    def test_move_dangling_ie(self):
326
319
        create_tree, root = self.get_transform()
327
320
        # prepare tree
328
 
        root = create_tree.root
 
321
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
329
322
        create_tree.new_file('name1', root, 'hello1', 'name1')
330
323
        create_tree.apply()
331
324
        delete_contents, root = self.get_transform()
341
334
    def test_replace_dangling_ie(self):
342
335
        create_tree, root = self.get_transform()
343
336
        # prepare tree
344
 
        root = create_tree.root
 
337
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
345
338
        create_tree.new_file('name1', root, 'hello1', 'name1')
346
339
        create_tree.apply()
347
340
        delete_contents = TreeTransform(self.wt)
394
387
                                         'dorothy-id')
395
388
        old_dorothy = conflicts.trans_id_tree_file_id('dorothy-id')
396
389
        oz = conflicts.trans_id_tree_file_id('oz-id')
397
 
        # set up DeletedParent parent conflict
 
390
        # set up missing, unversioned parent
398
391
        conflicts.delete_versioned(oz)
399
392
        emerald = conflicts.trans_id_tree_file_id('emerald-id')
400
 
        # set up MissingParent conflict
401
 
        munchkincity = conflicts.trans_id_file_id('munchkincity-id')
402
 
        conflicts.adjust_path('munchkincity', root, munchkincity)
403
 
        conflicts.new_directory('auntem', munchkincity, 'auntem-id')
404
393
        # set up parent loop
405
394
        conflicts.adjust_path('emeraldcity', emerald, emerald)
406
395
        return conflicts, emerald, oz, old_dorothy, new_dorothy
427
416
                                   'dorothy.moved', 'dorothy', None,
428
417
                                   'dorothy-id')
429
418
        self.assertEqual(cooked_conflicts[1], duplicate_id)
430
 
        missing_parent = MissingParent('Created directory', 'munchkincity',
431
 
                                       'munchkincity-id')
432
 
        deleted_parent = DeletingParent('Not deleting', 'oz', 'oz-id')
 
419
        missing_parent = MissingParent('Not deleting', 'oz', 'oz-id')
433
420
        self.assertEqual(cooked_conflicts[2], missing_parent)
434
 
        unversioned_parent = UnversionedParent('Versioned directory',
435
 
                                               'munchkincity',
436
 
                                               'munchkincity-id')
437
 
        unversioned_parent2 = UnversionedParent('Versioned directory', 'oz',
 
421
        unversioned_parent = UnversionedParent('Versioned directory', 'oz',
438
422
                                               'oz-id')
439
423
        self.assertEqual(cooked_conflicts[3], unversioned_parent)
440
424
        parent_loop = ParentLoop('Cancelled move', 'oz/emeraldcity', 
441
425
                                 'oz/emeraldcity', 'emerald-id', 'emerald-id')
442
 
        self.assertEqual(cooked_conflicts[4], deleted_parent)
443
 
        self.assertEqual(cooked_conflicts[5], unversioned_parent2)
444
 
        self.assertEqual(cooked_conflicts[6], parent_loop)
445
 
        self.assertEqual(len(cooked_conflicts), 7)
 
426
        self.assertEqual(cooked_conflicts[4], parent_loop)
 
427
        self.assertEqual(len(cooked_conflicts), 5)
446
428
        tt.finalize()
447
429
 
448
430
    def test_string_conflicts(self):
458
440
        self.assertEqual(conflicts_s[1], 'Conflict adding id to dorothy.  '
459
441
                                         'Unversioned existing file '
460
442
                                         'dorothy.moved.')
461
 
        self.assertEqual(conflicts_s[2], 'Conflict adding files to'
462
 
                                         ' munchkincity.  Created directory.')
463
 
        self.assertEqual(conflicts_s[3], 'Conflict because munchkincity is not'
464
 
                                         ' versioned, but has versioned'
465
 
                                         ' children.  Versioned directory.')
466
 
        self.assertEqualDiff(conflicts_s[4], "Conflict: can't delete oz because it"
467
 
                                         " is not empty.  Not deleting.")
468
 
        self.assertEqual(conflicts_s[5], 'Conflict because oz is not'
469
 
                                         ' versioned, but has versioned'
470
 
                                         ' children.  Versioned directory.')
471
 
        self.assertEqual(conflicts_s[6], 'Conflict moving oz/emeraldcity into'
 
443
        self.assertEqual(conflicts_s[2], 'Conflict adding files to oz.  '
 
444
                                         'Not deleting.')
 
445
        self.assertEqual(conflicts_s[3], 'Conflict adding versioned files to '
 
446
                                         'oz.  Versioned directory.')
 
447
        self.assertEqual(conflicts_s[4], 'Conflict moving oz/emeraldcity into'
472
448
                                         ' oz/emeraldcity.  Cancelled move.')
473
449
 
474
450
    def test_moving_versioned_directories(self):
541
517
        self.assertTrue(wt.is_executable('soc'))
542
518
        self.assertTrue(wt.is_executable('sac'))
543
519
 
544
 
    def test_preserve_mode(self):
545
 
        """File mode is preserved when replacing content"""
546
 
        if sys.platform == 'win32':
547
 
            raise TestSkipped('chmod has no effect on win32')
548
 
        transform, root = self.get_transform()
549
 
        transform.new_file('file1', root, 'contents', 'file1-id', True)
550
 
        transform.apply()
551
 
        self.assertTrue(self.wt.is_executable('file1-id'))
552
 
        transform, root = self.get_transform()
553
 
        file1_id = transform.trans_id_tree_file_id('file1-id')
554
 
        transform.delete_contents(file1_id)
555
 
        transform.create_file('contents2', file1_id)
556
 
        transform.apply()
557
 
        self.assertTrue(self.wt.is_executable('file1-id'))
558
 
 
559
 
    def test__set_mode_stats_correctly(self):
560
 
        """_set_mode stats to determine file mode."""
561
 
        if sys.platform == 'win32':
562
 
            raise TestSkipped('chmod has no effect on win32')
563
 
 
564
 
        stat_paths = []
565
 
        real_stat = os.stat
566
 
        def instrumented_stat(path):
567
 
            stat_paths.append(path)
568
 
            return real_stat(path)
569
 
 
570
 
        transform, root = self.get_transform()
571
 
 
572
 
        bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
573
 
                                     file_id='bar-id-1', executable=False)
574
 
        transform.apply()
575
 
 
576
 
        transform, root = self.get_transform()
577
 
        bar1_id = transform.trans_id_tree_path('bar')
578
 
        bar2_id = transform.trans_id_tree_path('bar2')
579
 
        try:
580
 
            os.stat = instrumented_stat
581
 
            transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
582
 
        finally:
583
 
            os.stat = real_stat
584
 
            transform.finalize()
585
 
 
586
 
        bar1_abspath = self.wt.abspath('bar')
587
 
        self.assertEqual([bar1_abspath], stat_paths)
588
 
 
589
520
 
590
521
class TransformGroup(object):
591
 
    def __init__(self, dirname, root_id):
 
522
    def __init__(self, dirname):
592
523
        self.name = dirname
593
524
        os.mkdir(dirname)
594
525
        self.wt = BzrDir.create_standalone_workingtree(dirname)
595
 
        self.wt.set_root_id(root_id)
596
526
        self.b = self.wt.branch
597
527
        self.tt = TreeTransform(self.wt)
598
528
        self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
604
534
 
605
535
class TestTransformMerge(TestCaseInTempDir):
606
536
    def test_text_merge(self):
607
 
        root_id = gen_root_id()
608
 
        base = TransformGroup("base", root_id)
 
537
        base = TransformGroup("base")
609
538
        base.tt.new_file('a', base.root, 'a\nb\nc\nd\be\n', 'a')
610
539
        base.tt.new_file('b', base.root, 'b1', 'b')
611
540
        base.tt.new_file('c', base.root, 'c', 'c')
615
544
        base.tt.new_directory('g', base.root, 'g')
616
545
        base.tt.new_directory('h', base.root, 'h')
617
546
        base.tt.apply()
618
 
        other = TransformGroup("other", root_id)
 
547
        other = TransformGroup("other")
619
548
        other.tt.new_file('a', other.root, 'y\nb\nc\nd\be\n', 'a')
620
549
        other.tt.new_file('b', other.root, 'b2', 'b')
621
550
        other.tt.new_file('c', other.root, 'c2', 'c')
626
555
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
627
556
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
628
557
        other.tt.apply()
629
 
        this = TransformGroup("this", root_id)
 
558
        this = TransformGroup("this")
630
559
        this.tt.new_file('a', this.root, 'a\nb\nc\nd\bz\n', 'a')
631
560
        this.tt.new_file('b', this.root, 'b', 'b')
632
561
        this.tt.new_file('c', this.root, 'c', 'c')
683
612
    def test_file_merge(self):
684
613
        if not has_symlinks():
685
614
            raise TestSkipped('Symlinks are not supported on this platform')
686
 
        root_id = gen_root_id()
687
 
        base = TransformGroup("BASE", root_id)
688
 
        this = TransformGroup("THIS", root_id)
689
 
        other = TransformGroup("OTHER", root_id)
 
615
        base = TransformGroup("BASE")
 
616
        this = TransformGroup("THIS")
 
617
        other = TransformGroup("OTHER")
690
618
        for tg in this, base, other:
691
619
            tg.tt.new_directory('a', tg.root, 'a')
692
620
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
724
652
        self.assertIs(os.path.lexists(this.wt.abspath('h.OTHER')), True)
725
653
 
726
654
    def test_filename_merge(self):
727
 
        root_id = gen_root_id()
728
 
        base = TransformGroup("BASE", root_id)
729
 
        this = TransformGroup("THIS", root_id)
730
 
        other = TransformGroup("OTHER", root_id)
 
655
        base = TransformGroup("BASE")
 
656
        this = TransformGroup("THIS")
 
657
        other = TransformGroup("OTHER")
731
658
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a') 
732
659
                                   for t in [base, this, other]]
733
660
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b') 
757
684
        self.assertEqual(this.wt.id2path('f'), pathjoin('b/f1'))
758
685
 
759
686
    def test_filename_merge_conflicts(self):
760
 
        root_id = gen_root_id()
761
 
        base = TransformGroup("BASE", root_id)
762
 
        this = TransformGroup("THIS", root_id)
763
 
        other = TransformGroup("OTHER", root_id)
 
687
        base = TransformGroup("BASE")
 
688
        this = TransformGroup("THIS")
 
689
        other = TransformGroup("OTHER")
764
690
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a') 
765
691
                                   for t in [base, this, other]]
766
692
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b') 
787
713
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.OTHER')), False)
788
714
        self.assertEqual(this.wt.id2path('i'), pathjoin('b/i1.OTHER'))
789
715
 
790
 
 
791
 
class TestBuildTree(tests.TestCaseWithTransport):
792
 
 
 
716
class TestBuildTree(TestCaseInTempDir):
793
717
    def test_build_tree(self):
794
718
        if not has_symlinks():
795
719
            raise TestSkipped('Test requires symlink support')
805
729
        self.assertIs(os.path.isdir('b/foo'), True)
806
730
        self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
807
731
        self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
808
 
 
809
 
    def test_file_conflict_handling(self):
810
 
        """Ensure that when building trees, conflict handling is done"""
811
 
        source = self.make_branch_and_tree('source')
812
 
        target = self.make_branch_and_tree('target')
813
 
        self.build_tree(['source/file', 'target/file'])
814
 
        source.add('file', 'new-file')
815
 
        source.commit('added file')
816
 
        build_tree(source.basis_tree(), target)
817
 
        self.assertEqual([DuplicateEntry('Moved existing file to',
818
 
                          'file.moved', 'file', None, 'new-file')],
819
 
                         target.conflicts())
820
 
        target2 = self.make_branch_and_tree('target2')
821
 
        target_file = file('target2/file', 'wb')
822
 
        try:
823
 
            source_file = file('source/file', 'rb')
824
 
            try:
825
 
                target_file.write(source_file.read())
826
 
            finally:
827
 
                source_file.close()
828
 
        finally:
829
 
            target_file.close()
830
 
        build_tree(source.basis_tree(), target2)
831
 
        self.assertEqual([], target2.conflicts())
832
 
 
833
 
    def test_symlink_conflict_handling(self):
834
 
        """Ensure that when building trees, conflict handling is done"""
835
 
        if not has_symlinks():
836
 
            raise TestSkipped('Test requires symlink support')
837
 
        source = self.make_branch_and_tree('source')
838
 
        os.symlink('foo', 'source/symlink')
839
 
        source.add('symlink', 'new-symlink')
840
 
        source.commit('added file')
841
 
        target = self.make_branch_and_tree('target')
842
 
        os.symlink('bar', 'target/symlink')
843
 
        build_tree(source.basis_tree(), target)
844
 
        self.assertEqual([DuplicateEntry('Moved existing file to',
845
 
            'symlink.moved', 'symlink', None, 'new-symlink')],
846
 
            target.conflicts())
847
 
        target = self.make_branch_and_tree('target2')
848
 
        os.symlink('foo', 'target2/symlink')
849
 
        build_tree(source.basis_tree(), target)
850
 
        self.assertEqual([], target.conflicts())
851
732
        
852
 
    def test_directory_conflict_handling(self):
853
 
        """Ensure that when building trees, conflict handling is done"""
854
 
        source = self.make_branch_and_tree('source')
855
 
        target = self.make_branch_and_tree('target')
856
 
        self.build_tree(['source/dir1/', 'source/dir1/file', 'target/dir1/'])
857
 
        source.add(['dir1', 'dir1/file'], ['new-dir1', 'new-file'])
858
 
        source.commit('added file')
859
 
        build_tree(source.basis_tree(), target)
860
 
        self.assertEqual([], target.conflicts())
861
 
        self.failUnlessExists('target/dir1/file')
862
 
 
863
 
        # Ensure contents are merged
864
 
        target = self.make_branch_and_tree('target2')
865
 
        self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
866
 
        build_tree(source.basis_tree(), target)
867
 
        self.assertEqual([], target.conflicts())
868
 
        self.failUnlessExists('target2/dir1/file2')
869
 
        self.failUnlessExists('target2/dir1/file')
870
 
 
871
 
        # Ensure new contents are suppressed for existing branches
872
 
        target = self.make_branch_and_tree('target3')
873
 
        self.make_branch('target3/dir1')
874
 
        self.build_tree(['target3/dir1/file2'])
875
 
        build_tree(source.basis_tree(), target)
876
 
        self.failIfExists('target3/dir1/file')
877
 
        self.failUnlessExists('target3/dir1/file2')
878
 
        self.failUnlessExists('target3/dir1.diverted/file')
879
 
        self.assertEqual([DuplicateEntry('Diverted to',
880
 
            'dir1.diverted', 'dir1', 'new-dir1', None)],
881
 
            target.conflicts())
882
 
 
883
 
        target = self.make_branch_and_tree('target4')
884
 
        self.build_tree(['target4/dir1/'])
885
 
        self.make_branch('target4/dir1/file')
886
 
        build_tree(source.basis_tree(), target)
887
 
        self.failUnlessExists('target4/dir1/file')
888
 
        self.assertEqual('directory', file_kind('target4/dir1/file'))
889
 
        self.failUnlessExists('target4/dir1/file.diverted')
890
 
        self.assertEqual([DuplicateEntry('Diverted to',
891
 
            'dir1/file.diverted', 'dir1/file', 'new-file', None)],
892
 
            target.conflicts())
893
 
 
894
 
    def test_mixed_conflict_handling(self):
895
 
        """Ensure that when building trees, conflict handling is done"""
896
 
        source = self.make_branch_and_tree('source')
897
 
        target = self.make_branch_and_tree('target')
898
 
        self.build_tree(['source/name', 'target/name/'])
899
 
        source.add('name', 'new-name')
900
 
        source.commit('added file')
901
 
        build_tree(source.basis_tree(), target)
902
 
        self.assertEqual([DuplicateEntry('Moved existing file to',
903
 
            'name.moved', 'name', None, 'new-name')], target.conflicts())
904
 
 
905
 
    def test_raises_in_populated(self):
906
 
        source = self.make_branch_and_tree('source')
907
 
        self.build_tree(['source/name'])
908
 
        source.add('name')
909
 
        source.commit('added name')
910
 
        target = self.make_branch_and_tree('target')
911
 
        self.build_tree(['target/name'])
912
 
        target.add('name')
913
 
        self.assertRaises(AssertionError, build_tree, source.basis_tree(),
914
 
                          target)
915
 
 
916
 
 
917
733
class MockTransform(object):
918
734
 
919
735
    def has_named_child(self, by_parent, parent_id, name):