/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_bundle.py

  • Committer: Jan Balster
  • Date: 2006-08-15 12:39:42 UTC
  • mfrom: (1923 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1928.
  • Revision ID: jan@merlinux.de-20060815123942-22c388c6e9a8ac91
merge bzr.dev 1923

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2004-2006 by Canonical Ltd
2
 
 
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
from cStringIO import StringIO
 
18
import os
 
19
import sys
 
20
import tempfile
18
21
 
 
22
from bzrlib import inventory
19
23
from bzrlib.builtins import merge
20
24
from bzrlib.bzrdir import BzrDir
21
25
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
22
26
from bzrlib.bundle.bundle_data import BundleTree
23
27
from bzrlib.bundle.serializer import write_bundle, read_bundle
 
28
from bzrlib.branch import Branch
24
29
from bzrlib.diff import internal_diff
25
 
from bzrlib.errors import BzrError, TestamentMismatch, NotABundle, BadBundle
 
30
from bzrlib.errors import (BzrError, TestamentMismatch, NotABundle, BadBundle, 
 
31
                           NoSuchFile,)
26
32
from bzrlib.merge import Merge3Merger
27
33
from bzrlib.osutils import has_symlinks, sha_file
28
34
from bzrlib.tests import (TestCaseInTempDir, TestCaseWithTransport,
33
39
 
34
40
class MockTree(object):
35
41
    def __init__(self):
36
 
        from bzrlib.inventory import RootEntry, ROOT_ID
 
42
        from bzrlib.inventory import InventoryDirectory, ROOT_ID
37
43
        object.__init__(self)
38
44
        self.paths = {ROOT_ID: ""}
39
45
        self.ids = {"": ROOT_ID}
40
46
        self.contents = {}
41
 
        self.root = RootEntry(ROOT_ID)
 
47
        self.root = InventoryDirectory(ROOT_ID, '', None)
42
48
 
43
49
    inventory = property(lambda x:x)
44
50
 
52
58
            return self.make_entry(file_id, self.paths[file_id])
53
59
 
54
60
    def parent_id(self, file_id):
55
 
        from os.path import dirname
56
 
        parent_dir = dirname(self.paths[file_id])
 
61
        parent_dir = os.path.dirname(self.paths[file_id])
57
62
        if parent_dir == "":
58
63
            return None
59
64
        return self.ids[parent_dir]
70
75
        return kind
71
76
 
72
77
    def make_entry(self, file_id, path):
73
 
        from os.path import basename
74
78
        from bzrlib.inventory import (InventoryEntry, InventoryFile
75
79
                                    , InventoryDirectory, InventoryLink)
76
 
        name = basename(path)
 
80
        name = os.path.basename(path)
77
81
        kind = self.get_file_kind(file_id)
78
82
        parent_id = self.parent_id(file_id)
79
83
        text_sha_1, text_size = self.contents_stats(file_id)
287
291
    def test_iteration(self):
288
292
        """Ensure that iteration through ids works properly"""
289
293
        btree = self.make_tree_1()[0]
290
 
        self.assertEqual(self.sorted_ids(btree), ['a', 'b', 'c', 'd'])
 
294
        self.assertEqual(self.sorted_ids(btree),
 
295
            [inventory.ROOT_ID, 'a', 'b', 'c', 'd'])
291
296
        btree.note_deletion("grandparent/parent/file")
292
297
        btree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
293
298
        btree.note_last_changed("grandparent/alt_parent/fool", 
294
299
                                "revisionidiguess")
295
 
        self.assertEqual(self.sorted_ids(btree), ['a', 'b', 'd', 'e'])
296
 
 
297
 
 
298
 
class BundleTester(TestCaseInTempDir):
 
300
        self.assertEqual(self.sorted_ids(btree),
 
301
            [inventory.ROOT_ID, 'a', 'b', 'd', 'e'])
 
302
 
 
303
 
 
304
class BundleTester(TestCaseWithTransport):
299
305
 
300
306
    def create_bundle_text(self, base_rev_id, rev_id):
301
307
        bundle_txt = StringIO()
369
375
 
370
376
    def test_crlf_bundle(self):
371
377
        try:
372
 
            read_bundle(StringIO('# Bazaar revision bundle v0.7\r\n'))
 
378
            read_bundle(StringIO('# Bazaar revision bundle v0.8\r\n'))
373
379
        except BadBundle:
374
380
            # It is currently permitted for bundles with crlf line endings to
375
381
            # make read_bundle raise a BadBundle, but this should be fixed.
379
385
    def get_checkout(self, rev_id, checkout_dir=None):
380
386
        """Get a new tree, with the specified revision in it.
381
387
        """
382
 
        from bzrlib.branch import Branch
383
 
        import tempfile
384
388
 
385
389
        if checkout_dir is None:
386
390
            checkout_dir = tempfile.mkdtemp(prefix='test-branch-', dir='.')
387
391
        else:
388
 
            import os
389
392
            if not os.path.exists(checkout_dir):
390
393
                os.mkdir(checkout_dir)
391
394
        tree = BzrDir.create_standalone_workingtree(checkout_dir)
398
401
        for ancestor in ancestors:
399
402
            old = self.b1.repository.revision_tree(ancestor)
400
403
            new = tree.branch.repository.revision_tree(ancestor)
 
404
 
 
405
            # Check that there aren't any inventory level changes
 
406
            delta = new.changes_from(old)
 
407
            self.assertFalse(delta.has_changed(),
 
408
                             'Revision %s not copied correctly.'
 
409
                             % (ancestor,))
 
410
 
 
411
            # Now check that the file contents are all correct
401
412
            for inventory_id in old:
402
413
                try:
403
414
                    old_file = old.get_file(inventory_id)
404
 
                except:
 
415
                except NoSuchFile:
405
416
                    continue
406
417
                if old_file is None:
407
418
                    continue
411
422
            rh = self.b1.revision_history()
412
423
            tree.branch.set_revision_history(rh[:rh.index(rev_id)+1])
413
424
            tree.update()
 
425
            delta = tree.changes_from(self.b1.repository.revision_tree(rev_id))
 
426
            self.assertFalse(delta.has_changed(),
 
427
                             'Working tree has modifications')
414
428
        return tree
415
429
 
416
430
    def valid_apply_bundle(self, base_rev_id, info, checkout_dir=None):
462
476
            #         to_tree.get_file(fileid).read())
463
477
 
464
478
    def test_bundle(self):
465
 
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
 
479
        self.tree1 = self.make_branch_and_tree('b1')
466
480
        self.b1 = self.tree1.branch
467
481
 
468
482
        open('b1/one', 'wb').write('one\n')
484
498
                , 'b1/dir/'
485
499
                , 'b1/dir/filein subdir.c'
486
500
                , 'b1/dir/WithCaps.txt'
487
 
                , 'b1/dir/trailing space '
 
501
                , 'b1/dir/ pre space'
488
502
                , 'b1/sub/'
489
503
                , 'b1/sub/sub/'
490
504
                , 'b1/sub/sub/nonempty.txt'
491
 
                # Tabs are not valid in filenames on windows
492
 
                #'b1/with\ttab.txt'
493
505
                ])
