~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: 2011-09-26 12:12:40 UTC
  • mto: This revision was merged to the branch mainline in revision 6170.
  • Revision ID: john@arbash-meinel.com-20110926121240-vdlz94tgi2i6py0f
Jelmer caught that getsignal() only takes one parameter.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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
 
    lockdir,
24
 
    osutils,
25
 
    tests,
26
24
    )
27
25
from bzrlib.branch import Branch
28
 
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
 
26
from bzrlib.bzrdir import BzrDirMetaFormat1
29
27
from bzrlib.commit import Commit, NullCommitReporter
30
28
from bzrlib.config import BranchConfig
31
 
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
32
 
                           LockContention)
33
 
from bzrlib.tests import TestCaseWithTransport
34
 
from bzrlib.workingtree import WorkingTree
 
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
35
43
 
36
44
 
37
45
# TODO: Test commit with some added, and added-but-missing files
70
78
    def renamed(self, change, old_path, new_path):
71
79
        self.calls.append(('renamed', change, old_path, new_path))
72
80
 
 
81
    def is_verbose(self):
 
82
        return True
 
83
 
73
84
 
74
85
class TestCommit(TestCaseWithTransport):
75
86
 
92
103
        eq(rev.message, 'add hello')
93
104
 
94
105
        tree1 = b.repository.revision_tree(rh[0])
 
106
        tree1.lock_read()
95
107
        text = tree1.get_file_text(file_id)
96
 
        eq(text, 'hello world')
 
108
        tree1.unlock()
 
109
        self.assertEqual('hello world', text)
97
110
 
98
111
        tree2 = b.repository.revision_tree(rh[1])
99
 
        eq(tree2.get_file_text(file_id), 'version 2')
100
 
 
101
 
    def test_delete_commit(self):
102
 
        """Test a commit with a deleted file"""
 
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"""
103
157
        wt = self.make_branch_and_tree('.')
104
158
        b = wt.branch
105
159
        file('hello', 'w').write('hello world')
107
161
        wt.commit(message='add hello')
108
162
 
109
163
        os.remove('hello')
110
 
        wt.commit('removed hello', rev_id='rev2')
 
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)
111
169
 
112
170
        tree = b.repository.revision_tree('rev2')
113
171
        self.assertFalse(tree.has_id('hello-id'))
114
172
 
 
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
 
115
193
    def test_pointless_commit(self):
116
194
        """Commit refuses unless there are changes or it's forced."""
117
195
        wt = self.make_branch_and_tree('.')
125
203
                          message='fails',
126
204
                          allow_pointless=False)
127
205
        self.assertEquals(b.revno(), 1)
128
 
        
 
206
 
129
207
    def test_commit_empty(self):
130
208
        """Commiting an empty tree works."""
131
209
        wt = self.make_branch_and_tree('.')
148
226
              ['hello-id', 'buongia-id'])
149
227
        wt.commit(message='add files',
150
228
                 rev_id='test@rev-1')
151
 
        
 
229
 
152
230
        os.remove('hello')
153
231
        file('buongia', 'w').write('new text')
