~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: John Arbash Meinel
  • Date: 2006-06-10 14:53:51 UTC
  • mto: (1711.7.2 win32)
  • mto: This revision was merged to the branch mainline in revision 1796.
  • Revision ID: john@arbash-meinel.com-20060610145351-9da0c1f8ba8a57e0
the _posix_* routines should use posixpath not os.path, so tests pass on win32

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2005, 2006 by Canonical Ltd
 
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
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
18
import os
19
19
 
20
20
import bzrlib
21
 
from bzrlib import (
22
 
    bzrdir,
23
 
    errors,
24
 
    )
 
21
from bzrlib.tests import TestCaseWithTransport
25
22
from bzrlib.branch import Branch
26
 
from bzrlib.bzrdir import BzrDirMetaFormat1
 
23
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
 
24
from bzrlib.workingtree import WorkingTree
27
25
from bzrlib.commit import Commit, NullCommitReporter
28
26
from bzrlib.config import BranchConfig
29
 
from bzrlib.errors import (
30
 
    PointlessCommit,
31
 
    BzrError,
32
 
    SigningFailed,
33
 
    LockContention,
34
 
    )
35
 
from bzrlib.tests import (
36
 
    TestCaseWithTransport,
37
 
    test_foreign,
38
 
    )
39
 
from bzrlib.tests.features import (
40
 
    SymlinkFeature,
41
 
    )
42
 
from bzrlib.tests.matchers import MatchesAncestry
 
27
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
 
28
                           LockContention)
43
29
 
44
30
 
45
31
# TODO: Test commit with some added, and added-but-missing files
78
64
    def renamed(self, change, old_path, new_path):
79
65
        self.calls.append(('renamed', change, old_path, new_path))
80
66
 
81
 
    def is_verbose(self):
82
 
        return True
83
 
 
84
67
 
85
68
class TestCommit(TestCaseWithTransport):
86
69
 
103
86
        eq(rev.message, 'add hello')
104
87
 
105
88
        tree1 = b.repository.revision_tree(rh[0])
106
 
        tree1.lock_read()
107
89
        text = tree1.get_file_text(file_id)
108
 
        tree1.unlock()
109
 
        self.assertEqual('hello world', text)
 
90
        eq(text, 'hello world')
110
91
 
111
92
        tree2 = b.repository.revision_tree(rh[1])
112
 
        tree2.lock_read()
113
 
        text = tree2.get_file_text(file_id)
114
 
        tree2.unlock()
115
 
        self.assertEqual('version 2', text)
116
 
 
117
 
    def test_commit_lossy_native(self):
118
 
        """Attempt a lossy commit to a native branch."""
119
 
        wt = self.make_branch_and_tree('.')
120
 
        b = wt.branch
121
 
        file('hello', 'w').write('hello world')
122
 
        wt.add('hello')
123
 
        revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
124
 
        self.assertEquals('revid', revid)
125
 
 
126
 
    def test_commit_lossy_foreign(self):
127
 
        """Attempt a lossy commit to a foreign branch."""
128
 
        test_foreign.register_dummy_foreign_for_test(self)
129
 
        wt = self.make_branch_and_tree('.',
130
 
            format=test_foreign.DummyForeignVcsDirFormat())
131
 
        b = wt.branch
132
 
        file('hello', 'w').write('hello world')
133
 
        wt.add('hello')
134
 
        revid = wt.commit(message='add hello', lossy=True,
135
 
            timestamp=1302659388, timezone=0)
136
 
        self.assertEquals('dummy-v1:1302659388.0-0-UNKNOWN', revid)
137
 
 
138
 
    def test_commit_bound_lossy_foreign(self):
139
 
        """Attempt a lossy commit to a bzr branch bound to a foreign branch."""
140
 
        test_foreign.register_dummy_foreign_for_test(self)
141
 
        foreign_branch = self.make_branch('foreign',
142
 
            format=test_foreign.DummyForeignVcsDirFormat())
