~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Ian Clatworthy
  • Date: 2010-03-03 03:28:30 UTC
  • mto: (4797.31.1 integration-2.1)
  • mto: This revision was merged to the branch mainline in revision 5075.
  • Revision ID: ian.clatworthy@canonical.com-20100303032830-qf3ty4z40i410bem
add What's New to the list of PDF documents generated

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
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
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
18
18
import os
19
19
 
20
20
import bzrlib
21
21
from bzrlib import (
 
22
    bzrdir,
22
23
    errors,
23
24
    lockdir,
24
25
    osutils,
28
29
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
29
30
from bzrlib.commit import Commit, NullCommitReporter
30
31
from bzrlib.config import BranchConfig
31
 
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
 
32
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
32
33
                           LockContention)
33
 
from bzrlib.tests import TestCaseWithTransport
 
34
from bzrlib.tests import SymlinkFeature, TestCaseWithTransport
34
35
from bzrlib.workingtree import WorkingTree
35
36
 
36
37
 
70
71
    def renamed(self, change, old_path, new_path):
71
72
        self.calls.append(('renamed', change, old_path, new_path))
72
73
 
 
74
    def is_verbose(self):
 
75
        return True
 
76
 
73
77
 
74
78
class TestCommit(TestCaseWithTransport):
75
79
 
92
96
        eq(rev.message, 'add hello')
93
97
 
94
98
        tree1 = b.repository.revision_tree(rh[0])
 
99
        tree1.lock_read()
95
100
        text = tree1.get_file_text(file_id)
96
 
        eq(text, 'hello world')
 
101
        tree1.unlock()
 
102
        self.assertEqual('hello world', text)
97
103
 
98
104
        tree2 = b.repository.revision_tree(rh[1])
99
 
        eq(tree2.get_file_text(file_id), 'version 2')
 
105
        tree2.lock_read()
 
106
        text = tree2.get_file_text(file_id)
 
107
        tree2.unlock()
 
108
        self.assertEqual('version 2', text)
100
109
 
101
 
    def test_delete_commit(self):
102
 
        """Test a commit with a deleted file"""
 
110
    def test_missing_commit(self):
 
111
        """Test a commit with a missing file"""
103
112
        wt = self.make_branch_and_tree('.')
104
113
        b = wt.branch
105
114
        file('hello', 'w').write('hello world')
112
121
        tree = b.repository.revision_tree('rev2')
113
122
        self.assertFalse(tree.has_id('hello-id'))
114
123
 
 
124
    def test_partial_commit_move(self):
 
125
        """Test a partial commit where a file was renamed but not committed.
 
126
 
 
127
        https://bugs.launchpad.net/bzr/+bug/83039
 
128
 
 
129
        If not handled properly, commit will try to snapshot
 
130
        dialog.py with olive/ as a parent, while
 
131
        olive/ has not been snapshotted yet.
 
132
        """
 
133
        wt = self.make_branch_and_tree('.')
 
134
        b = wt.branch
 
135
        self.build_tree(['annotate/', 'annotate/foo.py',
 
136
                         'olive/', 'olive/dialog.py'
 
137
                        ])
 
138
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
 
139
        wt.commit(message='add files')
 
140
        wt.rename_one("olive/dialog.py", "aaa")
 
141
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
 
142
        wt.commit('renamed hello', specific_files=["annotate"])
 
143
 
115
144
    def test_pointless_commit(self):
116
145
        """Commit refuses unless there are changes or it's forced."""
117
146
        wt = self.make_branch_and_tree('.')
125
154
                          message='fails',
126
155
                          allow_pointless=False)
127
156
        self.assertEquals(b.revno(), 1)
128
 
        
 
157
 
129
158
    def test_commit_empty(self):
130
159
        """Commiting an empty tree works."""
131
160
        wt = self.make_branch_and_tree('.')
148
177
              ['hello-id', 'buongia-id'])
149
178
        wt.commit(message='add files',
150
179
                 rev_id='test@rev-1')
151
 
        
 
180
 
152
181
        os.remove('hello')
153
182
        file('buongia', 'w').write('new text')
