~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Jelmer Vernooij
  • Date: 2011-08-19 22:34:02 UTC
  • mto: This revision was merged to the branch mainline in revision 6089.
  • Revision ID: jelmer@samba.org-20110819223402-wjywqb0fa1xxx522
Use get_transport_from_{url,path} in more places.

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')
112
166
        tree = b.repository.revision_tree('rev2')
113
167
        self.assertFalse(tree.has_id('hello-id'))
114
168
 
 
169
    def test_partial_commit_move(self):
 
170
        """Test a partial commit where a file was renamed but not committed.
 
171
 
 
172
        https://bugs.launchpad.net/bzr/+bug/83039
 
173
 
 
174
        If not handled properly, commit will try to snapshot
 
175
        dialog.py with olive/ as a parent, while
 
176
        olive/ has not been snapshotted yet.
 
177
        """
 
178
        wt = self.make_branch_and_tree('.')
 
179
        b = wt.branch
 
180
        self.build_tree(['annotate/', 'annotate/foo.py',
 
181
                         'olive/', 'olive/dialog.py'
 
182
                        ])
 
183
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
 
184
        wt.commit(message='add files')
 
185
        wt.rename_one("olive/dialog.py", "aaa")
 
186
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
 
187
        wt.commit('renamed hello', specific_files=["annotate"])
 
188
 
115
189
    def test_pointless_commit(self):
116
190
        """Commit refuses unless there are changes or it's forced."""
117
191
        wt = self.make_branch_and_tree('.')
125
199
                          message='fails',
126
200
                          allow_pointless=False)
127
201
        self.assertEquals(b.revno(), 1)
128
 
        
 
202
 
129
203
    def test_commit_empty(self):
130
204
        """Commiting an empty tree works."""
131
205
        wt = self.make_branch_and_tree('.')
148
222
              ['hello-id', 'buongia-id'])
149
223
        wt.commit(message='add files',
150
224
                 rev_id='test@rev-1')
151
 
        
 
225
 
152
226
        os.remove('hello')
153
227
        file('buongia', 'w').write('new text')
154
228
        wt.commit(message='update text',
165
239
        eq(b.revno(), 3)
166
240
 
167
241
        tree2 = b.repository.revision_tree('test@rev-2')
 
242
        tree2.lock_read()
 
243
        self.addCleanup(tree2.unlock)
168
244
        self.assertTrue(tree2.has_filename('hello'))
169
245
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
170
246
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
171
 
        
 
247
 
172
248
        tree3 = b.repository.revision_tree('test@rev-3')
 
249
        tree3.lock_read()
 
250
        self.addCleanup(tree3.unlock)
173
251
        self.assertFalse(tree3.has_filename('hello'))
174
252
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
175
253
 
186
264
 
187
265
        eq = self.assertEquals
188
266
        tree1 = b.repository.revision_tree('test@rev-1')
 
267
        tree1.lock_read()
 
268
        self.addCleanup(tree1.unlock)
189
269
        eq(tree1.id2path('hello-id'), 'hello')
190
270
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
191
271
        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')
 
272
        self.check_tree_shape(tree1, ['hello'])
 
273
        eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
195
274
 
196
275
        tree2 = b.repository.revision_tree('test@rev-2')
 
276
        tree2.lock_read()
 
277
        self.addCleanup(tree2.unlock)
197
278
        eq(tree2.id2path('hello-id'), 'fruity')
198
279
        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')
 
280
        self.check_tree_shape(tree2, ['fruity'])
 
281
        eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
202
282
 
203
283
    def test_reused_rev_id(self):
204
284
        """Test that a revision id cannot be reused in a branch"""
223
303
        wt.move(['hello'], 'a')
224
304
        r2 = 'test@rev-2'
225
305
        wt.commit('two', rev_id=r2, allow_pointless=False)
226
 
        self.check_inventory_shape(wt.read_working_inventory(),
227
 
                                   ['a', 'a/hello', 'b'])
 
306
        wt.lock_read()
 
307
        try:
 
308
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
 
309
        finally:
 
310
            wt.unlock()
228
311
 
229
312
        wt.move(['b'], 'a')
230
313
        r3 = 'test@rev-3'
231
314
        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'])
 
315
        wt.lock_read()
 
316
        try:
 
317
            self.check_tree_shape(wt,
 
318
                                       ['a/', 'a/hello', 'a/b/'])
 
319
            self.check_tree_shape(b.repository.revision_tree(r3),
 
320
                                       ['a/', 'a/hello', 'a/b/'])
 
321
        finally:
 
322
            wt.unlock()
236
323
 
237
324
        wt.move(['a/hello'], 'a/b')
238
325
        r4 = 'test@rev-4'
239
326
        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'])
 
327
        wt.lock_read()
 
328
        try:
 
329
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
 
330
        finally:
 
331
            wt.unlock()
242
332
 
243
 
        inv = b.repository.get_revision_inventory(r4)
 
333
        inv = b.repository.get_inventory(r4)
244
334
        eq(inv['hello-id'].revision, r4)
245
335
        eq(inv['a-id'].revision, r1)
246
336
        eq(inv['b-id'].revision, r3)
247
 
        
 
337
 
248
338
    def test_removed_commit(self):
249
339
        """Commit with a removed file"""
250
340
        wt = self.make_branch_and_tree('.')
274
364
        eq = self.assertEquals
275
365
        eq(b.revision_history(), rev_ids)
276
366
        for i in range(4):
277
 
            anc = b.repository.get_ancestry(rev_ids[i])
278
 
            eq(anc, [None] + rev_ids[:i+1])
 
367
            self.assertThat(rev_ids[:i+1],
 
368
                MatchesAncestry(b.repository, rev_ids[i]))
279
369
 
280
370
    def test_commit_new_subdir_child_selective(self):
281
371
        wt = self.make_branch_and_tree('.')
304
394
    def test_strict_commit_without_unknowns(self):
305
395
        """Try and commit with no unknown files and strict = True,
306
396
        should work."""
307
 
        from bzrlib.errors import StrictCommitFailed
308
397
        wt = self.make_branch_and_tree('.')
309
398
        b = wt.branch
310
399
        file('hello', 'w').write('hello world')
336
425
        wt = self.make_branch_and_tree('.')
337
426
        branch = wt.branch
338
427
        wt.commit("base", allow_pointless=True, rev_id='A')
339
 
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
 
428
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
340
429
        try:
341
430
            from bzrlib.testament import Testament
342
431
            # monkey patch gpg signing mechanism
345
434
                                                      allow_pointless=True,
346
435
                                                      rev_id='B',
347
436
                                                      working_tree=wt)