143
 
        wt = foreign_branch.create_checkout("local")
144
 
        b = wt.branch
145
 
        file('local/hello', 'w').write('hello world')
146
 
        wt.add('hello')
147
 
        revid = wt.commit(message='add hello', lossy=True,
148
 
            timestamp=1302659388, timezone=0)
149
 
        self.assertEquals('dummy-v1:1302659388.0-0-0', revid)
150
 
        self.assertEquals('dummy-v1:1302659388.0-0-0',
151
 
            foreign_branch.last_revision())
152
 
        self.assertEquals('dummy-v1:1302659388.0-0-0',
153
 
            wt.branch.last_revision())
154
 
 
155
 
    def test_missing_commit(self):
156
 
        """Test a commit with a missing file"""
 
93
        eq(tree2.get_file_text(file_id), 'version 2')
 
94
 
 
95
    def test_delete_commit(self):
 
96
        """Test a commit with a deleted file"""
157
97
        wt = self.make_branch_and_tree('.')
158
98
        b = wt.branch
159
99
        file('hello', 'w').write('hello world')
161
101
        wt.commit(message='add hello')
162
102
 
163
103
        os.remove('hello')
164
 
        reporter = CapturingReporter()
165
 
        wt.commit('removed hello', rev_id='rev2', reporter=reporter)
166
 
        self.assertEquals(
167
 
            [('missing', u'hello'), ('deleted', u'hello')],
168
 
            reporter.calls)
 
104
        wt.commit('removed hello', rev_id='rev2')
169
105
 
170
106
        tree = b.repository.revision_tree('rev2')
171
107
        self.assertFalse(tree.has_id('hello-id'))
172
108
 
173
 
    def test_partial_commit_move(self):
174
 
        """Test a partial commit where a file was renamed but not committed.
175
 
 
176
 
        https://bugs.launchpad.net/bzr/+bug/83039
177
 
 
178
 
        If not handled properly, commit will try to snapshot
179
 
        dialog.py with olive/ as a parent, while
180
 
        olive/ has not been snapshotted yet.
181
 
        """
182
 
        wt = self.make_branch_and_tree('.')
183
 
        b = wt.branch
184
 
        self.build_tree(['annotate/', 'annotate/foo.py',
185
 
                         'olive/', 'olive/dialog.py'
186
 
                        ])
187
 
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
188
 
        wt.commit(message='add files')
189
 
        wt.rename_one("olive/dialog.py", "aaa")
190
 
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
191
 
        wt.commit('renamed hello', specific_files=["annotate"])
192
 
 
193
109
    def test_pointless_commit(self):
194
110
        """Commit refuses unless there are changes or it's forced."""
195
111
        wt = self.make_branch_and_tree('.')
203
119
                          message='fails',
204
120
                          allow_pointless=False)
205
121
        self.assertEquals(b.revno(), 1)
206
 
 
 
122
        
207
123
    def test_commit_empty(self):
208
124
        """Commiting an empty tree works."""
209
125
        wt = self.make_branch_and_tree('.')
226
142
              ['hello-id', 'buongia-id'])
227
143
        wt.commit(message='add files',
228
144
                 rev_id='test@rev-1')
229
 
 
 
145
        
230
146
        os.remove('hello')
231
147
        file('buongia', 'w').write('new text')