494
506
        open('b1/sub/sub/emptyfile.txt', 'wb').close()
495
507
        open('b1/dir/nolastnewline.txt', 'wb').write('bloop')
501
513
                , 'dir'
502
514
                , 'dir/filein subdir.c'
503
515
                , 'dir/WithCaps.txt'
504
 
                , 'dir/trailing space '
 
516
                , 'dir/ pre space'
505
517
                , 'dir/nolastnewline.txt'
506
518
                , 'sub'
507
519
                , 'sub/sub'
533
545
        # Check a rollup bundle 
534
546
        bundle = self.get_valid_bundle(None, 'a@cset-0-3')
535
547
 
536
 
 
537
548
        # Now move the directory
538
549
        self.tree1.rename_one('dir', 'sub/dir')
539
550
        self.tree1.commit('rename dir', rev_id='a@cset-0-4')
544
555
 
545
556
        # Modified files
546
557
        open('b1/sub/dir/WithCaps.txt', 'ab').write('\nAdding some text\n')
547
 
        open('b1/sub/dir/trailing space ', 'ab').write('\nAdding some\nDOS format lines\n')
 
558
        open('b1/sub/dir/ pre space', 'ab').write('\r\nAdding some\r\nDOS format lines\r\n')
548
559
        open('b1/sub/dir/nolastnewline.txt', 'ab').write('\n')
549
 
        self.tree1.rename_one('sub/dir/trailing space ', 
550
 
                              'sub/ start and end space ')
 
560
        self.tree1.rename_one('sub/dir/ pre space', 
 
561
                              'sub/ start space')