348
 
            self.assertEqual(Testament.from_revision(branch.repository,
349
 
                             'B').as_short_text(),
 
437
            def sign(text):
 
438
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
 
439
            self.assertEqual(sign(Testament.from_revision(branch.repository,
 
440
                             'B').as_short_text()),
350
441
                             branch.repository.get_signature_text('B'))
351
442
        finally:
352
443
            bzrlib.gpg.GPGStrategy = oldstrategy
358
449
        wt = self.make_branch_and_tree('.')
359
450
        branch = wt.branch
360
451
        wt.commit("base", allow_pointless=True, rev_id='A')
361
 
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
 
452
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
362
453
        try:
363
 
            from bzrlib.testament import Testament
364
454
            # monkey patch gpg signing mechanism
365
455
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
366
456
            config = MustSignConfig(branch)
372
462
                              working_tree=wt)
373
463
            branch = Branch.open(self.get_url('.'))
374
464
            self.assertEqual(branch.revision_history(), ['A'])
375
 
            self.failIf(branch.repository.has_revision('B'))
 
465
            self.assertFalse(branch.repository.has_revision('B'))
376
466
        finally:
377
467
            bzrlib.gpg.GPGStrategy = oldstrategy
378
468
 
413
503
        bound = master.sprout('bound')
414
504
        wt = bound.open_workingtree()
415
505
        wt.branch.set_bound_location(os.path.realpath('master'))
416
 
 
417
 
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
418
506
        master_branch.lock_write()
419
507
        try:
420
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
421
508
            self.assertRaises(LockContention, wt.commit, 'silly')
422
509
        finally:
423
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
424
510
            master_branch.unlock()
425
511
 
426
512
    def test_commit_bound_merge(self):
437
523
        other_bzrdir = master_branch.bzrdir.sprout('other')
438
524
        other_tree = other_bzrdir.open_workingtree()
439
525
 
440
 
        # do a commit to the the other branch changing the content file so
 
526
        # do a commit to the other branch changing the content file so
441
527
        # that our commit after merging will have a merged revision in the
442
528
        # content file history.
443
529
        self.build_tree_contents([('other/content_file', 'change in other\n')])
454
540
        bound_tree.commit(message='commit of merge in bound tree')
455
541
 
456
542
    def test_commit_reporting_after_merge(self):
457
 
        # when doing a commit of a merge, the reporter needs to still 
 
543
        # when doing a commit of a merge, the reporter needs to still
458
544
        # be called for each item that is added/removed/deleted.
459
545
        this_tree = self.make_branch_and_tree('this')
460
546
        # we need a bunch of files and dirs, to perform one action on each.
503
589
        this_tree.merge_from_branch(other_tree.branch)
504
590
        reporter = CapturingReporter()
505
591
        this_tree.commit('do the commit', reporter=reporter)