232
148
        wt.commit(message='update text',
243
159
        eq(b.revno(), 3)
244
160
 
245
161
        tree2 = b.repository.revision_tree('test@rev-2')
246
 
        tree2.lock_read()
247
 
        self.addCleanup(tree2.unlock)
248
162
        self.assertTrue(tree2.has_filename('hello'))
249
163
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
250
164
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
251
 
 
 
165
        
252
166
        tree3 = b.repository.revision_tree('test@rev-3')
253
 
        tree3.lock_read()
254
 
        self.addCleanup(tree3.unlock)
255
167
        self.assertFalse(tree3.has_filename('hello'))
256
168
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
257
169
 
268
180
 
269
181
        eq = self.assertEquals
270
182
        tree1 = b.repository.revision_tree('test@rev-1')
271
 
        tree1.lock_read()
272
 
        self.addCleanup(tree1.unlock)
273
183
        eq(tree1.id2path('hello-id'), 'hello')
274
184
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
275
185
        self.assertFalse(tree1.has_filename('fruity'))
276
 
        self.check_tree_shape(tree1, ['hello'])
277
 
        eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
 
186
        self.check_inventory_shape(tree1.inventory, ['hello'])
 
187
        ie = tree1.inventory['hello-id']
 
188
        eq(ie.revision, 'test@rev-1')
278
189
 
279
190
        tree2 = b.repository.revision_tree('test@rev-2')
280
 
        tree2.lock_read()
281
 
        self.addCleanup(tree2.unlock)
282
191
        eq(tree2.id2path('hello-id'), 'fruity')
283
192
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
284
 
        self.check_tree_shape(tree2, ['fruity'])
285
 
        eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
 
193
        self.check_inventory_shape(tree2.inventory, ['fruity'])
 
194
        ie = tree2.inventory['hello-id']
 
195
        eq(ie.revision, 'test@rev-2')
286
196
 
287
197
    def test_reused_rev_id(self):
288
198
        """Test that a revision id cannot be reused in a branch"""
307
217
        wt.move(['hello'], 'a')
308
218
        r2 = 'test@rev-2'
309
219
        wt.commit('two', rev_id=r2, allow_pointless=False)
310
 
        wt.lock_read()
311
 
        try:
312
 
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
313
 
        finally:
314
 
            wt.unlock()
 
220
        self.check_inventory_shape(wt.read_working_inventory(),
 
221
                                   ['a', 'a/hello', 'b'])
315
222
 
316
223
        wt.move(['b'], 'a')
317
224
        r3 = 'test@rev-3'
318
225
        wt.commit('three', rev_id=r3, allow_pointless=False)
319
 
        wt.lock_read()
320
 
        try:
321
 
            self.check_tree_shape(wt,
322
 
                                       ['a/', 'a/hello', 'a/b/'])
323
 
            self.check_tree_shape(b.repository.revision_tree(r3),
324
 
                                       ['a/', 'a/hello', 'a/b/'])
325
 
        finally:
326
 
            wt.unlock()
 
226
        self.check_inventory_shape(wt.read_working_inventory(),
 
227
                                   ['a', 'a/hello', 'a/b'])
 
228
        self.check_inventory_shape(b.repository.get_revision_inventory(r3),
 
229
                                   ['a', 'a/hello', 'a/b'])
327
230
 
328
231
        wt.move(['a/hello'], 'a/b')
329
232
        r4 = 'test@rev-4'
330
233
        wt.commit('four', rev_id=r4, allow_pointless=False)
331
 
        wt.lock_read()
332
 
        try:
333
 
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
334
 
        finally:
335
 
            wt.unlock()
 
234
        self.check_inventory_shape(wt.read_working_inventory(),
 
235
                                   ['a', 'a/b/hello', 'a/b'])
336
236
 
337
 
        inv = b.repository.get_inventory(r4)
 
237
        inv = b.repository.get_revision_inventory(r4)
338
238
        eq(inv['hello-id'].revision, r4)
339
239
        eq(inv['a-id'].revision, r1)
340
240
        eq(inv['b-id'].revision, r3)
341
 
 
 
241
        
342
242
    def test_removed_commit(self):
343
243
        """Commit with a removed file"""
344
244
        wt = self.make_branch_and_tree('.')
368
268
        eq = self.assertEquals
369
269
        eq(b.revision_history(), rev_ids)
370
270
        for i in range(4):
371
 
            self.assertThat(rev_ids[:i+1],
372
 
                MatchesAncestry(b.repository, rev_ids[i]))
 
271
            anc = b.repository.get_ancestry(rev_ids[i])
 
272
            eq(anc, [None] + rev_ids[:i+1])
373
273
 
374
274
    def test_commit_new_subdir_child_selective(self):
375
275
        wt = self.make_branch_and_tree('.')
398
298
    def test_strict_commit_without_unknowns(self):
399
299
        """Try and commit with no unknown files and strict = True,
400
300
        should work."""
 
301
        from bzrlib.errors import StrictCommitFailed
401
302
        wt = self.make_branch_and_tree('.')
402
303
        b = wt.branch
403
304
        file('hello', 'w').write('hello world')
429
330
        wt = self.make_branch_and_tree('.')
430
331
        branch = wt.branch
431
332
        wt.commit("base", allow_pointless=True, rev_id='A')
432
 
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
 
333
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
433
334
        try:
434
335
            from bzrlib.testament import Testament
435
336
            # monkey patch gpg signing mechanism
438
339
                                                      allow_pointless=True,
439
340
                                                      rev_id='B',
440
341
                                                      working_tree=wt)
