~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Patch Queue Manager
  • Date: 2016-04-21 04:10:52 UTC
  • mfrom: (6616.1.1 fix-en-user-guide)
  • Revision ID: pqm@pqm.ubuntu.com-20160421041052-clcye7ns1qcl2n7w
(richard-wilbur) Ensure build of English use guide always uses English text
 even when user's locale specifies a different language. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2012, 2016 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
    config,
 
23
    controldir,
22
24
    errors,
23
 
    lockdir,
24
 
    osutils,
25
 
    tests,
26
25
    )
27
26
from bzrlib.branch import Branch
28
 
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
 
27
from bzrlib.bzrdir import BzrDirMetaFormat1
29
28
from bzrlib.commit import Commit, NullCommitReporter
30
 
from bzrlib.config import BranchConfig
31
 
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
32
 
                           LockContention)
33
 
from bzrlib.tests import SymlinkFeature, 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
38
46
 
39
 
class MustSignConfig(BranchConfig):
40
 
 
41
 
    def signature_needed(self):
42
 
        return True
43
 
 
44
 
    def gpg_signing_command(self):
45
 
        return ['cat', '-']
46
 
 
47
 
 
48
 
class BranchWithHooks(BranchConfig):
49
 
 
50
 
    def post_commit(self):
51
 
        return "bzrlib.ahook bzrlib.ahook"
 
47
class MustSignConfig(config.MemoryStack):
 
48
 
 
49
    def __init__(self):
 
50
        super(MustSignConfig, self).__init__('''
 
51
gpg_signing_command=cat -
 
52
create_signatures=always
 
53
''')
52
54
 
53
55
 
54
56
class CapturingReporter(NullCommitReporter):
80
82
        """Commit and check two versions of a single file."""
81
83
        wt = self.make_branch_and_tree('.')
82
84
        b = wt.branch
83
 
        file('hello', 'w').write('hello world')
 
85
        with file('hello', 'w') as f: f.write('hello world')
84
86
        wt.add('hello')
85
 
        wt.commit(message='add hello')
 
87
        rev1 = wt.commit(message='add hello')
86
88
        file_id = wt.path2id('hello')
87
89
 
88
 
        file('hello', 'w').write('version 2')
89
 
        wt.commit(message='commit 2')
 
90
        with file('hello', 'w') as f: f.write('version 2')
 
91
        rev2 = wt.commit(message='commit 2')
90
92
 
91
 
        eq = self.assertEquals
 
93
        eq = self.assertEqual
92
94
        eq(b.revno(), 2)
93
 
        rh = b.revision_history()
94
 
        rev = b.repository.get_revision(rh[0])
 
95
        rev = b.repository.get_revision(rev1)
95
96
        eq(rev.message, 'add hello')
96
97
 
97
 
        tree1 = b.repository.revision_tree(rh[0])
 
98
        tree1 = b.repository.revision_tree(rev1)
98
99
        tree1.lock_read()
99
100
        text = tree1.get_file_text(file_id)
100
101
        tree1.unlock()
101
102
        self.assertEqual('hello world', text)
102
103
 
103
 
        tree2 = b.repository.revision_tree(rh[1])
 
104
        tree2 = b.repository.revision_tree(rev2)
104
105
        tree2.lock_read()
105
106
        text = tree2.get_file_text(file_id)
106
107
        tree2.unlock()
107
108
        self.assertEqual('version 2', text)
108
109
 
109
 
    def test_delete_commit(self):
110
 
        """Test a commit with a deleted file"""
111
 
        wt = self.make_branch_and_tree('.')
112
 
        b = wt.branch
113
 
        file('hello', 'w').write('hello world')
 
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
        with file('hello', 'w') as f: f.write('hello world')
 
115
        wt.add('hello')
 
116
        revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
 
