~bzr-pqm/bzr/bzr.dev

5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2005-2011 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1246 by Martin Pool
- add very simple commit tests
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1246 by Martin Pool
- add very simple commit tests
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1246 by Martin Pool
- add very simple commit tests
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1246 by Martin Pool
- add very simple commit tests
16
17
18
import os
19
1472 by Robert Collins
post commit hook, first pass implementation
20
import bzrlib
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
21
from bzrlib import (
3113.6.7 by Aaron Bentley
Fix commit for a checkout sharing a repo with its branch (abentley, #177592)
22
    bzrdir,
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
23
    errors,
24
    )
1246 by Martin Pool
- add very simple commit tests
25
from bzrlib.branch import Branch
5579.3.1 by Jelmer Vernooij
Remove unused imports.
26
from bzrlib.bzrdir import BzrDirMetaFormat1
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
27
from bzrlib.commit import Commit, NullCommitReporter
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
28
from bzrlib.config import BranchConfig
5972.3.15 by Jelmer Vernooij
Use matchers.
29
from bzrlib.errors import (
30
    PointlessCommit,
31
    BzrError,
32
    SigningFailed,
33
    LockContention,
34
    )
5777.6.5 by Jelmer Vernooij
Add tests for lossy commit.
35
from bzrlib.tests import (
36
    TestCaseWithTransport,
37
    test_foreign,
38
    )
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
39
from bzrlib.tests.features import (
40
    SymlinkFeature,
41
    )
5972.3.15 by Jelmer Vernooij
Use matchers.
42
from bzrlib.tests.matchers import MatchesAncestry
1246 by Martin Pool
- add very simple commit tests
43
44
1257 by Martin Pool
doc
45
# TODO: Test commit with some added, and added-but-missing files
46
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
47
class MustSignConfig(BranchConfig):
48
49
    def signature_needed(self):
50
        return True
51
52
    def gpg_signing_command(self):
53
        return ['cat', '-']
54
55
1472 by Robert Collins
post commit hook, first pass implementation
56
class BranchWithHooks(BranchConfig):
57
58
    def post_commit(self):
59
        return "bzrlib.ahook bzrlib.ahook"
60
61
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
62
class CapturingReporter(NullCommitReporter):
63
    """This reporter captures the calls made to it for evaluation later."""
64
65
    def __init__(self):
66
        # a list of the calls this received
67
        self.calls = []
68
69
    def snapshot_change(self, change, path):
70
        self.calls.append(('change', change, path))
71
72
    def deleted(self, file_id):
73
        self.calls.append(('deleted', file_id))
74
75
    def missing(self, path):
76
        self.calls.append(('missing', path))
77
78
    def renamed(self, change, old_path, new_path):
79
        self.calls.append(('renamed', change, old_path, new_path))
80
2789.2.1 by Ian Clatworthy
Make commit less verbose by default
81
    def is_verbose(self):
82
        return True
83
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
84
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
85
class TestCommit(TestCaseWithTransport):
1390 by Robert Collins
pair programming worx... merge integration and weave
86
1246 by Martin Pool
- add very simple commit tests
87
    def test_simple_commit(self):
88
        """Commit and check two versions of a single file."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
89
        wt = self.make_branch_and_tree('.')
90
        b = wt.branch
1246 by Martin Pool
- add very simple commit tests
91
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
92
        wt.add('hello')
93
        wt.commit(message='add hello')
94
        file_id = wt.path2id('hello')
1246 by Martin Pool
- add very simple commit tests
95
96
        file('hello', 'w').write('version 2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
97
        wt.commit(message='commit 2')
1246 by Martin Pool
- add very simple commit tests
98
99
        eq = self.assertEquals
100
        eq(b.revno(), 2)
101
        rh = b.revision_history()
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
102
        rev = b.repository.get_revision(rh[0])
1246 by Martin Pool
- add very simple commit tests
103
        eq(rev.message, 'add hello')
104
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
105
        tree1 = b.repository.revision_tree(rh[0])
3010.1.3 by Robert Collins
Lock RevisionTrees correctly in commit tests.
106
        tree1.lock_read()
1246 by Martin Pool
- add very simple commit tests
107
        text = tree1.get_file_text(file_id)
3010.1.3 by Robert Collins
Lock RevisionTrees correctly in commit tests.
108
        tree1.unlock()
109
        self.assertEqual('hello world', text)
1246 by Martin Pool
- add very simple commit tests
110
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
111
        tree2 = b.repository.revision_tree(rh[1])
3010.1.3 by Robert Collins
Lock RevisionTrees correctly in commit tests.
112
        tree2.lock_read()
113
        text = tree2.get_file_text(file_id)
114
        tree2.unlock()
115
        self.assertEqual('version 2', text)
1246 by Martin Pool
- add very simple commit tests
116
5777.6.5 by Jelmer Vernooij
Add tests for lossy commit.
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."""
5777.6.6 by Jelmer Vernooij
Add lossy tests.
128
        test_foreign.register_dummy_foreign_for_test(self)
5777.6.5 by Jelmer Vernooij
Add tests for lossy commit.
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')
5777.6.6 by Jelmer Vernooij
Add lossy tests.
134
        revid = wt.commit(message='add hello', lossy=True,
135
            timestamp=1302659388, timezone=0)
136
        self.assertEquals('dummy-v1:1302659388.0-0-UNKNOWN', revid)
5777.6.5 by Jelmer Vernooij
Add tests for lossy commit.
137
5777.7.5 by Jelmer Vernooij
Add tests for committing to a branch bound to a foreign branch.
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
4183.5.5 by Robert Collins
Enable record_iter_changes for cases where it can work.
155
    def test_missing_commit(self):
156
        """Test a commit with a missing file"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
157
        wt = self.make_branch_and_tree('.')
158
        b = wt.branch
1247 by Martin Pool
- tests for deletion and removal of files in commits
159
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
160
        wt.add(['hello'], ['hello-id'])
161
        wt.commit(message='add hello')
1247 by Martin Pool
- tests for deletion and removal of files in commits
162
163
        os.remove('hello')
6125.1.1 by Jelmer Vernooij
Report missing files as removed in 'bzr commit', rather than modified.
164
        reporter = CapturingReporter()
165
        wt.commit('removed hello', rev_id='rev2', reporter=reporter)
166
        self.assertEquals(
167
            [('missing', u'hello'), ('deleted', u'hello')],
168
            reporter.calls)
1247 by Martin Pool
- tests for deletion and removal of files in commits
169
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
170
        tree = b.repository.revision_tree('rev2')
1247 by Martin Pool
- tests for deletion and removal of files in commits
171
        self.assertFalse(tree.has_id('hello-id'))
172
2258.4.1 by Jelmer Vernooij
Add test that demonstrates a corner case bug in commit.
173
    def test_partial_commit_move(self):
3373.4.1 by John Arbash Meinel
Merge in and clean up the test for bug #83039.
174
        """Test a partial commit where a file was renamed but not committed.
175
176
        https://bugs.launchpad.net/bzr/+bug/83039
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
177
2258.4.1 by Jelmer Vernooij
Add test that demonstrates a corner case bug in commit.
178
        If not handled properly, commit will try to snapshot
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
179
        dialog.py with olive/ as a parent, while
2258.4.1 by Jelmer Vernooij
Add test that demonstrates a corner case bug in commit.
180
        olive/ has not been snapshotted yet.
181
        """
182
        wt = self.make_branch_and_tree('.')
183
        b = wt.branch
3373.4.1 by John Arbash Meinel
Merge in and clean up the test for bug #83039.
184
        self.build_tree(['annotate/', 'annotate/foo.py',
185
                         'olive/', 'olive/dialog.py'
186
                        ])
2258.4.1 by Jelmer Vernooij
Add test that demonstrates a corner case bug in commit.
187
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
188
        wt.commit(message='add files')
3373.4.1 by John Arbash Meinel
Merge in and clean up the test for bug #83039.
189
        wt.rename_one("olive/dialog.py", "aaa")
190
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
2258.4.1 by Jelmer Vernooij
Add test that demonstrates a corner case bug in commit.
191
        wt.commit('renamed hello', specific_files=["annotate"])
192
1253 by Martin Pool
- test that pointless commits are trapped
193
    def test_pointless_commit(self):
194
        """Commit refuses unless there are changes or it's forced."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
195
        wt = self.make_branch_and_tree('.')
196
        b = wt.branch
1253 by Martin Pool
- test that pointless commits are trapped
197
        file('hello', 'w').write('hello')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
198
        wt.add(['hello'])
199
        wt.commit(message='add hello')
1253 by Martin Pool
- test that pointless commits are trapped
200
        self.assertEquals(b.revno(), 1)
201
        self.assertRaises(PointlessCommit,
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
202
                          wt.commit,
1253 by Martin Pool
- test that pointless commits are trapped
203
                          message='fails',
204
                          allow_pointless=False)
205
        self.assertEquals(b.revno(), 1)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
206
1252 by Martin Pool
- add test for commit of an empty tree
207
    def test_commit_empty(self):
1253 by Martin Pool
- test that pointless commits are trapped
208
        """Commiting an empty tree works."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
209
        wt = self.make_branch_and_tree('.')
210
        b = wt.branch
211
        wt.commit(message='empty tree', allow_pointless=True)
1253 by Martin Pool
- test that pointless commits are trapped
212
        self.assertRaises(PointlessCommit,
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
213
                          wt.commit,
1253 by Martin Pool
- test that pointless commits are trapped
214
                          message='empty tree',
215
                          allow_pointless=False)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
216
        wt.commit(message='empty tree', allow_pointless=True)
1252 by Martin Pool
- add test for commit of an empty tree
217
        self.assertEquals(b.revno(), 2)
218
219
    def test_selective_delete(self):
220
        """Selective commit in tree with deletions"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
221
        wt = self.make_branch_and_tree('.')
222
        b = wt.branch
1254 by Martin Pool
- fix handling of selective commit with deleted files
223
        file('hello', 'w').write('hello')
224
        file('buongia', 'w').write('buongia')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
225
        wt.add(['hello', 'buongia'],
1255 by Martin Pool
- more tests for selective commit of deletion
226
              ['hello-id', 'buongia-id'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
227
        wt.commit(message='add files',
1255 by Martin Pool
- more tests for selective commit of deletion
228
                 rev_id='test@rev-1')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
229
1254 by Martin Pool
- fix handling of selective commit with deleted files
230
        os.remove('hello')
231
        file('buongia', 'w').write('new text')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
232
        wt.commit(message='update text',
1254 by Martin Pool
- fix handling of selective commit with deleted files
233
                 specific_files=['buongia'],
1255 by Martin Pool
- more tests for selective commit of deletion
234
                 allow_pointless=False,
235
                 rev_id='test@rev-2')
1254 by Martin Pool
- fix handling of selective commit with deleted files
236
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
237
        wt.commit(message='remove hello',
1254 by Martin Pool
- fix handling of selective commit with deleted files
238
                 specific_files=['hello'],
1255 by Martin Pool
- more tests for selective commit of deletion
239
                 allow_pointless=False,
240
                 rev_id='test@rev-3')
1254 by Martin Pool
- fix handling of selective commit with deleted files
241
242
        eq = self.assertEquals
243
        eq(b.revno(), 3)
1255 by Martin Pool
- more tests for selective commit of deletion
244
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
245
        tree2 = b.repository.revision_tree('test@rev-2')
3010.1.3 by Robert Collins
Lock RevisionTrees correctly in commit tests.
246
        tree2.lock_read()
247
        self.addCleanup(tree2.unlock)
1255 by Martin Pool
- more tests for selective commit of deletion
248
        self.assertTrue(tree2.has_filename('hello'))
249
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
250
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
251
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
252
        tree3 = b.repository.revision_tree('test@rev-3')
3010.1.3 by Robert Collins
Lock RevisionTrees correctly in commit tests.
253
        tree3.lock_read()
254
        self.addCleanup(tree3.unlock)
1255 by Martin Pool
- more tests for selective commit of deletion
255
        self.assertFalse(tree3.has_filename('hello'))
256
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
257
258
    def test_commit_rename(self):
259
        """Test commit of a revision where a file is renamed."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
260
        tree = self.make_branch_and_tree('.')
261
        b = tree.branch
1185.38.7 by John Arbash Meinel
Updated build_tree to use fixed line-endings for tests which read the file contents and compare
262
        self.build_tree(['hello'], line_endings='binary')
1508.1.7 by Robert Collins
Move rename_one from Branch to WorkingTree. (Robert Collins).
263
        tree.add(['hello'], ['hello-id'])
264
        tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
265
1508.1.7 by Robert Collins
Move rename_one from Branch to WorkingTree. (Robert Collins).
266
        tree.rename_one('hello', 'fruity')
267
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
268
1303 by Martin Pool
- commit updates entry_version
269
        eq = self.assertEquals
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
270
        tree1 = b.repository.revision_tree('test@rev-1')
3010.1.3 by Robert Collins
Lock RevisionTrees correctly in commit tests.
271
        tree1.lock_read()
272
        self.addCleanup(tree1.unlock)
1303 by Martin Pool
- commit updates entry_version
273
        eq(tree1.id2path('hello-id'), 'hello')
274
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
275
        self.assertFalse(tree1.has_filename('fruity'))
5807.1.5 by Jelmer Vernooij
Fix more things to use tree objects.
276
        self.check_tree_shape(tree1, ['hello'])
277
        eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
278
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
279
        tree2 = b.repository.revision_tree('test@rev-2')
3010.1.3 by Robert Collins
Lock RevisionTrees correctly in commit tests.
280
        tree2.lock_read()
281
        self.addCleanup(tree2.unlock)
1303 by Martin Pool
- commit updates entry_version
282
        eq(tree2.id2path('hello-id'), 'fruity')
283
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
5807.1.5 by Jelmer Vernooij
Fix more things to use tree objects.
284
        self.check_tree_shape(tree2, ['fruity'])
285
        eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
1291 by Martin Pool
- add test for moving files between directories
286
287
    def test_reused_rev_id(self):
1292 by Martin Pool
- add check that revision ids cannot be committed twice
288
        """Test that a revision id cannot be reused in a branch"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
289
        wt = self.make_branch_and_tree('.')
290
        b = wt.branch
291
        wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
1292 by Martin Pool
- add check that revision ids cannot be committed twice
292
        self.assertRaises(Exception,
1534.4.35 by Robert Collins
Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()
293
                          wt.commit,
1292 by Martin Pool
- add check that revision ids cannot be committed twice
294
                          message='reused id',
295
                          rev_id='test@rev-1',
296
                          allow_pointless=True)
1291 by Martin Pool
- add test for moving files between directories
297
298
    def test_commit_move(self):
299
        """Test commit of revisions with moved files and directories"""
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
300
        eq = self.assertEquals
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
301
        wt = self.make_branch_and_tree('.')
302
        b = wt.branch
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
303
        r1 = 'test@rev-1'
1291 by Martin Pool
- add test for moving files between directories
304
        self.build_tree(['hello', 'a/', 'b/'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
305
        wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
306
        wt.commit('initial', rev_id=r1, allow_pointless=False)
307
        wt.move(['hello'], 'a')
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
308
        r2 = 'test@rev-2'
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
309
        wt.commit('two', rev_id=r2, allow_pointless=False)
2255.2.136 by John Arbash Meinel
(James Westby) add read locks around read_working_inventory() in test_commit_move
310
        wt.lock_read()
311
        try:
5807.1.5 by Jelmer Vernooij
Fix more things to use tree objects.
312
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
2255.2.136 by John Arbash Meinel
(James Westby) add read locks around read_working_inventory() in test_commit_move
313
        finally:
314
            wt.unlock()
1291 by Martin Pool
- add test for moving files between directories
315
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
316
        wt.move(['b'], 'a')
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
317
        r3 = 'test@rev-3'
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
318
        wt.commit('three', rev_id=r3, allow_pointless=False)
2255.2.136 by John Arbash Meinel
(James Westby) add read locks around read_working_inventory() in test_commit_move
319
        wt.lock_read()
320
        try:
5807.1.5 by Jelmer Vernooij
Fix more things to use tree objects.
321
            self.check_tree_shape(wt,
2545.3.2 by James Westby
Add a test for check_inventory_shape.
322
                                       ['a/', 'a/hello', 'a/b/'])
5807.1.5 by Jelmer Vernooij
Fix more things to use tree objects.
323
            self.check_tree_shape(b.repository.revision_tree(r3),
2545.3.2 by James Westby
Add a test for check_inventory_shape.
324
                                       ['a/', 'a/hello', 'a/b/'])
2255.2.136 by John Arbash Meinel
(James Westby) add read locks around read_working_inventory() in test_commit_move
325
        finally:
326
            wt.unlock()
1291 by Martin Pool
- add test for moving files between directories
327
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
328
        wt.move(['a/hello'], 'a/b')
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
329
        r4 = 'test@rev-4'
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
330
        wt.commit('four', rev_id=r4, allow_pointless=False)
2255.2.136 by John Arbash Meinel
(James Westby) add read locks around read_working_inventory() in test_commit_move
331
        wt.lock_read()
332
        try:
5807.1.5 by Jelmer Vernooij
Fix more things to use tree objects.
333
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
2255.2.136 by John Arbash Meinel
(James Westby) add read locks around read_working_inventory() in test_commit_move
334
        finally:
335
            wt.unlock()
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
336
5035.3.1 by Jelmer Vernooij
Remove Repository.get_revision_inventory.
337
        inv = b.repository.get_inventory(r4)
1092.2.21 by Robert Collins
convert name_version to revision in inventory entries
338
        eq(inv['hello-id'].revision, r4)
339
        eq(inv['a-id'].revision, r1)
340
        eq(inv['b-id'].revision, r3)
2255.2.136 by John Arbash Meinel
(James Westby) add read locks around read_working_inventory() in test_commit_move
341
1246 by Martin Pool
- add very simple commit tests
342
    def test_removed_commit(self):
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
343
        """Commit with a removed file"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
344
        wt = self.make_branch_and_tree('.')
345
        b = wt.branch
1247 by Martin Pool
- tests for deletion and removal of files in commits
346
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
347
        wt.add(['hello'], ['hello-id'])
348
        wt.commit(message='add hello')
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
349
        wt.remove('hello')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
350
        wt.commit('removed hello', rev_id='rev2')
1247 by Martin Pool
- tests for deletion and removal of files in commits
351
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
352
        tree = b.repository.revision_tree('rev2')
1247 by Martin Pool
- tests for deletion and removal of files in commits
353
        self.assertFalse(tree.has_id('hello-id'))
1246 by Martin Pool
- add very simple commit tests
354
1256 by Martin Pool
- test that commits append to the tree's ancestry
355
    def test_committed_ancestry(self):
356
        """Test commit appends revisions to ancestry."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
357
        wt = self.make_branch_and_tree('.')
358
        b = wt.branch
1256 by Martin Pool
- test that commits append to the tree's ancestry
359
        rev_ids = []
360
        for i in range(4):
361
            file('hello', 'w').write((str(i) * 4) + '\n')
362
            if i == 0:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
363
                wt.add(['hello'], ['hello-id'])
1256 by Martin Pool
- test that commits append to the tree's ancestry
364
            rev_id = 'test@rev-%d' % (i+1)
365
            rev_ids.append(rev_id)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
366
            wt.commit(message='rev %d' % (i+1),
1256 by Martin Pool
- test that commits append to the tree's ancestry
367
                     rev_id=rev_id)
368
        eq = self.assertEquals
369
        eq(b.revision_history(), rev_ids)
370
        for i in range(4):
5972.3.15 by Jelmer Vernooij
Use matchers.
371
            self.assertThat(rev_ids[:i+1],
372
                MatchesAncestry(b.repository, rev_ids[i]))
1416 by Robert Collins
when committing a specific file, include all its parents
373
374
    def test_commit_new_subdir_child_selective(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
375
        wt = self.make_branch_and_tree('.')
376
        b = wt.branch
1416 by Robert Collins
when committing a specific file, include all its parents
377
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
378
        wt.add(['dir', 'dir/file1', 'dir/file2'],
1416 by Robert Collins
when committing a specific file, include all its parents
379
              ['dirid', 'file1id', 'file2id'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
380
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
381
        inv = b.repository.get_inventory('1')
1416 by Robert Collins
when committing a specific file, include all its parents
382
        self.assertEqual('1', inv['dirid'].revision)
383
        self.assertEqual('1', inv['file1id'].revision)
384
        # FIXME: This should raise a KeyError I think, rbc20051006
385
        self.assertRaises(BzrError, inv.__getitem__, 'file2id')
1185.16.65 by mbp at sourcefrog
- new commit --strict option
386
387
    def test_strict_commit(self):
388
        """Try and commit with unknown files and strict = True, should fail."""
389
        from bzrlib.errors import StrictCommitFailed
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
390
        wt = self.make_branch_and_tree('.')
391
        b = wt.branch
1185.16.65 by mbp at sourcefrog
- new commit --strict option
392
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
393
        wt.add('hello')
1185.16.65 by mbp at sourcefrog
- new commit --strict option
394
        file('goodbye', 'w').write('goodbye cruel world!')
1534.4.35 by Robert Collins
Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()
395
        self.assertRaises(StrictCommitFailed, wt.commit,
1185.16.65 by mbp at sourcefrog
- new commit --strict option
396
            message='add hello but not goodbye', strict=True)
397
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
398
    def test_strict_commit_without_unknowns(self):
399
        """Try and commit with no unknown files and strict = True,
400
        should work."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
401
        wt = self.make_branch_and_tree('.')
402
        b = wt.branch
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
403
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
404
        wt.add('hello')
405
        wt.commit(message='add hello', strict=True)
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
406
1185.16.65 by mbp at sourcefrog
- new commit --strict option
407
    def test_nonstrict_commit(self):
408
        """Try and commit with unknown files and strict = False, should work."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
409
        wt = self.make_branch_and_tree('.')
410
        b = wt.branch
1185.16.65 by mbp at sourcefrog
- new commit --strict option
411
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
412
        wt.add('hello')
1185.16.65 by mbp at sourcefrog
- new commit --strict option
413
        file('goodbye', 'w').write('goodbye cruel world!')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
414
        wt.commit(message='add hello but not goodbye', strict=False)
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
415
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
416
    def test_nonstrict_commit_without_unknowns(self):
417
        """Try and commit with no unknown files and strict = False,
418
        should work."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
419
        wt = self.make_branch_and_tree('.')
420
        b = wt.branch
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
421
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
422
        wt.add('hello')
423
        wt.commit(message='add hello', strict=False)
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
424
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
425
    def test_signed_commit(self):
426
        import bzrlib.gpg
427
        import bzrlib.commit as commit
428
        oldstrategy = bzrlib.gpg.GPGStrategy
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
429
        wt = self.make_branch_and_tree('.')
430
        branch = wt.branch
431
        wt.commit("base", allow_pointless=True, rev_id='A')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
432
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
433
        try:
434
            from bzrlib.testament import Testament
435
            # monkey patch gpg signing mechanism
436
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
2149.1.3 by Aaron Bentley
Updates from review comments
437
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
438
                                                      allow_pointless=True,
439
                                                      rev_id='B',
440
                                                      working_tree=wt)
1551.12.15 by Aaron Bentley
add header/trailer to fake clearsigned texts
441
            def sign(text):
442
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
443
            self.assertEqual(sign(Testament.from_revision(branch.repository,
444
                             'B').as_short_text()),
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
445
                             branch.repository.get_signature_text('B'))
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
446
        finally:
447
            bzrlib.gpg.GPGStrategy = oldstrategy
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
448
449
    def test_commit_failed_signature(self):
450
        import bzrlib.gpg
451
        import bzrlib.commit as commit
452
        oldstrategy = bzrlib.gpg.GPGStrategy
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
453
        wt = self.make_branch_and_tree('.')
454
        branch = wt.branch
455
        wt.commit("base", allow_pointless=True, rev_id='A')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
456
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
457
        try:
458
            # monkey patch gpg signing mechanism
459
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
460
            config = MustSignConfig(branch)
461
            self.assertRaises(SigningFailed,
462
                              commit.Commit(config=config).commit,
1534.4.34 by Robert Collins
Fix remaining uses of deprecated apis within bzrlib.
463
                              message="base",
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
464
                              allow_pointless=True,
1534.4.34 by Robert Collins
Fix remaining uses of deprecated apis within bzrlib.
465
                              rev_id='B',
466
                              working_tree=wt)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
467
            branch = Branch.open(self.get_url('.'))
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
468
            self.assertEqual(branch.revision_history(), ['A'])
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
469
            self.assertFalse(branch.repository.has_revision('B'))
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
470
        finally:
471
            bzrlib.gpg.GPGStrategy = oldstrategy
1472 by Robert Collins
post commit hook, first pass implementation
472
473
    def test_commit_invokes_hooks(self):
474
        import bzrlib.commit as commit
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
475
        wt = self.make_branch_and_tree('.')
476
        branch = wt.branch
1472 by Robert Collins
post commit hook, first pass implementation
477
        calls = []
478
        def called(branch, rev_id):
479
            calls.append('called')
480
        bzrlib.ahook = called
481
        try:
482
            config = BranchWithHooks(branch)
483
            commit.Commit(config=config).commit(
2149.1.3 by Aaron Bentley
Updates from review comments
484
                            message = "base",
1472 by Robert Collins
post commit hook, first pass implementation
485
                            allow_pointless=True,
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
486
                            rev_id='A', working_tree = wt)
1472 by Robert Collins
post commit hook, first pass implementation
487
            self.assertEqual(['called', 'called'], calls)
488
        finally:
489
            del bzrlib.ahook
1593.1.1 by Robert Collins
Move responsibility for setting branch nickname in commits to the WorkingTree convenience function.
490
491
    def test_commit_object_doesnt_set_nick(self):
492
        # using the Commit object directly does not set the branch nick.
493
        wt = self.make_branch_and_tree('.')
494
        c = Commit()
2149.1.3 by Aaron Bentley
Updates from review comments
495
        c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
1593.1.1 by Robert Collins
Move responsibility for setting branch nickname in commits to the WorkingTree convenience function.
496
        self.assertEquals(wt.branch.revno(), 1)
497
        self.assertEqual({},
498
                         wt.branch.repository.get_revision(
499
                            wt.branch.last_revision()).properties)
500
1614.1.1 by Aaron Bentley
Fixed master locking in commit
501
    def test_safe_master_lock(self):
502
        os.mkdir('master')
503
        master = BzrDirMetaFormat1().initialize('master')
504
        master.create_repository()
505
        master_branch = master.create_branch()
506
        master.create_workingtree()
507
        bound = master.sprout('bound')
508
        wt = bound.open_workingtree()
509
        wt.branch.set_bound_location(os.path.realpath('master'))
510
        master_branch.lock_write()
1658.1.5 by Martin Pool
Release more locks taken during test suite
511
        try:
512
            self.assertRaises(LockContention, wt.commit, 'silly')
513
        finally:
514
            master_branch.unlock()
1668.1.3 by Martin Pool
[patch] use the correct transaction when committing snapshot (Malone: #43959)
515
516
    def test_commit_bound_merge(self):
517
        # see bug #43959; commit of a merge in a bound branch fails to push
518
        # the new commit into the master
519
        master_branch = self.make_branch('master')
520
        bound_tree = self.make_branch_and_tree('bound')
521
        bound_tree.branch.bind(master_branch)
522
523
        self.build_tree_contents([('bound/content_file', 'initial contents\n')])
524
        bound_tree.add(['content_file'])
525
        bound_tree.commit(message='woo!')
526
527
        other_bzrdir = master_branch.bzrdir.sprout('other')
528
        other_tree = other_bzrdir.open_workingtree()
529
4775.1.1 by Martin Pool
Remove several 'the the' typos
530
        # do a commit to the other branch changing the content file so
1668.1.3 by Martin Pool
[patch] use the correct transaction when committing snapshot (Malone: #43959)
531
        # that our commit after merging will have a merged revision in the
532
        # content file history.
533
        self.build_tree_contents([('other/content_file', 'change in other\n')])
534
        other_tree.commit('change in other')
535
536
        # do a merge into the bound branch from other, and then change the
537
        # content file locally to force a new revision (rather than using the
538
        # revision from other). This forces extra processing in commit.
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
539
        bound_tree.merge_from_branch(other_tree.branch)
1668.1.3 by Martin Pool
[patch] use the correct transaction when committing snapshot (Malone: #43959)
540
        self.build_tree_contents([('bound/content_file', 'change in bound\n')])
541
542
        # before #34959 was fixed, this failed with 'revision not present in
543
        # weave' when trying to implicitly push from the bound branch to the master
544
        bound_tree.commit(message='commit of merge in bound tree')
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
545
546
    def test_commit_reporting_after_merge(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
547
        # when doing a commit of a merge, the reporter needs to still
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
548
        # be called for each item that is added/removed/deleted.
549
        this_tree = self.make_branch_and_tree('this')
550
        # we need a bunch of files and dirs, to perform one action on each.
551
        self.build_tree([
552
            'this/dirtorename/',
553
            'this/dirtoreparent/',
554
            'this/dirtoleave/',
555
            'this/dirtoremove/',
556
            'this/filetoreparent',
557
            'this/filetorename',
558
            'this/filetomodify',
559
            'this/filetoremove',
560
            'this/filetoleave']
561
            )
562
        this_tree.add([
563
            'dirtorename',
564
            'dirtoreparent',
565
            'dirtoleave',
566
            'dirtoremove',
567
            'filetoreparent',
568
            'filetorename',
569
            'filetomodify',
570
            'filetoremove',
571
            'filetoleave']
572
            )
573
        this_tree.commit('create_files')
574
        other_dir = this_tree.bzrdir.sprout('other')
575
        other_tree = other_dir.open_workingtree()
576
        other_tree.lock_write()
577
        # perform the needed actions on the files and dirs.
578
        try:
579
            other_tree.rename_one('dirtorename', 'renameddir')
580
            other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
581
            other_tree.rename_one('filetorename', 'renamedfile')
582
            other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
583
            other_tree.remove(['dirtoremove', 'filetoremove'])
584
            self.build_tree_contents([
585
                ('other/newdir/', ),
586
                ('other/filetomodify', 'new content'),
587
                ('other/newfile', 'new file content')])
588
            other_tree.add('newfile')
589
            other_tree.add('newdir/')
590
            other_tree.commit('modify all sample files and dirs.')
591
        finally:
592
            other_tree.unlock()
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
593
        this_tree.merge_from_branch(other_tree.branch)
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
594
        reporter = CapturingReporter()
595
        this_tree.commit('do the commit', reporter=reporter)
4183.5.5 by Robert Collins
Enable record_iter_changes for cases where it can work.
596
        expected = set([
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
597
            ('change', 'modified', 'filetomodify'),
598
            ('change', 'added', 'newdir'),
599
            ('change', 'added', 'newfile'),
600
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
2829.1.1 by Ian Clatworthy
re-apply Aaron's fix for #94975 (Ian Clatworthy)
601
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
602
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
603
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
604
            ('deleted', 'dirtoremove'),
605
            ('deleted', 'filetoremove'),
4183.5.5 by Robert Collins
Enable record_iter_changes for cases where it can work.
606
            ])
607
        result = set(reporter.calls)
608
        missing = expected - result
609
        new = result - expected
610
        self.assertEqual((set(), set()), (missing, new))
1551.7.24 by Aaron Bentley
Ensure commit respects file spec when committing removals
611
612
    def test_commit_removals_respects_filespec(self):
613
        """Commit respects the specified_files for removals."""
614
        tree = self.make_branch_and_tree('.')
615
        self.build_tree(['a', 'b'])
616
        tree.add(['a', 'b'])
617
        tree.commit('added a, b')
618
        tree.remove(['a', 'b'])
1906.1.1 by Robert Collins
(robertc) Trivial change to test_commit_removals_respects_filespec to be easir to read.
619
        tree.commit('removed a', specific_files='a')
2255.2.148 by John Arbash Meinel
lock a basis tree during a commit test.
620
        basis = tree.basis_tree()
621
        tree.lock_read()
622
        try:
623
            self.assertIs(None, basis.path2id('a'))
624
            self.assertFalse(basis.path2id('b') is None)
625
        finally:
626
            tree.unlock()
1864.2.1 by John Arbash Meinel
Commit timestamp restricted to 1ms precision.
627
628
    def test_commit_saves_1ms_timestamp(self):
629
        """Passing in a timestamp is saved with 1ms resolution"""
630
        tree = self.make_branch_and_tree('.')
631
        self.build_tree(['a'])
632
        tree.add('a')
633
        tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
634
                    rev_id='a1')
635
636
        rev = tree.branch.repository.get_revision('a1')
637
        self.assertEqual(1153248633.419, rev.timestamp)
638
639
    def test_commit_has_1ms_resolution(self):
640
        """Allowing commit to generate the timestamp also has 1ms resolution"""
641
        tree = self.make_branch_and_tree('.')
642
        self.build_tree(['a'])
643
        tree.add('a')
644
        tree.commit('added a', rev_id='a1')
645
646
        rev = tree.branch.repository.get_revision('a1')
647
        timestamp = rev.timestamp
648
        timestamp_1ms = round(timestamp, 3)
649
        self.assertEqual(timestamp_1ms, timestamp)
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
650
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
651
    def assertBasisTreeKind(self, kind, tree, file_id):
652
        basis = tree.basis_tree()
653
        basis.lock_read()
654
        try:
655
            self.assertEqual(kind, basis.kind(file_id))
656
        finally:
657
            basis.unlock()
658
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
659
    def test_commit_kind_changes(self):
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
660
        self.requireFeature(SymlinkFeature)
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
661
        tree = self.make_branch_and_tree('.')
662
        os.symlink('target', 'name')
663
        tree.add('name', 'a-file-id')
664
        tree.commit('Added a symlink')
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
665
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
666
667
        os.unlink('name')
668
        self.build_tree(['name'])
669
        tree.commit('Changed symlink to file')
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
670
        self.assertBasisTreeKind('file', tree, 'a-file-id')
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
671
672
        os.unlink('name')
673
        os.symlink('target', 'name')
674
        tree.commit('file to symlink')
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
675
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
676
677
        os.unlink('name')
678
        os.mkdir('name')
679
        tree.commit('symlink to directory')
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
680
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
681
682
        os.rmdir('name')
683
        os.symlink('target', 'name')
684
        tree.commit('directory to symlink')
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
685
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
686
687
        # prepare for directory <-> file tests
688
        os.unlink('name')
689
        os.mkdir('name')
690
        tree.commit('symlink to directory')
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
691
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
692
693
        os.rmdir('name')
694
        self.build_tree(['name'])
695
        tree.commit('Changed directory to file')
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
696
        self.assertBasisTreeKind('file', tree, 'a-file-id')
1959.4.1 by Aaron Bentley
Correctly handle all file kind changes
697
698
        os.unlink('name')
699
        os.mkdir('name')
700
        tree.commit('file to directory')
2255.2.135 by John Arbash Meinel
Add locking in the test_commit_kind_changes test.
701
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
1959.4.2 by Aaron Bentley
Merge bzr.dev
702
1551.8.29 by Aaron Bentley
Stop accepting non-existant files in commit (#50793)
703
    def test_commit_unversioned_specified(self):
704
        """Commit should raise if specified files isn't in basis or worktree"""
705
        tree = self.make_branch_and_tree('.')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
706
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
1551.8.29 by Aaron Bentley
Stop accepting non-existant files in commit (#50793)
707
                          'message', specific_files=['bogus'])
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
708
709
    class Callback(object):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
710
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
711
        def __init__(self, message, testcase):
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
712
            self.called = False
713
            self.message = message
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
714
            self.testcase = testcase
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
715
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
716
        def __call__(self, commit_obj):
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
717
            self.called = True
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
718
            self.testcase.assertTrue(isinstance(commit_obj, Commit))
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
719
            return self.message
720
721
    def test_commit_callback(self):
722
        """Commit should invoke a callback to get the message"""
723
724
        tree = self.make_branch_and_tree('.')
725
        try:
726
            tree.commit()
727
        except Exception, e:
728
            self.assertTrue(isinstance(e, BzrError))
2149.1.3 by Aaron Bentley
Updates from review comments
729
            self.assertEqual('The message or message_callback keyword'
730
                             ' parameter is required for commit().', str(e))
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
731
        else:
732
            self.fail('exception not raised')
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
733
        cb = self.Callback(u'commit 1', self)
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
734
        tree.commit(message_callback=cb)
735
        self.assertTrue(cb.called)
736
        repository = tree.branch.repository
737
        message = repository.get_revision(tree.last_revision()).message
738
        self.assertEqual('commit 1', message)
739
740
    def test_no_callback_pointless(self):
741
        """Callback should not be invoked for pointless commit"""
742
        tree = self.make_branch_and_tree('.')
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
743
        cb = self.Callback(u'commit 2', self)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
744
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
745
                          allow_pointless=False)
746
        self.assertFalse(cb.called)
747
748
    def test_no_callback_netfailure(self):
749
        """Callback should not be invoked if connectivity fails"""
2149.1.3 by Aaron Bentley
Updates from review comments
750
        tree = self.make_branch_and_tree('.')
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
751
        cb = self.Callback(u'commit 2', self)
2149.1.3 by Aaron Bentley
Updates from review comments
752
        repository = tree.branch.repository
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
753
        # simulate network failure
4617.2.1 by Robert Collins
Fix test_commit for use with 2a as the default repository.
754
        def raise_(self, arg, arg2, arg3=None, arg4=None):
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
755
            raise errors.NoSuchFile('foo')
756
        repository.add_inventory = raise_
4617.2.1 by Robert Collins
Fix test_commit for use with 2a as the default repository.
757
        repository.add_inventory_by_delta = raise_
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
758
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
759
        self.assertFalse(cb.called)
1551.15.9 by Aaron Bentley
Better error for selected-file commit of merges
760
761
    def test_selected_file_merge_commit(self):
762
        """Ensure the correct error is raised"""
763
        tree = self.make_branch_and_tree('foo')
764
        # pending merge would turn into a left parent
765
        tree.commit('commit 1')
766
        tree.add_parent_tree_id('example')
767
        self.build_tree(['foo/bar', 'foo/baz'])
768
        tree.add(['bar', 'baz'])
769
        err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
770
            tree.commit, 'commit 2', specific_files=['bar', 'baz'])
771
        self.assertEqual(['bar', 'baz'], err.files)
772
        self.assertEqual('Selected-file commit of merges is not supported'
773
                         ' yet: files bar, baz', str(err))
2671.2.2 by Lukáš Lalinský
Move setting of the author revision property to MutableTree.commit. Don't use try/except KeyError in LongLogFormatter to display authors and branch-nicks. Removed warning about missing e-mail in the authors name.
774
2829.1.1 by Ian Clatworthy
re-apply Aaron's fix for #94975 (Ian Clatworthy)
775
    def test_commit_ordering(self):
776
        """Test of corner-case commit ordering error"""
777
        tree = self.make_branch_and_tree('.')
778
        self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
779
        tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
780
        tree.commit('setup')
781
        self.build_tree(['a/c/d/'])
782
        tree.add('a/c/d')
783
        tree.rename_one('a/z/x', 'a/c/d/x')
784
        tree.commit('test', specific_files=['a/z/y'])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
785
2671.2.2 by Lukáš Lalinský
Move setting of the author revision property to MutableTree.commit. Don't use try/except KeyError in LongLogFormatter to display authors and branch-nicks. Removed warning about missing e-mail in the authors name.
786
    def test_commit_no_author(self):
787
        """The default kwarg author in MutableTree.commit should not add
788
        the 'author' revision property.
789
        """
790
        tree = self.make_branch_and_tree('foo')
791
        rev_id = tree.commit('commit 1')
792
        rev = tree.branch.repository.get_revision(rev_id)
793
        self.assertFalse('author' in rev.properties)
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
794
        self.assertFalse('authors' in rev.properties)
2671.2.2 by Lukáš Lalinský
Move setting of the author revision property to MutableTree.commit. Don't use try/except KeyError in LongLogFormatter to display authors and branch-nicks. Removed warning about missing e-mail in the authors name.
795
796
    def test_commit_author(self):
797
        """Passing a non-empty author kwarg to MutableTree.commit should add
798
        the 'author' revision property.
799
        """
800
        tree = self.make_branch_and_tree('foo')
4056.2.1 by James Westby
Allow specifying multiple authors for a revision.
801
        rev_id = self.callDeprecated(['The parameter author was '
802
                'deprecated in version 1.13. Use authors instead'],
803
                tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
2671.2.2 by Lukáš Lalinský
Move setting of the author revision property to MutableTree.commit. Don't use try/except KeyError in LongLogFormatter to display authors and branch-nicks. Removed warning about missing e-mail in the authors name.
804
        rev = tree.branch.repository.get_revision(rev_id)
805
        self.assertEqual('John Doe <jdoe@example.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
806
                         rev.properties['authors'])
807
        self.assertFalse('author' in rev.properties)
3113.6.7 by Aaron Bentley
Fix commit for a checkout sharing a repo with its branch (abentley, #177592)
808
4056.2.1 by James Westby
Allow specifying multiple authors for a revision.
809
    def test_commit_empty_authors_list(self):
810
        """Passing an empty list to authors shouldn't add the property."""
811
        tree = self.make_branch_and_tree('foo')
812
        rev_id = tree.commit('commit 1', authors=[])
813
        rev = tree.branch.repository.get_revision(rev_id)
814
        self.assertFalse('author' in rev.properties)
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
815
        self.assertFalse('authors' in rev.properties)
4056.2.1 by James Westby
Allow specifying multiple authors for a revision.
816
817
    def test_multiple_authors(self):
818
        tree = self.make_branch_and_tree('foo')
819
        rev_id = tree.commit('commit 1',
820
                authors=['John Doe <jdoe@example.com>',
821
                         'Jane Rey <jrey@example.com>'])
822
        rev = tree.branch.repository.get_revision(rev_id)
823
        self.assertEqual('John Doe <jdoe@example.com>\n'
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
824
                'Jane Rey <jrey@example.com>', rev.properties['authors'])
825
        self.assertFalse('author' in rev.properties)
4056.2.1 by James Westby
Allow specifying multiple authors for a revision.
826
827
    def test_author_and_authors_incompatible(self):
828
        tree = self.make_branch_and_tree('foo')
829
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
830
                authors=['John Doe <jdoe@example.com>',
831
                         'Jane Rey <jrey@example.com>'],
832
                author="Jack Me <jme@example.com>")
833
834
    def test_author_with_newline_rejected(self):
835
        tree = self.make_branch_and_tree('foo')
836
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
837
                authors=['John\nDoe <jdoe@example.com>'])
838
3113.6.7 by Aaron Bentley
Fix commit for a checkout sharing a repo with its branch (abentley, #177592)
839
    def test_commit_with_checkout_and_branch_sharing_repo(self):
840
        repo = self.make_repository('repo', shared=True)
841
        # make_branch_and_tree ignores shared repos
842
        branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
843
        tree2 = branch.create_checkout('repo/tree2')
844
        tree2.commit('message', rev_id='rev1')
845
        self.assertTrue(tree2.branch.repository.has_revision('rev1'))