506
 
        self.assertEqual([
507
 
            ('change', 'unchanged', ''),
508
 
            ('change', 'unchanged', 'dirtoleave'),
509
 
            ('change', 'unchanged', 'filetoleave'),
 
592
        expected = set([
510
593
            ('change', 'modified', 'filetomodify'),
511
594
            ('change', 'added', 'newdir'),
512
595
            ('change', 'added', 'newfile'),
513
596
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
 
597
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
514
598
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
515
599
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
516
 
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
517
600
            ('deleted', 'dirtoremove'),
518
601
            ('deleted', 'filetoremove'),
519
 
            ],
520
 
            reporter.calls)
 
602
            ])
 
603
        result = set(reporter.calls)
 
604
        missing = expected - result
 
605
        new = result - expected
 
606
        self.assertEqual((set(), set()), (missing, new))
521
607
 
522
608
    def test_commit_removals_respects_filespec(self):
523
609
        """Commit respects the specified_files for removals."""
527
613
        tree.commit('added a, b')
528
614
        tree.remove(['a', 'b'])
529
615
        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)
 
616
        basis = tree.basis_tree()
 
617
        tree.lock_read()
 
618
        try:
 
619
            self.assertIs(None, basis.path2id('a'))
 
620
            self.assertFalse(basis.path2id('b') is None)
 
621
        finally:
 
622
            tree.unlock()
533
623
 
534
624
    def test_commit_saves_1ms_timestamp(self):
535
625
        """Passing in a timestamp is saved with 1ms resolution"""
554
644
        timestamp_1ms = round(timestamp, 3)
555
645
        self.assertEqual(timestamp_1ms, timestamp)
556
646
 
 
647
    def assertBasisTreeKind(self, kind, tree, file_id):
 
648
        basis = tree.basis_tree()
 
649
        basis.lock_read()
 
650
        try:
 
651
            self.assertEqual(kind, basis.kind(file_id))
 
652
        finally:
 
653
            basis.unlock()
 
654
 
557
655
    def test_commit_kind_changes(self):
558
 
        if not osutils.has_symlinks():
559
 
            raise tests.TestSkipped('Test requires symlink support')
 
656
        self.requireFeature(SymlinkFeature)
560
657
        tree = self.make_branch_and_tree('.')
561
658
        os.symlink('target', 'name')
562
659
        tree.add('name', 'a-file-id')
563
660
        tree.commit('Added a symlink')
564
 
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
661
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
565
662
 
566
663
        os.unlink('name')
567
664
        self.build_tree(['name'])
568
665
        tree.commit('Changed symlink to file')
569
 
        self.assertEqual('file', tree.basis_tree().kind('a-file-id'))
 
666
        self.assertBasisTreeKind('file', tree, 'a-file-id')
570
667
 
571
668
        os.unlink('name')
572
669
        os.symlink('target', 'name')
573
670
        tree.commit('file to symlink')
574
 
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
671
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
575
672
 
576
673
        os.unlink('name')
577
674
        os.mkdir('name')
578
675
        tree.commit('symlink to directory')
579
 
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
676
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
580
677
 
581
678
        os.rmdir('name')
582
679
        os.symlink('target', 'name')
583
680
        tree.commit('directory to symlink')
584
 
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
681
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
585
682
 
586
683
        # prepare for directory <-> file tests
587
684
        os.unlink('name')
588
685
        os.mkdir('name')
589
686
        tree.commit('symlink to directory')
590
 
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
687
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
591
688
 
592
689
        os.rmdir('name')
593
690
        self.build_tree(['name'])
594
691
        tree.commit('Changed directory to file')
595
 
        self.assertEqual('file', tree.basis_tree().kind('a-file-id'))
 
692
        self.assertBasisTreeKind('file', tree, 'a-file-id')
596
693
 
597
694
        os.unlink('name')
598
695
        os.mkdir('name')
599
696
        tree.commit('file to directory')
600
 
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
697
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
601
698
 
602
699
    def test_commit_unversioned_specified(self):
603
700
        """Commit should raise if specified files isn't in basis or worktree"""
604
701
        tree = self.make_branch_and_tree('.')
605
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
 
702
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
606
703
                          'message', specific_files=['bogus'])
607
704
 
608
705
    class Callback(object):
609
 
        
 
706
 
610
707
        def __init__(self, message, testcase):
611
708
            self.called = False
612
709
            self.message = message
640
737
        """Callback should not be invoked for pointless commit"""
641
738
        tree = self.make_branch_and_tree('.')
642
739
        cb = self.Callback(u'commit 2', self)
643
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
 
740
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
644
741
                          allow_pointless=False)
645
742
        self.assertFalse(cb.called)
646
743
 
650
747
        cb = self.Callback(u'commit 2', self)
651
748
        repository = tree.branch.repository
652
749
        # simulate network failure