154
183
        wt.commit(message='update text',
165
194
        eq(b.revno(), 3)
166
195
 
167
196
        tree2 = b.repository.revision_tree('test@rev-2')
 
197
        tree2.lock_read()
 
198
        self.addCleanup(tree2.unlock)
168
199
        self.assertTrue(tree2.has_filename('hello'))
169
200
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
170
201
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
171
 
        
 
202
 
172
203
        tree3 = b.repository.revision_tree('test@rev-3')
 
204
        tree3.lock_read()
 
205
        self.addCleanup(tree3.unlock)
173
206
        self.assertFalse(tree3.has_filename('hello'))
174
207
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
175
208
 
186
219
 
187
220
        eq = self.assertEquals
188
221
        tree1 = b.repository.revision_tree('test@rev-1')
 
222
        tree1.lock_read()
 
223
        self.addCleanup(tree1.unlock)
189
224
        eq(tree1.id2path('hello-id'), 'hello')
190
225
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
191
226
        self.assertFalse(tree1.has_filename('fruity'))
194
229
        eq(ie.revision, 'test@rev-1')
195
230
 
196
231
        tree2 = b.repository.revision_tree('test@rev-2')
 
232
        tree2.lock_read()
 
233
        self.addCleanup(tree2.unlock)
197
234
        eq(tree2.id2path('hello-id'), 'fruity')
198
235
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
199
236
        self.check_inventory_shape(tree2.inventory, ['fruity'])
427
464
        bound = master.sprout('bound')
428
465
        wt = bound.open_workingtree()
429
466
        wt.branch.set_bound_location(os.path.realpath('master'))
430
 
 
431
 
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
432
467
        master_branch.lock_write()
433
468
        try:
434
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
435
469
            self.assertRaises(LockContention, wt.commit, 'silly')
436
470
        finally:
437
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
438
471
            master_branch.unlock()
439
472
 
440
473
    def test_commit_bound_merge(self):
451
484
        other_bzrdir = master_branch.bzrdir.sprout('other')
452
485
        other_tree = other_bzrdir.open_workingtree()
453
486
 
454
 
        # do a commit to the the other branch changing the content file so
 
487
        # do a commit to the other branch changing the content file so
455
488
        # that our commit after merging will have a merged revision in the
456
489
        # content file history.
457
490
        self.build_tree_contents([('other/content_file', 'change in other\n')])
468
501
        bound_tree.commit(message='commit of merge in bound tree')
469
502
 
470
503
    def test_commit_reporting_after_merge(self):
471
 
        # when doing a commit of a merge, the reporter needs to still 
 
504
        # when doing a commit of a merge, the reporter needs to still
472
505
        # be called for each item that is added/removed/deleted.
473
506
        this_tree = self.make_branch_and_tree('this')
474
507
        # we need a bunch of files and dirs, to perform one action on each.
517
550
        this_tree.merge_from_branch(other_tree.branch)
518
551
        reporter = CapturingReporter()
519
552
        this_tree.commit('do the commit', reporter=reporter)
520
 
        self.assertEqual([
521
 
            ('change', 'unchanged', ''),
522
 
            ('change', 'unchanged', 'dirtoleave'),
523
 
            ('change', 'unchanged', 'filetoleave'),
 
553
        expected = set([
524
554
            ('change', 'modified', 'filetomodify'),
525
555
            ('change', 'added', 'newdir'),
526
556
            ('change', 'added', 'newfile'),
527
557
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
 
558
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
528
559
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
529
560
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
530
 
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
531
561
            ('deleted', 'dirtoremove'),
532
562
            ('deleted', 'filetoremove'),
533
 
            ],
534
 
            reporter.calls)
 
563
            ])
 
564
        result = set(reporter.calls)
 
565
        missing = expected - result
 
566
        new = result - expected
 
567
        self.assertEqual((set(), set()), (missing, new))
535
568
 
536
569
    def test_commit_removals_respects_filespec(self):
537
570
        """Commit respects the specified_files for removals."""
581
614
            basis.unlock()
582
615
 
583
616
    def test_commit_kind_changes(self):
584
 
        if not osutils.has_symlinks():
585
 
            raise tests.TestSkipped('Test requires symlink support')
 
617
        self.requireFeature(SymlinkFeature)
586
618
        tree = self.make_branch_and_tree('.')
587
619
        os.symlink('target', 'name')
588
620
        tree.add('name', 'a-file-id')
628
660
    def test_commit_unversioned_specified(self):
629
661
        """Commit should raise if specified files isn't in basis or worktree"""
630
662
        tree = self.make_branch_and_tree('.')
631
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
 
663
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
632
664
                          'message', specific_files=['bogus'])
633
665
 
634
666
    class Callback(object):
635
 
        
 
667
 
636
668
        def __init__(self, message, testcase):
637
669
            self.called = False
638
670
            self.message = message
666
698
        """Callback should not be invoked for pointless commit"""
667
699
        tree = self.make_branch_and_tree('.')