441
 
            def sign(text):
442
 
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
443
 
            self.assertEqual(sign(Testament.from_revision(branch.repository,
444
 
                             'B').as_short_text()),
 
342
            self.assertEqual(Testament.from_revision(branch.repository,
 
343
                             'B').as_short_text(),
445
344
                             branch.repository.get_signature_text('B'))
446
345
        finally:
447
346
            bzrlib.gpg.GPGStrategy = oldstrategy
453
352
        wt = self.make_branch_and_tree('.')
454
353
        branch = wt.branch
455
354
        wt.commit("base", allow_pointless=True, rev_id='A')
456
 
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
 
355
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
457
356
        try:
 
357
            from bzrlib.testament import Testament
458
358
            # monkey patch gpg signing mechanism
459
359
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
460
360
            config = MustSignConfig(branch)
466
366
                              working_tree=wt)
467
367
            branch = Branch.open(self.get_url('.'))
468
368
            self.assertEqual(branch.revision_history(), ['A'])
469
 
            self.assertFalse(branch.repository.has_revision('B'))
 
369
            self.failIf(branch.repository.has_revision('B'))
470
370
        finally:
471
371
            bzrlib.gpg.GPGStrategy = oldstrategy
472
372
 
527
427
        other_bzrdir = master_branch.bzrdir.sprout('other')
528
428
        other_tree = other_bzrdir.open_workingtree()
529
429
 
530
 
        # do a commit to the other branch changing the content file so
 
430
        # do a commit to the the other branch changing the content file so
531
431
        # that our commit after merging will have a merged revision in the
532
432
        # content file history.
533
433
        self.build_tree_contents([('other/content_file', 'change in other\n')])
536
436
        # do a merge into the bound branch from other, and then change the
537
437
        # content file locally to force a new revision (rather than using the
538
438
        # revision from other). This forces extra processing in commit.
539
 
        bound_tree.merge_from_branch(other_tree.branch)
 
439
        self.merge(other_tree.branch, bound_tree)
540
440
        self.build_tree_contents([('bound/content_file', 'change in bound\n')])
541
441
 
542
442
        # before #34959 was fixed, this failed with 'revision not present in
544
444
        bound_tree.commit(message='commit of merge in bound tree')
545
445
 
546
446
    def test_commit_reporting_after_merge(self):
547
 
        # when doing a commit of a merge, the reporter needs to still
 
447
        # when doing a commit of a merge, the reporter needs to still 
548
448
        # be called for each item that is added/removed/deleted.
549
449
        this_tree = self.make_branch_and_tree('this')
550
450
        # we need a bunch of files and dirs, to perform one action on each.
590
490
            other_tree.commit('modify all sample files and dirs.')
591
491
        finally:
592
492
            other_tree.unlock()