154
232
        wt.commit(message='update text',
165
243
        eq(b.revno(), 3)
166
244
 
167
245
        tree2 = b.repository.revision_tree('test@rev-2')
 
246
        tree2.lock_read()
 
247
        self.addCleanup(tree2.unlock)
168
248
        self.assertTrue(tree2.has_filename('hello'))
169
249
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
170
250
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
171
 
        
 
251
 
172
252
        tree3 = b.repository.revision_tree('test@rev-3')
 
253
        tree3.lock_read()
 
254
        self.addCleanup(tree3.unlock)
173
255
        self.assertFalse(tree3.has_filename('hello'))
174
256
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
175
257
 
186
268
 
187
269
        eq = self.assertEquals
188
270
        tree1 = b.repository.revision_tree('test@rev-1')
 
271
        tree1.lock_read()
 
272
        self.addCleanup(tree1.unlock)
189
273
        eq(tree1.id2path('hello-id'), 'hello')
190
274
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
191
275
        self.assertFalse(tree1.has_filename('fruity'))
192
 
        self.check_inventory_shape(tree1.inventory, ['hello'])
193
 
        ie = tree1.inventory['hello-id']
194
 
        eq(ie.revision, 'test@rev-1')
 
276
        self.check_tree_shape(tree1, ['hello'])
 
277
        eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
195
278
 
196
279
        tree2 = b.repository.revision_tree('test@rev-2')
 
280
        tree2.lock_read()
 
281
        self.addCleanup(tree2.unlock)
197
282
        eq(tree2.id2path('hello-id'), 'fruity')
198
283
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
199
 
        self.check_inventory_shape(tree2.inventory, ['fruity'])
200
 
        ie = tree2.inventory['hello-id']
201
 
        eq(ie.revision, 'test@rev-2')
 
284
        self.check_tree_shape(tree2, ['fruity'])
 
285
        eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
202
286
 
203
287
    def test_reused_rev_id(self):
204
288
        """Test that a revision id cannot be reused in a branch"""
223
307
        wt.move(['hello'], 'a')
224
308
        r2 = 'test@rev-2'
225
309
        wt.commit('two', rev_id=r2, allow_pointless=False)
226
 
        self.check_inventory_shape(wt.read_working_inventory(),
227
 
                                   ['a', 'a/hello', 'b'])
 
310
        wt.lock_read()
 
311
        try:
 
312
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
 
313
        finally:
 
314
            wt.unlock()
228
315
 
229
316
        wt.move(['b'], 'a')
230
317
        r3 = 'test@rev-3'
231
318
        wt.commit('three', rev_id=r3, allow_pointless=False)
232
 
        self.check_inventory_shape(wt.read_working_inventory(),
233
 
                                   ['a', 'a/hello', 'a/b'])
234
 
        self.check_inventory_shape(b.repository.get_revision_inventory(r3),
235
 
                                   ['a', 'a/hello', 'a/b'])
 
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()
236
327
 
237
328
        wt.move(['a/hello'], 'a/b')
238
329
        r4 = 'test@rev-4'
239
330
        wt.commit('four', rev_id=r4, allow_pointless=False)
240
 
        self.check_inventory_shape(wt.read_working_inventory(),
241
 
                                   ['a', 'a/b/hello', 'a/b'])
 
331
        wt.lock_read()
 
332
        try:
 
333
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
 
334
        finally:
 
335
            wt.unlock()
242
336
 
243
 
        inv = b.repository.get_revision_inventory(r4)
 
337
        inv = b.repository.get_inventory(r4)
244
338
        eq(inv['hello-id'].revision, r4)
245
339
        eq(inv['a-id'].revision, r1)
246
340
        eq(inv['b-id'].revision, r3)
247
 
        
 
341
 
248
342
    def test_removed_commit(self):
249
343
        """Commit with a removed file"""
250
344
        wt = self.make_branch_and_tree('.')
274
368
        eq = self.assertEquals
275
369
        eq(b.revision_history(), rev_ids)
276
370
        for i in range(4):
277
 
            anc = b.repository.get_ancestry(rev_ids[i])
278
 
            eq(anc, [None] + rev_ids[:i+1])
 
371
            self.assertThat(rev_ids[:i+1],
 
372
                MatchesAncestry(b.repository, rev_ids[i]))
279
373
 
280
374
    def test_commit_new_subdir_child_selective(self):
281
375
        wt = self.make_branch_and_tree('.')
304
398
    def test_strict_commit_without_unknowns(self):
305
399
        """Try and commit with no unknown files and strict = True,
306
400
        should work."""
307
 
        from bzrlib.errors import StrictCommitFailed
308
401
        wt = self.make_branch_and_tree('.')
309
402
        b = wt.branch
310
403
        file('hello', 'w').write('hello world')
336
429
        wt = self.make_branch_and_tree('.')
337
430
        branch = wt.branch
338
431
        wt.commit("base", allow_pointless=True, rev_id='A')
339
 
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
 
432
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
340
433
        try:
341
434
            from bzrlib.testament import Testament
342
435
            # monkey patch gpg signing mechanism
345
438
                                                      allow_pointless=True,
346
439
                                                      rev_id='B',
347
440
                                                      working_tree=wt)