117
        self.assertEqual('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
        with file('hello', 'w') as f: f.write('hello world')
 
126
        wt.add('hello')
 
127
        revid = wt.commit(message='add hello', lossy=True,
 
128
            timestamp=1302659388, timezone=0)
 
129
        self.assertEqual('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
        with file('local/hello', 'w') as f: f.write('hello world')
 
139
        wt.add('hello')
 
140
        revid = wt.commit(message='add hello', lossy=True,
 
141
            timestamp=1302659388, timezone=0)
 
142
        self.assertEqual('dummy-v1:1302659388.0-0-0', revid)
 
143
        self.assertEqual('dummy-v1:1302659388.0-0-0',
 
144
            foreign_branch.last_revision())
 
145
        self.assertEqual('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"""
 
150
        wt = self.make_branch_and_tree('.')
 
151
        b = wt.branch
 
152
        with file('hello', 'w') as f: f.write('hello world')
114
153
        wt.add(['hello'], ['hello-id'])
115
154
        wt.commit(message='add hello')
116
155
 
117
156
        os.remove('hello')
118
 
        wt.commit('removed hello', rev_id='rev2')
 
157
        reporter = CapturingReporter()
 
158
        wt.commit('removed hello', rev_id='rev2', reporter=reporter)
 
159
        self.assertEqual(
 
160
            [('missing', u'hello'), ('deleted', u'hello')],
 
161
            reporter.calls)
119
162
 
120
163
        tree = b.repository.revision_tree('rev2')
121
164
        self.assertFalse(tree.has_id('hello-id'))
122
165
 
 
166
    def test_partial_commit_move(self):
 
167
        """Test a partial commit where a file was renamed but not committed.
 
168
 
 
169
        https://bugs.launchpad.net/bzr/+bug/83039
 
170
 
 
171
        If not handled properly, commit will try to snapshot
 
172
        dialog.py with olive/ as a parent, while
 
173
        olive/ has not been snapshotted yet.
 
174
        """
 
175
        wt = self.make_branch_and_tree('.')
 
176
        b = wt.branch
 
177
        self.build_tree(['annotate/', 'annotate/foo.py',
 
178
                         'olive/', 'olive/dialog.py'
 
179
                        ])
 
180
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
 
181
        wt.commit(message='add files')
 
182
        wt.rename_one("olive/dialog.py", "aaa")
 
183
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
 
184
        wt.commit('renamed hello', specific_files=["annotate"])
 
185
 
123
186
    def test_pointless_commit(self):
124
187
        """Commit refuses unless there are changes or it's forced."""
125
188
        wt = self.make_branch_and_tree('.')
126
189
        b = wt.branch
127
 
        file('hello', 'w').write('hello')
 
190
        with file('hello', 'w') as f: f.write('hello')
128
191
        wt.add(['hello'])
129
192
        wt.commit(message='add hello')
130
 
        self.assertEquals(b.revno(), 1)
 
193
        self.assertEqual(b.revno(), 1)
131
194
        self.assertRaises(PointlessCommit,
132
195
                          wt.commit,
133
196
                          message='fails',
134
197
                          allow_pointless=False)
135
 
        self.assertEquals(b.revno(), 1)
136
 
        
 
198
        self.assertEqual(b.revno(), 1)
 
199
 
137
200
    def test_commit_empty(self):
138
201
        """Commiting an empty tree works."""
139
202
        wt = self.make_branch_and_tree('.')
144
207
                          message='empty tree',
145
208
                          allow_pointless=False)
146
209
        wt.commit(message='empty tree', allow_pointless=True)
147
 
        self.assertEquals(b.revno(), 2)
 
210
        self.assertEqual(b.revno(), 2)
148
211
 
149
212
    def test_selective_delete(self):
150
213
        """Selective commit in tree with deletions"""
151
214
        wt = self.make_branch_and_tree('.')
152
215
        b = wt.branch
153
 
        file('hello', 'w').write('hello')
154
 
        file('buongia', 'w').write('buongia')
 
216
        with file('hello', 'w') as f: f.write('hello')
 
217
        with file('buongia', 'w') as f: f.write('buongia')
155
218
        wt.add(['hello', 'buongia'],
156
219
              ['hello-id', 'buongia-id'])
157
220
        wt.commit(message='add files',
158
221
                 rev_id='test@rev-1')
159
 
        
 
222
 
160
223
        os.remove('hello')
161
 
        file('buongia', 'w').write('new text')
 
224
        with file('buongia', 'w') as f: f.write('new text')
162
225
        wt.commit(message='update text',
163
226
                 specific_files=['buongia'],
164
227
                 allow_pointless=False,
169
232
                 allow_pointless=False,
170
233
                 rev_id='test@rev-3')
171
234
 
172
 
        eq = self.assertEquals
 
235
        eq = self.assertEqual
173
236
        eq(b.revno(), 3)
174
237
 
175
238
        tree2 = b.repository.revision_tree('test@rev-2')
176
239
        tree2.lock_read()
177
240
        self.addCleanup(tree2.unlock)
178
241
        self.assertTrue(tree2.has_filename('hello'))
179
 
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
180
 
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
181
 
        
 
242
        self.assertEqual(tree2.get_file_text('hello-id'), 'hello')
 
243
        self.assertEqual(tree2.get_file_text('buongia-id'), 'new text')
 
244
 
182
245
        tree3 = b.repository.revision_tree('test@rev-3')
183
246
        tree3.lock_read()
184
247
        self.addCleanup(tree3.unlock)
185
248
        self.assertFalse(tree3.has_filename('hello'))
186
 
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
 
249
        self.assertEqual(tree3.get_file_text('buongia-id'), 'new text')
187
250
 
188
251
    def test_commit_rename(self):
189
252
        """Test commit of a revision where a file is renamed."""
196
259
        tree.rename_one('hello', 'fruity')
197
260
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
198
261
 
199
 
        eq = self.assertEquals
 
262
        eq = self.assertEqual
200
263
        tree1 = b.repository.revision_tree('test@rev-1')
201
264
        tree1.lock_read()
202
265
        self.addCleanup(tree1.unlock)
203
266
        eq(tree1.id2path('hello-id'), 'hello')
204
267
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
205
268
        self.assertFalse(tree1.has_filename('fruity'))
206
 
        self.check_inventory_shape(tree1.inventory, ['hello'])
207
 
        ie = tree1.inventory['hello-id']
208
 
        eq(ie.revision, 'test@rev-1')
 
269
        self.check_tree_shape(tree1, ['hello'])
 
270
        eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
209
271
 
210
272
        tree2 = b.repository.revision_tree('test@rev-2')
211
273
        tree2.lock_read()
212
274
        self.addCleanup(tree2.unlock)
213
275
        eq(tree2.id2path('hello-id'), 'fruity')
214
276
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
215
 
        self.check_inventory_shape(tree2.inventory, ['fruity'])
216
 
        ie = tree2.inventory['hello-id']
217
 
        eq(ie.revision, 'test@rev-2')
 
277
        self.check_tree_shape(tree2, ['fruity'])
 
278
        eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
218
279
 
219
280
    def test_reused_rev_id(self):
220
281
        """Test that a revision id cannot be reused in a branch"""
229
290
 
230
291
    def test_commit_move(self):
231
292
        """Test commit of revisions with moved files and directories"""
232
 
        eq = self.assertEquals
 
293
        eq = self.assertEqual
233
294
        wt = self.make_branch_and_tree('.')
234
295
        b = wt.branch
235
296
        r1 = 'test@rev-1'
241
302
        wt.commit('two', rev_id=r2, allow_pointless=False)
242
303
        wt.lock_read()
243
304
        try:
244
 
            self.check_inventory_shape(wt.read_working_inventory(),
245
 
                                       ['a/', 'a/hello', 'b/'])
 
305
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
246
306
        finally:
247
307
            wt.unlock()
248
308
 
251
311
        wt.commit('three', rev_id=r3, allow_pointless=False)
252
312
        wt.lock_read()
253
313
        try:
254
 
            self.check_inventory_shape(wt.read_working_inventory(),
 
314
            self.check_tree_shape(wt,
255
315
                                       ['a/', 'a/hello', 'a/b/'])
256
 
            self.check_inventory_shape(b.repository.get_revision_inventory(r3),
 
316
            self.check_tree_shape(b.repository.revision_tree(r3),
257
317
                                       ['a/', 'a/hello', 'a/b/'])
258
318
        finally:
259
319
            wt.unlock()
263
323
        wt.commit('four', rev_id=r4, allow_pointless=False)
264
324
        wt.lock_read()
265
325
        try:
266
 
            self.check_inventory_shape(wt.read_working_inventory(),
267
 
                                       ['a/', 'a/b/hello', 'a/b/'])
 
326
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
268
327
        finally:
269
328
            wt.unlock()
270
329
 
271
 
        inv = b.repository.get_revision_inventory(r4)
 
330
        inv = b.repository.get_inventory(r4)
272
331
        eq(inv['hello-id'].revision, r4)
273
332
        eq(inv['a-id'].revision, r1)
274
333
        eq(inv['b-id'].revision, r3)
277
336
        """Commit with a removed file"""
278
337
        wt = self.make_branch_and_tree('.')
279
338
        b = wt.branch
280
 
        file('hello', 'w').write('hello world')
 
339
        with file('hello', 'w') as f: f.write('hello world')
281
340
        wt.add(['hello'], ['hello-id'])
282
341
        wt.commit(message='add hello')
283
342
        wt.remove('hello')
292
351
        b = wt.branch
293
352
        rev_ids = []
294
353
        for i in range(4):
295
 
            file('hello', 'w').write((str(i) * 4) + '\n')
 
354
            with file('hello', 'w') as f: f.write((str(i) * 4) + '\n')
296
355
            if i == 0:
297
356
                wt.add(['hello'], ['hello-id'])
298
357
            rev_id = 'test@rev-%d' % (i+1)
299
358
            rev_ids.append(rev_id)
300
359
            wt.commit(message='rev %d' % (i+1),
301
360
                     rev_id=rev_id)
302
 
        eq = self.assertEquals
303
 
        eq(b.revision_history(), rev_ids)
304
361
        for i in range(4):
305
 
            anc = b.repository.get_ancestry(rev_ids[i])
306
 
            eq(anc, [None] + rev_ids[:i+1])
 
362
            self.assertThat(rev_ids[:i+1],
 
363
                MatchesAncestry(b.repository, rev_ids[i]))
307
364
 
308
365
    def test_commit_new_subdir_child_selective(self):
309
366
        wt = self.make_branch_and_tree('.')
323
380
        from bzrlib.errors import StrictCommitFailed
324
381
        wt = self.make_branch_and_tree('.')
325
382
        b = wt.branch
326
 
        file('hello', 'w').write('hello world')
 
383
        with file('hello', 'w') as f: f.write('hello world')
327
384
        wt.add('hello')
328
 
        file('goodbye', 'w').write('goodbye cruel world!')
 
385
        with file('goodbye', 'w') as f: f.write('goodbye cruel world!')
329
386
        self.assertRaises(StrictCommitFailed, wt.commit,
330
387
            message='add hello but not goodbye', strict=True)
331
388
 
332
389
    def test_strict_commit_without_unknowns(self):
333
390
        """Try and commit with no unknown files and strict = True,
334
391
        should work."""
335
 
        from bzrlib.errors import StrictCommitFailed
336
392
        wt = self.make_branch_and_tree('.')
337
393
        b = wt.branch
338
 
        file('hello', 'w').write('hello world')
 
394
        with file('hello', 'w') as f: f.write('hello world')
339
395
        wt.add('hello')
340
396
        wt.commit(message='add hello', strict=True)
341
397
 
343
399
        """Try and commit with unknown files and strict = False, should work."""
344
400
        wt = self.make_branch_and_tree('.')
345
401
        b = wt.branch
346
 
        file('hello', 'w').write('hello world')
 
402
        with file('hello', 'w') as f: f.write('hello world')
347
403
        wt.add('hello')
348
 
        file('goodbye', 'w').write('goodbye cruel world!')
 
404
        with file('goodbye', 'w') as f: f.write('goodbye cruel world!')
349
405
        wt.commit(message='add hello but not goodbye', strict=False)
350
406
 
351
407
    def test_nonstrict_commit_without_unknowns(self):
353
409
        should work."""
354
410
        wt = self.make_branch_and_tree('.')
355
411
        b = wt.branch
356
 
        file('hello', 'w').write('hello world')
 
412
        with file('hello', 'w') as f: f.write('hello world')
357
413
        wt.add('hello')
358
414
        wt.commit(message='add hello', strict=False)
359
415
 
364
420
        wt = self.make_branch_and_tree('.')
365
421
        branch = wt.branch
366
422
        wt.commit("base", allow_pointless=True, rev_id='A')
367
 
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
 
423
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
368
424
        try:
369
425
            from bzrlib.testament import Testament
370
426
            # monkey patch gpg signing mechanism
371
427
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
372
 
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
373
 
                                                      allow_pointless=True,
374
 
                                                      rev_id='B',
375
 
                                                      working_tree=wt)
 
428
            conf = config.MemoryStack('''
 
429
gpg_signing_command=cat -
 
430
create_signatures=always
 
431
''')
 
432
            commit.Commit(config_stack=conf).commit(
 
433
                message="base", allow_pointless=True, rev_id='B',
 
434
                working_tree=wt)
376
435
            def sign(text):
377
436
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
378
437
            self.assertEqual(sign(Testament.from_revision(branch.repository,
379
 
                             'B').as_short_text()),
 
438
                                                          'B').as_short_text()),
380
439
                             branch.repository.get_signature_text('B'))
381
440
        finally:
382
441
            bzrlib.gpg.GPGStrategy = oldstrategy
388
447
        wt = self.make_branch_and_tree('.')
389
448
        branch = wt.branch
390
449
        wt.commit("base", allow_pointless=True, rev_id='A')
391
 
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
 
450
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
392
451
        try:
393
 
            from bzrlib.testament import Testament
394
452
            # monkey patch gpg signing mechanism
395
453
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
396
 
            config = MustSignConfig(branch)
 
454
            conf = config.MemoryStack('''
 
455
gpg_signing_command=cat -
 
456
create_signatures=always
 
457
''')
397
458
            self.assertRaises(SigningFailed,
398
 
                              commit.Commit(config=config).commit,
 
459
                              commit.Commit(config_stack=conf).commit,
399
460
                              message="base",
400
461
                              allow_pointless=True,
401
462
                              rev_id='B',
402
463
                              working_tree=wt)
403
464
            branch = Branch.open(self.get_url('.'))
404
 
            self.assertEqual(branch.revision_history(), ['A'])
405
 
            self.failIf(branch.repository.has_revision('B'))
 
465
            self.assertEqual(branch.last_revision(), 'A')
 
466
            self.assertFalse(branch.repository.has_revision('B'))
406
467
        finally:
407
468
            bzrlib.gpg.GPGStrategy = oldstrategy
408
469
 
415
476
            calls.append('called')
416
477
        bzrlib.ahook = called
417
478
        try:
418
 
            config = BranchWithHooks(branch)
419
 
            commit.Commit(config=config).commit(
420
 
                            message = "base",
421
 
                            allow_pointless=True,
422
 
                            rev_id='A', working_tree = wt)
 
479
            conf = config.MemoryStack('post_commit=bzrlib.ahook bzrlib.ahook')
 
480
            commit.Commit(config_stack=conf).commit(
 
481
                message = "base", allow_pointless=True, rev_id='A',
 
482
                working_tree = wt)
423
483
            self.assertEqual(['called', 'called'], calls)
424
484
        finally:
425
485
            del bzrlib.ahook
429
489
        wt = self.make_branch_and_tree('.')
430
490
        c = Commit()
431
491
        c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
432
 
        self.assertEquals(wt.branch.revno(), 1)
 
492
        self.assertEqual(wt.branch.revno(), 1)
433
493
        self.assertEqual({},
434
494
                         wt.branch.repository.get_revision(
435
495
                            wt.branch.last_revision()).properties)
443
503
        bound = master.sprout('bound')
444
504
        wt = bound.open_workingtree()
445
505
        wt.branch.set_bound_location(os.path.realpath('master'))
446
 
 
447
 
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
448
506
        master_branch.lock_write()
449
507
        try:
450
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
451
508
            self.assertRaises(LockContention, wt.commit, 'silly')
452
509
        finally:
453
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
454
510
            master_branch.unlock()
455
511
 
456
512
    def test_commit_bound_merge(self):
467
523
        other_bzrdir = master_branch.bzrdir.sprout('other')
468
524
        other_tree = other_bzrdir.open_workingtree()
469
525
 
470
 
        # 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
471
527
        # that our commit after merging will have a merged revision in the
472
528
        # content file history.
473
529
        self.build_tree_contents([('other/content_file', 'change in other\n')])
484
540
        bound_tree.commit(message='commit of merge in bound tree')
485
541
 
486
542
    def test_commit_reporting_after_merge(self):
487
 
        # 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
488
544
        # be called for each item that is added/removed/deleted.
489
545
        this_tree = self.make_branch_and_tree('this')
490
546
        # we need a bunch of files and dirs, to perform one action on each.
533
589
        this_tree.merge_from_branch(other_tree.branch)
534
590
        reporter = CapturingReporter()
535
591
        this_tree.commit('do the commit', reporter=reporter)
536
 
        self.assertEqual([
537
 
            ('change', 'unchanged', ''),
538
 
            ('change', 'unchanged', 'dirtoleave'),
539
 
            ('change', 'unchanged', 'filetoleave'),
 
592
        expected = set([
540
593
            ('change', 'modified', 'filetomodify'),
541
594
            ('change', 'added', 'newdir'),
542
595
            ('change', 'added', 'newfile'),
546
599
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
547
600
            ('deleted', 'dirtoremove'),
548
601
            ('deleted', 'filetoremove'),
549
 
            ],
550
 
            reporter.calls)
 
602
            ])
 
603
        result = set(reporter.calls)
 
604
        missing = expected - result
 
605
        new = result - expected
 
606
        self.assertEqual((set(), set()), (missing, new))
551
607
 
552
608
    def test_commit_removals_respects_filespec(self):
553
609
        """Commit respects the specified_files for removals."""
643
699
    def test_commit_unversioned_specified(self):
644
700
        """Commit should raise if specified files isn't in basis or worktree"""
645
701
        tree = self.make_branch_and_tree('.')
646
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
 
702
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
647
703
                          'message', specific_files=['bogus'])
648
704
 
649
705
    class Callback(object):
650
 
        
 
706
 
651
707
        def __init__(self, message, testcase):
652
708
            self.called = False
653
709
            self.message = message
681
737
        """Callback should not be invoked for pointless commit"""
682
738
        tree = self.make_branch_and_tree('.')
683
739
        cb = self.Callback(u'commit 2', self)
684
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
 
740
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
685
741
                          allow_pointless=False)
686
742
        self.assertFalse(cb.called)
687
743
 
691
747
        cb = self.Callback(u'commit 2', self)
692
748
        repository = tree.branch.repository
693
749
        # simulate network failure
694
 
        def raise_(self, arg, arg2):
 
750
        def raise_(self, arg, arg2, arg3=None, arg4=None):
695
751
            raise errors.NoSuchFile('foo')
696
752
        repository.add_inventory = raise_
 
753
        repository.add_inventory_by_delta = raise_
697
754
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
698
755
        self.assertFalse(cb.called)
699
756
 
721
778
        tree.add('a/c/d')
722
779
        tree.rename_one('a/z/x', 'a/c/d/x')
723
780
        tree.commit('test', specific_files=['a/z/y'])
724
 
 
 
781
 
725
782
    def test_commit_no_author(self):
726
783
        """The default kwarg author in MutableTree.commit should not add
727
784
        the 'author' revision property.
730
787
        rev_id = tree.commit('commit 1')
731
788
        rev = tree.branch.repository.get_revision(rev_id)
732
789
        self.assertFalse('author' in rev.properties)
 
790
        self.assertFalse('authors' in rev.properties)
733
791
 
734
792
    def test_commit_author(self):
735
793
        """Passing a non-empty author kwarg to MutableTree.commit should add
736
794
        the 'author' revision property.
737
795
        """
738
796
        tree = self.make_branch_and_tree('foo')
739
 
        rev_id = tree.commit('commit 1', author='John Doe <jdoe@example.com>')
 
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>')
740
800
        rev = tree.branch.repository.get_revision(rev_id)
741
801
        self.assertEqual('John Doe <jdoe@example.com>',
742
 
                         rev.properties['author'])
 
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 = controldir.ControlDir.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'))