593
 
        this_tree.merge_from_branch(other_tree.branch)
 
493
        self.merge(other_tree.branch, this_tree)
594
494
        reporter = CapturingReporter()
595
495
        this_tree.commit('do the commit', reporter=reporter)
596
 
        expected = set([
 
496
        self.assertEqual([
 
497
            ('change', 'unchanged', 'dirtoleave'),
 
498
            ('change', 'unchanged', 'filetoleave'),
597
499
            ('change', 'modified', 'filetomodify'),
598
500
            ('change', 'added', 'newdir'),
599
501
            ('change', 'added', 'newfile'),
600
502
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
601
 
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
602
503
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
603
504
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
 
505
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
604
506
            ('deleted', 'dirtoremove'),
605
507
            ('deleted', 'filetoremove'),
606
 
            ])
607
 
        result = set(reporter.calls)
608
 
        missing = expected - result
609
 
        new = result - expected
610
 
        self.assertEqual((set(), set()), (missing, new))
611
 
 
612
 
    def test_commit_removals_respects_filespec(self):
613
 
        """Commit respects the specified_files for removals."""
614
 
        tree = self.make_branch_and_tree('.')
615
 
        self.build_tree(['a', 'b'])
616
 
        tree.add(['a', 'b'])
617
 
        tree.commit('added a, b')
618
 
        tree.remove(['a', 'b'])
619
 
        tree.commit('removed a', specific_files='a')
620
 
        basis = tree.basis_tree()
621
 
        tree.lock_read()
622
 
        try:
623
 
            self.assertIs(None, basis.path2id('a'))
624
 
            self.assertFalse(basis.path2id('b') is None)
625
 
        finally:
626
 
            tree.unlock()
627
 
 
628
 
    def test_commit_saves_1ms_timestamp(self):
629
 
        """Passing in a timestamp is saved with 1ms resolution"""
630
 
        tree = self.make_branch_and_tree('.')
631
 
        self.build_tree(['a'])
632
 
        tree.add('a')
633
 
        tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
634
 
                    rev_id='a1')
635
 
 
636
 
        rev = tree.branch.repository.get_revision('a1')
637
 
        self.assertEqual(1153248633.419, rev.timestamp)
638
 
 
639
 
    def test_commit_has_1ms_resolution(self):
640
 
        """Allowing commit to generate the timestamp also has 1ms resolution"""
641
 
        tree = self.make_branch_and_tree('.')
642
 
        self.build_tree(['a'])
643
 
        tree.add('a')
644
 
        tree.commit('added a', rev_id='a1')
645
 
 
646
 
        rev = tree.branch.repository.get_revision('a1')
647
 
        timestamp = rev.timestamp
648
 
        timestamp_1ms = round(timestamp, 3)
649
 
        self.assertEqual(timestamp_1ms, timestamp)
650
 
 
651
 
    def assertBasisTreeKind(self, kind, tree, file_id):
652
 
        basis = tree.basis_tree()
653
 
        basis.lock_read()
654
 
        try:
655
 
            self.assertEqual(kind, basis.kind(file_id))
656
 
        finally:
657
 
            basis.unlock()
658
 
 
659
 
    def test_commit_kind_changes(self):
660
 
        self.requireFeature(SymlinkFeature)
661
 
        tree = self.make_branch_and_tree('.')
662
 
        os.symlink('target', 'name')
663
 
        tree.add('name', 'a-file-id')
664
 
        tree.commit('Added a symlink')
665
 
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
666
 
 
667
 
        os.unlink('name')
668
 
        self.build_tree(['name'])
669
 
        tree.commit('Changed symlink to file')
670
 
        self.assertBasisTreeKind('file', tree, 'a-file-id')
671
 
 
672
 
        os.unlink('name')
673
 
        os.symlink('target', 'name')
674
 
        tree.commit('file to symlink')
675
 
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
676
 
 
677
 
        os.unlink('name')
678
 
        os.mkdir('name')
679
 
        tree.commit('symlink to directory')
680
 
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
681
 
 
682
 
        os.rmdir('name')
683
 
        os.symlink('target', 'name')
684
 
        tree.commit('directory to symlink')
685
 
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
686
 
 
687
 
        # prepare for directory <-> file tests
688
 
        os.unlink('name')
689
 
        os.mkdir('name')
690
 
        tree.commit('symlink to directory')
691
 
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
692
 
 
693
 
        os.rmdir('name')
694
 
        self.build_tree(['name'])
695
 
        tree.commit('Changed directory to file')
696
 
        self.assertBasisTreeKind('file', tree, 'a-file-id')
697
 
 
698
 
        os.unlink('name')
699
 
        os.mkdir('name')
700
 
        tree.commit('file to directory')
701
 
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
702
 
 
703
 
    def test_commit_unversioned_specified(self):
704
 
        """Commit should raise if specified files isn't in basis or worktree"""
705
 
        tree = self.make_branch_and_tree('.')
706
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
707
 
                          'message', specific_files=['bogus'])