653
 
        def raise_(self, arg, arg2):
 
750
        def raise_(self, arg, arg2, arg3=None, arg4=None):
654
751
            raise errors.NoSuchFile('foo')
655
752
        repository.add_inventory = raise_
 
753
        repository.add_inventory_by_delta = raise_
656
754
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
657
755
        self.assertFalse(cb.called)
 
756
 
 
757
    def test_selected_file_merge_commit(self):
 
758
        """Ensure the correct error is raised"""
 
759
        tree = self.make_branch_and_tree('foo')
 
760
        # pending merge would turn into a left parent
 
761
        tree.commit('commit 1')
 
762
        tree.add_parent_tree_id('example')
 
763
        self.build_tree(['foo/bar', 'foo/baz'])
 
764
        tree.add(['bar', 'baz'])
 
765
        err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
 
766
            tree.commit, 'commit 2', specific_files=['bar', 'baz'])
 
767
        self.assertEqual(['bar', 'baz'], err.files)
 
768
        self.assertEqual('Selected-file commit of merges is not supported'
 
769
                         ' yet: files bar, baz', str(err))
 
770
 
 
771
    def test_commit_ordering(self):
 
772
        """Test of corner-case commit ordering error"""
 
773
        tree = self.make_branch_and_tree('.')
 
774
        self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
 
775
        tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
 
776
        tree.commit('setup')
 
777
        self.build_tree(['a/c/d/'])
 
778
        tree.add('a/c/d')
 
779
        tree.rename_one('a/z/x', 'a/c/d/x')
 
780
        tree.commit('test', specific_files=['a/z/y'])
 
781
 
 
782
    def test_commit_no_author(self):
 
783
        """The default kwarg author in MutableTree.commit should not add
 
784
        the 'author' revision property.
 
785
        """
 
786
        tree = self.make_branch_and_tree('foo')
 
787
        rev_id = tree.commit('commit 1')
 
788
        rev = tree.branch.repository.get_revision(rev_id)
 
789
        self.assertFalse('author' in rev.properties)
 
790
        self.assertFalse('authors' in rev.properties)
 
791
 
 
792
    def test_commit_author(self):
 
793
        """Passing a non-empty author kwarg to MutableTree.commit should add
 
794
        the 'author' revision property.
 
795
        """
 
796
        tree = self.make_branch_and_tree('foo')
 
797
        rev_id = self.callDeprecated(['The parameter author was '
 
798
                'deprecated in version 1.13. Use authors instead'],
 
799
                tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
 
800
        rev = tree.branch.repository.get_revision(rev_id)
 
801
        self.assertEqual('John Doe <jdoe@example.com>',
 
802
                         rev.properties['authors'])
 
803
        self.assertFalse('author' in rev.properties)
 
804
 
 
805
    def test_commit_empty_authors_list(self):
 
806
        """Passing an empty list to authors shouldn't add the property."""
 
807
        tree = self.make_branch_and_tree('foo')
 
808
        rev_id = tree.commit('commit 1', authors=[])
 
809
        rev = tree.branch.repository.get_revision(rev_id)
 
810
        self.assertFalse('author' in rev.properties)
 
811
        self.assertFalse('authors' in rev.properties)
 
812
 
 
813
    def test_multiple_authors(self):
 
814
        tree = self.make_branch_and_tree('foo')
 
815
        rev_id = tree.commit('commit 1',
 
816
                authors=['John Doe <jdoe@example.com>',
 
817
                         'Jane Rey <jrey@example.com>'])
 
818
        rev = tree.branch.repository.get_revision(rev_id)
 
819
        self.assertEqual('John Doe <jdoe@example.com>\n'
 
820
                'Jane Rey <jrey@example.com>', rev.properties['authors'])
 
821
        self.assertFalse('author' in rev.properties)
 
822
 
 
823
    def test_author_and_authors_incompatible(self):
 
824
        tree = self.make_branch_and_tree('foo')
 
825
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
 
826
                authors=['John Doe <jdoe@example.com>',
 
827
                         'Jane Rey <jrey@example.com>'],
 
828
                author="Jack Me <jme@example.com>")
 
829
 
 
830
    def test_author_with_newline_rejected(self):
 
831
        tree = self.make_branch_and_tree('foo')
 
832
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
 
833
                authors=['John\nDoe <jdoe@example.com>'])
 
834
 
 
835
    def test_commit_with_checkout_and_branch_sharing_repo(self):
 
836
        repo = self.make_repository('repo', shared=True)
 
837
        # make_branch_and_tree ignores shared repos
 
838
        branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
 
839
        tree2 = branch.create_checkout('repo/tree2')
 
840
        tree2.commit('message', rev_id='rev1')
 
841
        self.assertTrue(tree2.branch.repository.has_revision('rev1'))