551
562
        self.tree1.commit('Modified files', rev_id='a@cset-0-5')
552
563
        bundle = self.get_valid_bundle('a@cset-0-4', 'a@cset-0-5')
553
564
 
554
 
        # Handle international characters
555
 
        try:
556
 
            f = open(u'b1/with Dod\xe9', 'wb')
557
 
        except UnicodeEncodeError:
558
 
            raise TestSkipped("Filesystem doesn't support unicode")
559
 
        f.write((u'A file\n'
560
 
            u'With international man of mystery\n'
561
 
            u'William Dod\xe9\n').encode('utf-8'))
562
 
        self.tree1.add([u'with Dod\xe9'])
563
 
        # BUG: (sort of) You must set verbose=False, so that python doesn't try
564
 
        #       and print the name of William Dode as part of the commit
565
 
        self.tree1.commit(u'i18n commit from William Dod\xe9', 
566
 
                          rev_id='a@cset-0-6', committer=u'William Dod\xe9',
567
 
                          verbose=False)
568
 
        bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
569
565
        self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
570
566
        self.tree1.rename_one('with space.txt', 'WithCaps.txt')
571
567
        self.tree1.rename_one('temp', 'with space.txt')
572
 
        self.tree1.commit(u'swap filenames', rev_id='a@cset-0-7',
 
568
        self.tree1.commit(u'swap filenames', rev_id='a@cset-0-6',
 
569
                          verbose=False)
 
570
        bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
 
571
        other = self.get_checkout('a@cset-0-5')
 
572
        other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
 
573
        other.commit('rename file', rev_id='a@cset-0-6b')
 
574
        merge([other.basedir, -1], [None, None], this_dir=self.tree1.basedir)
 
575
        self.tree1.commit(u'Merge', rev_id='a@cset-0-7',
573
576
                          verbose=False)
574
577
        bundle = self.get_valid_bundle('a@cset-0-6', 'a@cset-0-7')
575
 
        other = self.get_checkout('a@cset-0-6')
576
 
        other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
577
 
        other.commit('rename file', rev_id='a@cset-0-7b')
578
 
        merge([other.basedir, -1], [None, None], this_dir=self.tree1.basedir)
579
 
        self.tree1.commit(u'Merge', rev_id='a@cset-0-8',
580
 
                          verbose=False)
581
 
        bundle = self.get_valid_bundle('a@cset-0-7', 'a@cset-0-8')
582
578
 
583
579
    def test_symlink_bundle(self):
584
580
        if not has_symlinks():
616
612
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
617
613
        self.b1 = self.tree1.branch
618
614
        tt = TreeTransform(self.tree1)
619
 
        tt.new_file('file', tt.root, '\x00\xff', 'binary-1')
620
 
        tt.new_file('file2', tt.root, '\x00\xff', 'binary-2')
 
615
        
 
616
        # Add
 
617
        tt.new_file('file', tt.root, '\x00\n\x00\r\x01\n\x02\r\xff', 'binary-1')
 
618
        tt.new_file('file2', tt.root, '\x01\n\x02\r\x03\n\x04\r\xff', 'binary-2')
621
619
        tt.apply()
622
620
        self.tree1.commit('add binary', rev_id='b@cset-0-1')
623
621
        self.get_valid_bundle(None, 'b@cset-0-1')
 
622
 
 
623
        # Delete
624
624
        tt = TreeTransform(self.tree1)
625
625
        trans_id = tt.trans_id_tree_file_id('binary-1')
626
626
        tt.delete_contents(trans_id)
627
627
        tt.apply()
628
628
        self.tree1.commit('delete binary', rev_id='b@cset-0-2')
629
629
        self.get_valid_bundle('b@cset-0-1', 'b@cset-0-2')
 
630
 
 
631
        # Rename & modify
630
632
        tt = TreeTransform(self.tree1)
631
633
        trans_id = tt.trans_id_tree_file_id('binary-2')
632
634
        tt.adjust_path('file3', tt.root, trans_id)
633
635
        tt.delete_contents(trans_id)
634
 
        tt.create_file('filecontents\x00', trans_id)
 
636
        tt.create_file('file\rcontents\x00\n\x00', trans_id)
635
637
        tt.apply()
636
638
        self.tree1.commit('rename and modify binary', rev_id='b@cset-0-3')
637
639
        self.get_valid_bundle('b@cset-0-2', 'b@cset-0-3')
 
640
 
 
641
        # Modify
638
642
        tt = TreeTransform(self.tree1)
639
643
        trans_id = tt.trans_id_tree_file_id('binary-2')
640
644
        tt.delete_contents(trans_id)
641
 
        tt.create_file('\x00filecontents', trans_id)
 
645
        tt.create_file('\x00file\rcontents', trans_id)
642
646
        tt.apply()
643
647
        self.tree1.commit('just modify binary', rev_id='b@cset-0-4')
644
648
        self.get_valid_bundle('b@cset-0-3', 'b@cset-0-4')
645
649
 
 
650
        # Rollup
 
651
        self.get_valid_bundle(None, 'b@cset-0-4')
 
652
 
646
653
    def test_last_modified(self):
647
654
        self.tree1 = BzrDir.create_standalone_workingtree('b1')
648
655
        self.b1 = self.tree1.branch
689
696
        self.assertContainsRe(bundle_file.getvalue(), 'one')
690
697
        self.assertContainsRe(bundle_file.getvalue(), 'three')
691
698
 
 
699
    def test_unicode_bundle(self):
 
700
        # Handle international characters
 
701
        os.mkdir('b1')
 
702
        try:
 
703
            f = open(u'b1/with Dod\xe9', 'wb')
 
704
        except UnicodeEncodeError:
 
705
            raise TestSkipped("Filesystem doesn't support unicode")
 
706
 
 
707
        self.tree1 = self.make_branch_and_tree('b1')
 
708
        self.b1 = self.tree1.branch
 
709
 
 
710
        f.write((u'A file\n'
 
711
            u'With international man of mystery\n'
 
712
            u'William Dod\xe9\n').encode('utf-8'))
 
713
        f.close()
 
714
 
 
715
        self.tree1.add([u'with Dod\xe9'])
 
716
        self.tree1.commit(u'i18n commit from William Dod\xe9', 
 
717
                          rev_id='i18n-1', committer=u'William Dod\xe9')
 
718
 
 
719
        # Add
 
720
        bundle = self.get_valid_bundle(None, 'i18n-1')
 
721
 
 
722
        # Modified
 
723
        f = open(u'b1/with Dod\xe9', 'wb')
 
724
        f.write(u'Modified \xb5\n'.encode('utf8'))
 
725
        f.close()
 
726
        self.tree1.commit(u'modified', rev_id='i18n-2')
 
727
 
 
728
        bundle = self.get_valid_bundle('i18n-1', 'i18n-2')
 
729
        
 
730
        # Renamed
 
731
        self.tree1.rename_one(u'with Dod\xe9', u'B\xe5gfors')
 
732
        self.tree1.commit(u'renamed, the new i18n man', rev_id='i18n-3',
 
733
                          committer=u'Erik B\xe5gfors')
 
734
 
 
735
        bundle = self.get_valid_bundle('i18n-2', 'i18n-3')
 
736
 
 
737
        # Removed
 
738
        self.tree1.remove([u'B\xe5gfors'])
 
739
        self.tree1.commit(u'removed', rev_id='i18n-4')
 
740
 
 
741
        bundle = self.get_valid_bundle('i18n-3', 'i18n-4')
 
742
 
 
743
        # Rollup
 
744
        bundle = self.get_valid_bundle(None, 'i18n-4')
 
745
 
 
746
 
 
747
    def test_whitespace_bundle(self):
 
748
        if sys.platform in ('win32', 'cygwin'):
 
749
            raise TestSkipped('Windows doesn\'t support filenames'
 
750
                              ' with tabs or trailing spaces')
 
751
        self.tree1 = self.make_branch_and_tree('b1')
 
752
        self.b1 = self.tree1.branch
 
753
 
 
754
        self.build_tree(['b1/trailing space '])
 
755
        self.tree1.add(['trailing space '])
 
756
        # TODO: jam 20060701 Check for handling files with '\t' characters
 
757
        #       once we actually support them
 
758
 
 
759
        # Added
 
760
        self.tree1.commit('funky whitespace', rev_id='white-1')
 
761
 
 
762
        bundle = self.get_valid_bundle(None, 'white-1')
 
763
 
 
764
        # Modified
 
765
        open('b1/trailing space ', 'ab').write('add some text\n')
 
766
        self.tree1.commit('add text', rev_id='white-2')
 
767
 
 
768
        bundle = self.get_valid_bundle('white-1', 'white-2')
 
769
 
 
770
        # Renamed
 
771
        self.tree1.rename_one('trailing space ', ' start and end space ')
 
772
        self.tree1.commit('rename', rev_id='white-3')
 
773
 
 
774
        bundle = self.get_valid_bundle('white-2', 'white-3')
 
775
 
 
776
        # Removed
 
777
        self.tree1.remove([' start and end space '])
 
778
        self.tree1.commit('removed', rev_id='white-4')
 
779
 
 
780
        bundle = self.get_valid_bundle('white-3', 'white-4')
 
781
        
 
782
        # Now test a complet roll-up
 
783
        bundle = self.get_valid_bundle(None, 'white-4')
 
784
 
 
785
    def test_alt_timezone_bundle(self):
 
786
        self.tree1 = self.make_branch_and_tree('b1')
 
787
        self.b1 = self.tree1.branch
 
788
 
 
789
        self.build_tree(['b1/newfile'])
 
790
        self.tree1.add(['newfile'])
 
791
 
 
792
        # Asia/Colombo offset = 5 hours 30 minutes
 
793
        self.tree1.commit('non-hour offset timezone', rev_id='tz-1',
 
794
                          timezone=19800, timestamp=1152544886.0)
 
795
 
 
796
        bundle = self.get_valid_bundle(None, 'tz-1')
 
797
        
 
798
        rev = bundle.revisions[0]
 
799
        self.assertEqual('Mon 2006-07-10 20:51:26.000000000 +0530', rev.date)
 
800
        self.assertEqual(19800, rev.timezone)
 
801
        self.assertEqual(1152544886.0, rev.timestamp)
 
802
 
 
803
    def test_bundle_root_id(self):
 
804
        self.tree1 = self.make_branch_and_tree('b1')
 
805
        self.b1 = self.tree1.branch
 
806
        self.tree1.commit('message', rev_id='revid1')
 
807
        bundle = self.get_valid_bundle(None, 'revid1')
 
808
        tree = bundle.revision_tree(self.b1.repository, 'revid1')
 
809
        self.assertEqual('revid1', tree.inventory.root.revision)
 
810
 
692
811
 
693
812
class MungedBundleTester(TestCaseWithTransport):
694
813
 
700
819
        wt.commit('add one', rev_id='a@cset-0-1')
701
820
        self.build_tree(['b1/two'])
702
821
        wt.add('two')
703
 
        wt.commit('add two', rev_id='a@cset-0-2')
 
822
        wt.commit('add two', rev_id='a@cset-0-2',
 
823
                  revprops={'branch-nick':'test'})
704
824
 
705
825
        bundle_txt = StringIO()
706
826
        rev_ids = write_bundle(wt.branch.repository, 'a@cset-0-2',
711
831
 
712
832
    def check_valid(self, bundle):
713
833
        """Check that after whatever munging, the final object is valid."""
714
 
        self.assertEqual(['a@cset-0-2'], 
 
834
        self.assertEqual(['a@cset-0-2'],
715
835
            [r.revision_id for r in bundle.real_revisions])
716
836
 
717
837
    def test_extra_whitespace(self):
750
870
        # creates a blank line at the end, and fails if that
751
871
        # line is stripped
752
872
        self.assertEqual('\n\n', raw[-2:])
753
 
        bundle_text = StringIO(raw[:-1])
754
 
 
755
 
        bundle = read_bundle(bundle_txt)
756
 
        self.check_valid(bundle)
 
873
        bundle_txt = StringIO(raw[:-1])
 
874
 
 
875
        bundle = read_bundle(bundle_txt)
 
876
        self.check_valid(bundle)
 
877
 
 
878
    def test_opening_text(self):
 
879
        bundle_txt = self.build_test_bundle()
 
880
 
 
881
        bundle_txt = StringIO("Some random\nemail comments\n"
 
882
                              + bundle_txt.getvalue())
 
883
 
 
884
        bundle = read_bundle(bundle_txt)
 
885
        self.check_valid(bundle)
 
886
 
 
887
    def test_trailing_text(self):
 
888
        bundle_txt = self.build_test_bundle()
 
889
 
 
890
        bundle_txt = StringIO(bundle_txt.getvalue() +
 
891
                              "Some trailing\nrandom\ntext\n")
 
892
 
 
893
        bundle = read_bundle(bundle_txt)
 
894
        self.check_valid(bundle)
 
895