708
 
 
709
 
    class Callback(object):
710
 
 
711
 
        def __init__(self, message, testcase):
712
 
            self.called = False
713
 
            self.message = message
714
 
            self.testcase = testcase
715
 
 
716
 
        def __call__(self, commit_obj):
717
 
            self.called = True
718
 
            self.testcase.assertTrue(isinstance(commit_obj, Commit))
719
 
            return self.message
720
 
 
721
 
    def test_commit_callback(self):
722
 
        """Commit should invoke a callback to get the message"""
723
 
 
724
 
        tree = self.make_branch_and_tree('.')
725
 
        try:
726
 
            tree.commit()
727
 
        except Exception, e:
728
 
            self.assertTrue(isinstance(e, BzrError))
729
 
            self.assertEqual('The message or message_callback keyword'
730
 
                             ' parameter is required for commit().', str(e))
731
 
        else:
732
 
            self.fail('exception not raised')
733
 
        cb = self.Callback(u'commit 1', self)
734
 
        tree.commit(message_callback=cb)
735
 
        self.assertTrue(cb.called)
736
 
        repository = tree.branch.repository
737
 
        message = repository.get_revision(tree.last_revision()).message
738
 
        self.assertEqual('commit 1', message)
739
 
 
740
 
    def test_no_callback_pointless(self):
741
 
        """Callback should not be invoked for pointless commit"""
742
 
        tree = self.make_branch_and_tree('.')
743
 
        cb = self.Callback(u'commit 2', self)
744
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
745
 
                          allow_pointless=False)
746
 
        self.assertFalse(cb.called)
747
 
 
748
 
    def test_no_callback_netfailure(self):
749
 
        """Callback should not be invoked if connectivity fails"""
750
 
        tree = self.make_branch_and_tree('.')
751
 
        cb = self.Callback(u'commit 2', self)
752
 
        repository = tree.branch.repository
753
 
        # simulate network failure
754
 
        def raise_(self, arg, arg2, arg3=None, arg4=None):
755
 
            raise errors.NoSuchFile('foo')
756
 
        repository.add_inventory = raise_
757
 
        repository.add_inventory_by_delta = raise_
758
 
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
759
 
        self.assertFalse(cb.called)
760
 
 
761
 
    def test_selected_file_merge_commit(self):
762
 
        """Ensure the correct error is raised"""
763
 
        tree = self.make_branch_and_tree('foo')
764
 
        # pending merge would turn into a left parent
765
 
        tree.commit('commit 1')
766
 
        tree.add_parent_tree_id('example')
767
 
        self.build_tree(['foo/bar', 'foo/baz'])
768
 
        tree.add(['bar', 'baz'])
769
 
        err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
770
 
            tree.commit, 'commit 2', specific_files=['bar', 'baz'])