348
 
            self.assertEqual(Testament.from_revision(branch.repository,
349
 
                             'B').as_short_text(),
 
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()),
350
445
                             branch.repository.get_signature_text('B'))
351
446
        finally:
352
447
            bzrlib.gpg.GPGStrategy = oldstrategy
358
453
        wt = self.make_branch_and_tree('.')
359
454
        branch = wt.branch
360
455
        wt.commit("base", allow_pointless=True, rev_id='A')
361
 
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
 
456
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
362
457
        try:
363
 
            from bzrlib.testament import Testament
364
458
            # monkey patch gpg signing mechanism
365
459
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
366
460
            config = MustSignConfig(branch)
372
466
                              working_tree=wt)
373
467
            branch = Branch.open(self.get_url('.'))
374
468
            self.assertEqual(branch.revision_history(), ['A'])
375
 
            self.failIf(branch.repository.has_revision('B'))
 
469
            self.assertFalse(branch.repository.has_revision('B'))
376
470
        finally:
377
471
            bzrlib.gpg.GPGStrategy = oldstrategy
378
472
 
413
507
        bound = master.sprout('bound')
414
508
        wt = bound.open_workingtree()
415
509
        wt.branch.set_bound_location(os.path.realpath('master'))
416
 
 
417
 
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
418
510
        master_branch.lock_write()
419
511
        try:
420
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
421
512
            self.assertRaises(LockContention, wt.commit, 'silly')
422
513
        finally:
423
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
424
514
            master_branch.unlock()
425
515
 
426
516
    def test_commit_bound_merge(self):
437
527
        other_bzrdir = master_branch.bzrdir.sprout('other')
438
528
        other_tree = other_bzrdir.open_workingtree()
439
529
 
440
 
        # do a commit to the the other branch changing the content file so
 
530
        # do a commit to the other branch changing the content file so
441
531
        # that our commit after merging will have a merged revision in the
442
532
        # content file history.
443
533
        self.build_tree_contents([('other/content_file', 'change in other\n')])
454
544
        bound_tree.commit(message='commit of merge in bound tree')
455
545
 
456
546
    def test_commit_reporting_after_merge(self):
457
 
        # when doing a commit of a merge, the reporter needs to still 
 
547
        # when doing a commit of a merge, the reporter needs to still
458
548
        # be called for each item that is added/removed/deleted.
459
549
        this_tree = self.make_branch_and_tree('this')
460
550
        # we need a bunch of files and dirs, to perform one action on each.
503
593
        this_tree.merge_from_branch(other_tree.branch)
504
594
        reporter = CapturingReporter()
505
595
        this_tree.commit('do the commit', reporter=reporter)
506
 
        self.assertEqual([
507
 
            ('change', 'unchanged', ''),
508
 
            ('change', 'unchanged', 'dirtoleave'),
509
 
            ('change', 'unchanged', 'filetoleave'),
 
596
        expected = set([
510
597
            ('change', 'modified', 'filetomodify'),
511
598
            ('change', 'added', 'newdir'),
512
599
            ('change', 'added', 'newfile'),
513
600
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
 
601
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
514
602
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
515
603
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
516
 
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
517
604
            ('deleted', 'dirtoremove'),
518
605
            ('deleted', 'filetoremove'),
519
 
            ],
520
 
            reporter.calls)
 
606
            ])
 
607
        result = set(reporter.calls)
 
608
        missing = expected - result
 
609
        new = result - expected
 
610
        self.assertEqual((set(), set()), (missing, new))
521
611
 