668
700
        cb = self.Callback(u'commit 2', self)
669
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
 
701
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
670
702
                          allow_pointless=False)
671
703
        self.assertFalse(cb.called)
672
704
 
676
708
        cb = self.Callback(u'commit 2', self)
677
709
        repository = tree.branch.repository
678
710
        # simulate network failure
679
 
        def raise_(self, arg, arg2):
 
711
        def raise_(self, arg, arg2, arg3=None, arg4=None):
680
712
            raise errors.NoSuchFile('foo')
681
713
        repository.add_inventory = raise_
 
714
        repository.add_inventory_by_delta = raise_
682
715
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
683
716
        self.assertFalse(cb.called)
684
717
 
695
728
        self.assertEqual(['bar', 'baz'], err.files)
696
729
        self.assertEqual('Selected-file commit of merges is not supported'
697
730
                         ' yet: files bar, baz', str(err))
 
731
 
 
732
    def test_commit_ordering(self):
 
733
        """Test of corner-case commit ordering error"""
 
734
        tree = self.make_branch_and_tree('.')
 
735
        self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
 
736
        tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
 
737
        tree.commit('setup')
 
738
        self.build_tree(['a/c/d/'])
 
739
        tree.add('a/c/d')
 
740
        tree.rename_one('a/z/x', 'a/c/d/x')
 
741
        tree.commit('test', specific_files=['a/z/y'])
 
742
 
 
743
    def test_commit_no_author(self):
 
744
        """The default kwarg author in MutableTree.commit should not add
 
745
        the 'author' revision property.
 
746
        """
 
747
        tree = self.make_branch_and_tree('foo')
 
748
        rev_id = tree.commit('commit 1')
 
749
        rev = tree.branch.repository.get_revision(rev_id)
 
750
        self.assertFalse('author' in rev.properties)
 
751
        self.assertFalse('authors' in rev.properties)
 
752
 
 
753
    def test_commit_author(self):
 
754
        """Passing a non-empty author kwarg to MutableTree.commit should add
 
755
        the 'author' revision property.
 
756
        """
 
757
        tree = self.make_branch_and_tree('foo')
 
758
        rev_id = self.callDeprecated(['The parameter author was '
 
759
                'deprecated in version 1.13. Use authors instead'],
 
760
                tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
 
761
        rev = tree.branch.repository.get_revision(rev_id)
 
762
        self.assertEqual('John Doe <jdoe@example.com>',
 
763
                         rev.properties['authors'])
 
764
        self.assertFalse('author' in rev.properties)
 
765
 
 
766
    def test_commit_empty_authors_list(self):
 
767
        """Passing an empty list to authors shouldn't add the property."""
 
768
        tree = self.make_branch_and_tree('foo')
 
769
        rev_id = tree.commit('commit 1', authors=[])
 
770
        rev = tree.branch.repository.get_revision(rev_id)
 
771
        self.assertFalse('author' in rev.properties)
 
772
        self.assertFalse('authors' in rev.properties)
 
773
 
 
774
    def test_multiple_authors(self):
 
775
        tree = self.make_branch_and_tree('foo')
 
776
        rev_id = tree.commit('commit 1',
 
777
                authors=['John Doe <jdoe@example.com>',
 
778
                         'Jane Rey <jrey@example.com>'])
 
779
        rev = tree.branch.repository.get_revision(rev_id)
 
780
        self.assertEqual('John Doe <jdoe@example.com>\n'
 
781
                'Jane Rey <jrey@example.com>', rev.properties['authors'])
 
782
        self.assertFalse('author' in rev.properties)
 
783
 
 
784
    def test_author_and_authors_incompatible(self):
 
785
        tree = self.make_branch_and_tree('foo')
 
786
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
 
787
                authors=['John Doe <jdoe@example.com>',
 
788
                         'Jane Rey <jrey@example.com>'],
 
789
                author="Jack Me <jme@example.com>")
 
790
 
 
791
    def test_author_with_newline_rejected(self):
 
792
        tree = self.make_branch_and_tree('foo')
 
793
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
 
794
                authors=['John\nDoe <jdoe@example.com>'])
 
795
 
 
796
    def test_commit_with_checkout_and_branch_sharing_repo(self):
 
797
        repo = self.make_repository('repo', shared=True)
 
798
        # make_branch_and_tree ignores shared repos
 
799
        branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
 
800
        tree2 = branch.create_checkout('repo/tree2')
 
801
        tree2.commit('message', rev_id='rev1')
 
802
        self.assertTrue(tree2.branch.repository.has_revision('rev1'))