771
 
        self.assertEqual(['bar', 'baz'], err.files)
772
 
        self.assertEqual('Selected-file commit of merges is not supported'
773
 
                         ' yet: files bar, baz', str(err))
774
 
 
775
 
    def test_commit_ordering(self):
776
 
        """Test of corner-case commit ordering error"""
777
 
        tree = self.make_branch_and_tree('.')
778
 
        self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
779
 
        tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
780
 
        tree.commit('setup')
781
 
        self.build_tree(['a/c/d/'])
782
 
        tree.add('a/c/d')
783
 
        tree.rename_one('a/z/x', 'a/c/d/x')
784
 
        tree.commit('test', specific_files=['a/z/y'])
785
 
 
786
 
    def test_commit_no_author(self):
787
 
        """The default kwarg author in MutableTree.commit should not add
788
 
        the 'author' revision property.
789
 
        """
790
 
        tree = self.make_branch_and_tree('foo')
791
 
        rev_id = tree.commit('commit 1')
792
 
        rev = tree.branch.repository.get_revision(rev_id)
793
 
        self.assertFalse('author' in rev.properties)
794
 
        self.assertFalse('authors' in rev.properties)
795
 
 
796
 
    def test_commit_author(self):
797
 
        """Passing a non-empty author kwarg to MutableTree.commit should add
798
 
        the 'author' revision property.
799
 
        """
800
 
        tree = self.make_branch_and_tree('foo')
801
 
        rev_id = self.callDeprecated(['The parameter author was '
802
 
                'deprecated in version 1.13. Use authors instead'],
803
 
                tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
804
 
        rev = tree.branch.repository.get_revision(rev_id)
805
 
        self.assertEqual('John Doe <jdoe@example.com>',
806
 
                         rev.properties['authors'])
807
 
        self.assertFalse('author' in rev.properties)
808
 
 
809
 
    def test_commit_empty_authors_list(self):
810
 
        """Passing an empty list to authors shouldn't add the property."""
811
 
        tree = self.make_branch_and_tree('foo')
812
 
        rev_id = tree.commit('commit 1', authors=[])
813
 
        rev = tree.branch.repository.get_revision(rev_id)
814
 
        self.assertFalse('author' in rev.properties)
815
 
        self.assertFalse('authors' in rev.properties)
816
 
 
817
 
    def test_multiple_authors(self):
818
 
        tree = self.make_branch_and_tree('foo')
819
 
        rev_id = tree.commit('commit 1',
820
 
                authors=['John Doe <jdoe@example.com>',
821
 
                         'Jane Rey <jrey@example.com>'])
822
 
        rev = tree.branch.repository.get_revision(rev_id)
823
 
        self.assertEqual('John Doe <jdoe@example.com>\n'
824
 
                'Jane Rey <jrey@example.com>', rev.properties['authors'])
825
 
        self.assertFalse('author' in rev.properties)
826
 
 
827
 
    def test_author_and_authors_incompatible(self):
828
 
        tree = self.make_branch_and_tree('foo')
829
 
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
830
 
                authors=['John Doe <jdoe@example.com>',
831
 
                         'Jane Rey <jrey@example.com>'],
832
 
                author="Jack Me <jme@example.com>")
833
 
 
834
 
    def test_author_with_newline_rejected(self):
835
 
        tree = self.make_branch_and_tree('foo')
836
 
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
837
 
                authors=['John\nDoe <jdoe@example.com>'])
838
 
 
839
 
    def test_commit_with_checkout_and_branch_sharing_repo(self):
840
 
        repo = self.make_repository('repo', shared=True)
841
 
        # make_branch_and_tree ignores shared repos
842
 
        branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
843
 
        tree2 = branch.create_checkout('repo/tree2')
844
 
        tree2.commit('message', rev_id='rev1')
845
 
        self.assertTrue(tree2.branch.repository.has_revision('rev1'))
 
508
            ],
 
509
            reporter.calls)