522
612
    def test_commit_removals_respects_filespec(self):
523
613
        """Commit respects the specified_files for removals."""
527
617
        tree.commit('added a, b')
528
618
        tree.remove(['a', 'b'])
529
619
        tree.commit('removed a', specific_files='a')
530
 
        basis = tree.basis_tree().inventory
531
 
        self.assertIs(None, basis.path2id('a'))
532
 
        self.assertFalse(basis.path2id('b') is None)
 
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()
533
627
 
534
628
    def test_commit_saves_1ms_timestamp(self):
535
629
        """Passing in a timestamp is saved with 1ms resolution"""
554
648
        timestamp_1ms = round(timestamp, 3)
555
649
        self.assertEqual(timestamp_1ms, timestamp)
556
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
 
557
659
    def test_commit_kind_changes(self):
558
 
        if not osutils.has_symlinks():
559
 
            raise tests.TestSkipped('Test requires symlink support')
 
660
        self.requireFeature(SymlinkFeature)
560
661
        tree = self.make_branch_and_tree('.')
561
662
        os.symlink('target', 'name')
562
663
        tree.add('name', 'a-file-id')
563
664
        tree.commit('Added a symlink')
564
 
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
665
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
565
666
 
566
667
        os.unlink('name')
567
668
        self.build_tree(['name'])
568
669
        tree.commit('Changed symlink to file')
569
 
        self.assertEqual('file', tree.basis_tree().kind('a-file-id'))
 
670
        self.assertBasisTreeKind('file', tree, 'a-file-id')
570
671
 
571
672
        os.unlink('name')
572
673
        os.symlink('target', 'name')
573
674
        tree.commit('file to symlink')
574
 
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
675
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
575
676
 
576
677
        os.unlink('name')
577
678
        os.mkdir('name')
578
679
        tree.commit('symlink to directory')
579
 
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
680
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
580
681
 
581
682
        os.rmdir('name')
582
683
        os.symlink('target', 'name')
583
684
        tree.commit('directory to symlink')
584
 
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
685
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
585
686
 
586
687
        # prepare for directory <-> file tests
587
688
        os.unlink('name')
588
689
        os.mkdir('name')
589
690
        tree.commit('symlink to directory')
590
 
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
691
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
591
692
 
592
693
        os.rmdir('name')
593
694
        self.build_tree(['name'])
594
695
        tree.commit('Changed directory to file')
595
 
        self.assertEqual('file', tree.basis_tree().kind('a-file-id'))
 
696
        self.assertBasisTreeKind('file', tree, 'a-file-id')
596
697
 
597
698
        os.unlink('name')
598
699
        os.mkdir('name')
599
700
        tree.commit('file to directory')
600
 
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
701
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
601
702
 
602
703
    def test_commit_unversioned_specified(self):
603
704
        """Commit should raise if specified files isn't in basis or worktree"""
604
705
        tree = self.make_branch_and_tree('.')
605
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
 
706
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
606
707
                          'message', specific_files=['bogus'])
607
708
 
608
709
    class Callback(object):
609
 
        
 
710
 
610
711
        def __init__(self, message, testcase):
611
712
            self.called = False
612
713
            self.message = message
640
741
        """Callback should not be invoked for pointless commit"""
641
742
        tree = self.make_branch_and_tree('.')
642
743
        cb = self.Callback(u'commit 2', self)
643
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
 
744
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
644
745
                          allow_pointless=False)
645
746
        self.assertFalse(cb.called)
646
747
 
650
751
        cb = self.Callback(u'commit 2', self)
651
752
        repository = tree.branch.repository
652
753
        # simulate network failure
653
 
        def raise_(self, arg, arg2):
 
754
        def raise_(self, arg, arg2, arg3=None, arg4=None):
654
755
            raise errors.NoSuchFile('foo')
655
756
        repository.add_inventory = raise_
 
757
        repository.add_inventory_by_delta = raise_
656
758
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
657
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'))