~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Martin Packman
  • Date: 2011-12-13 17:10:47 UTC
  • mto: This revision was merged to the branch mainline in revision 6367.
  • Revision ID: martin.packman@canonical.com-20111213171047-esvi1kyfbuehmhrm
Minor tweaks including normalising _fs_enc value

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