~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: INADA Naoki
  • Date: 2011-05-05 09:15:34 UTC
  • mto: (5830.3.3 i18n-msgfmt)
  • mto: This revision was merged to the branch mainline in revision 5873.
  • Revision ID: songofacandy@gmail.com-20110505091534-7sv835xpofwrmpt4
Add update-pot command to Makefile and tools/bzrgettext script that
extracts help text from bzr commands.

Show diffs side-by-side

added added

removed removed

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