/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2006-2011 Canonical Ltd
1740.3.1 by Jelmer Vernooij
Introduce and use CommitBuilder objects.
2
#
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.
7
#
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.
12
#
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
1740.3.1 by Jelmer Vernooij
Introduce and use CommitBuilder objects.
16
17
"""Tests for repository commit builder."""
18
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
19
import os
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
20
21
from bzrlib import (
5609.31.2 by mbp at sourcefrog
Also turn off whoami inference in per_repository tests
22
    config,
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
23
    errors,
24
    inventory,
25
    osutils,
26
    repository,
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
27
    revision as _mod_revision,
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
28
    tests,
29
    )
5010.2.24 by Vincent Ladeuil
Fix imports in per_repository/test_commit_builder.py.
30
from bzrlib.tests import per_repository
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
31
from bzrlib.tests import (
32
    features,
33
    )
5010.2.24 by Vincent Ladeuil
Fix imports in per_repository/test_commit_builder.py.
34
35
36
class TestCommitBuilder(per_repository.TestCaseWithRepository):
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
37
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
38
    def test_get_commit_builder(self):
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
39
        branch = self.make_branch('.')
40
        branch.repository.lock_write()
41
        builder = branch.repository.get_commit_builder(
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
42
            branch, [], branch.get_config_stack())
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
43
        self.assertIsInstance(builder, repository.CommitBuilder)
2805.6.1 by Robert Collins
Set random_revid on CommitBuilder when a commit generated its own revision id.
44
        self.assertTrue(builder.random_revid)
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
45
        branch.repository.commit_write_group()
46
        branch.repository.unlock()
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
47
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
48
    def record_root(self, builder, tree):
49
        if builder.record_root_entry is True:
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
50
            tree.lock_read()
51
            try:
52
                ie = tree.inventory.root
53
            finally:
54
                tree.unlock()
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
55
            parent_tree = tree.branch.repository.revision_tree(
56
                              _mod_revision.NULL_REVISION)
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
57
            parent_invs = []
2776.4.4 by Robert Collins
Move content summary generation outside of record_entry_contents.
58
            builder.record_entry_contents(ie, parent_invs, '', tree,
59
                tree.path_content_summary(''))
1731.1.33 by Aaron Bentley
Revert no-special-root changes
60
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
61
    def test_finish_inventory_with_record_root(self):
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
62
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
63
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
64
        try:
65
            builder = tree.branch.get_commit_builder([])
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
66
            if not builder.supports_record_entry_contents:
67
                raise tests.TestNotApplicable("CommitBuilder doesn't support "
68
                    "record_entry_contents")
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
69
            repo = tree.branch.repository
2617.6.8 by Robert Collins
Review feedback and documentation.
70
            self.record_root(builder, tree)
71
            builder.finish_inventory()
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
72
            repo.commit_write_group()
73
        finally:
74
            tree.unlock()
75
76
    def test_finish_inventory_record_iter_changes(self):
77
        tree = self.make_branch_and_tree(".")
78
        tree.lock_write()
79
        try:
80
            builder = tree.branch.get_commit_builder([])
81
            try:
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
82
                list(builder.record_iter_changes(tree, tree.last_revision(),
83
                    tree.iter_changes(tree.basis_tree())))
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
84
                builder.finish_inventory()
85
            except:
86
                builder.abort()
87
                raise
88
            repo = tree.branch.repository
89
            repo.commit_write_group()
2617.6.8 by Robert Collins
Review feedback and documentation.
90
        finally:
91
            tree.unlock()
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
92
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
93
    def test_abort_record_entry_contents(self):
2749.3.1 by Jelmer Vernooij
Add CommitBuilder.abort().
94
        tree = self.make_branch_and_tree(".")
95
        tree.lock_write()
96
        try:
97
            builder = tree.branch.get_commit_builder([])
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
98
            if not builder.supports_record_entry_contents:
99
                raise tests.TestNotApplicable("CommitBuilder doesn't support "
100
                    "record_entry_contents")
2749.3.1 by Jelmer Vernooij
Add CommitBuilder.abort().
101
            self.record_root(builder, tree)
102
            builder.finish_inventory()
103
            builder.abort()
104
        finally:
105
            tree.unlock()
106
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
107
    def test_abort_record_iter_changes(self):
108
        tree = self.make_branch_and_tree(".")
109
        tree.lock_write()
110
        try:
111
            builder = tree.branch.get_commit_builder([])
112
            try:
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
113
                basis = tree.basis_tree()
114
                last_rev = tree.last_revision()
115
                changes = tree.iter_changes(basis)
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
116
                list(builder.record_iter_changes(tree, last_rev, changes))
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
117
                builder.finish_inventory()
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
118
            finally:
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
119
                builder.abort()
120
        finally:
121
            tree.unlock()
122
5777.6.8 by Jelmer Vernooij
Add test for get_commit_builder(lossy=True).
123
    def test_commit_lossy(self):
124
        tree = self.make_branch_and_tree(".")
125
        tree.lock_write()
126
        try:
127
            builder = tree.branch.get_commit_builder([], lossy=True)
128
            list(builder.record_iter_changes(tree, tree.last_revision(),
129
                tree.iter_changes(tree.basis_tree())))
130
            builder.finish_inventory()
131
            rev_id = builder.commit('foo bar blah')
132
        finally:
133
            tree.unlock()
134
        rev = tree.branch.repository.get_revision(rev_id)
135
        self.assertEqual('foo bar blah', rev.message)
136
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
137
    def test_commit_message(self):
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
138
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
139
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
140
        try:
141
            builder = tree.branch.get_commit_builder([])
5718.4.6 by Jelmer Vernooij
inline function only used once.
142
            list(builder.record_iter_changes(tree, tree.last_revision(),
143
                tree.iter_changes(tree.basis_tree())))
144
            builder.finish_inventory()
2617.6.8 by Robert Collins
Review feedback and documentation.
145
            rev_id = builder.commit('foo bar blah')
146
        finally:
147
            tree.unlock()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
148
        rev = tree.branch.repository.get_revision(rev_id)
149
        self.assertEqual('foo bar blah', rev.message)
150
6217.5.1 by Jelmer Vernooij
Add CommitBuilder.updates_branch.
151
    def test_updates_branch(self):
152
        tree = self.make_branch_and_tree(".")
153
        tree.lock_write()
154
        try:
155
            builder = tree.branch.get_commit_builder([])
156
            list(builder.record_iter_changes(tree, tree.last_revision(),
157
                tree.iter_changes(tree.basis_tree())))
158
            builder.finish_inventory()
159
            will_update_branch = builder.updates_branch
160
            rev_id = builder.commit('might update the branch')
161
        finally:
162
            tree.unlock()
163
        actually_updated_branch = (tree.branch.last_revision() == rev_id)
164
        self.assertEquals(actually_updated_branch, will_update_branch)
165
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
166
    def test_commit_with_revision_id_record_entry_contents(self):
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
167
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
168
        tree.lock_write()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
169
        try:
2617.6.8 by Robert Collins
Review feedback and documentation.
170
            # use a unicode revision id to test more corner cases.
171
            # The repository layer is meant to handle this.
172
            revision_id = u'\xc8abc'.encode('utf8')
2150.2.2 by Robert Collins
Change the commit builder selected-revision-id test to use a unicode revision id where possible, leading to stricter testing of the hypothetical unicode revision id support in bzr.
173
            try:
2617.6.8 by Robert Collins
Review feedback and documentation.
174
                try:
175
                    builder = tree.branch.get_commit_builder([],
176
                        revision_id=revision_id)
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
177
                except errors.NonAsciiRevisionId:
2617.6.8 by Robert Collins
Review feedback and documentation.
178
                    revision_id = 'abc'
179
                    builder = tree.branch.get_commit_builder([],
180
                        revision_id=revision_id)
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
181
            except errors.CannotSetRevisionId:
2617.6.8 by Robert Collins
Review feedback and documentation.
182
                # This format doesn't support supplied revision ids
183
                return
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
184
            if not builder.supports_record_entry_contents:
185
                raise tests.TestNotApplicable("CommitBuilder doesn't support "
186
                    "record_entry_contents")
2805.6.1 by Robert Collins
Set random_revid on CommitBuilder when a commit generated its own revision id.
187
            self.assertFalse(builder.random_revid)
2617.6.8 by Robert Collins
Review feedback and documentation.
188
            self.record_root(builder, tree)
189
            builder.finish_inventory()
190
            self.assertEqual(revision_id, builder.commit('foo bar'))
191
        finally:
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
192
            tree.unlock()
2150.2.2 by Robert Collins
Change the commit builder selected-revision-id test to use a unicode revision id where possible, leading to stricter testing of the hypothetical unicode revision id support in bzr.
193
        self.assertTrue(tree.branch.repository.has_revision(revision_id))
194
        # the revision id must be set on the inventory when saving it. This
195
        # does not precisely test that - a repository that wants to can add it
196
        # on deserialisation, but thats all the current contract guarantees
197
        # anyway.
198
        self.assertEqual(revision_id,
199
            tree.branch.repository.get_inventory(revision_id).revision_id)
1740.3.8 by Jelmer Vernooij
Move make_revision() to commit builder.
200
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
201
    def test_commit_with_revision_id_record_iter_changes(self):
202
        tree = self.make_branch_and_tree(".")
203
        tree.lock_write()
204
        try:
205
            # use a unicode revision id to test more corner cases.
206
            # The repository layer is meant to handle this.
207
            revision_id = u'\xc8abc'.encode('utf8')
208
            try:
209
                try:
210
                    builder = tree.branch.get_commit_builder([],
211
                        revision_id=revision_id)
212
                except errors.NonAsciiRevisionId:
213
                    revision_id = 'abc'
214
                    builder = tree.branch.get_commit_builder([],
215
                        revision_id=revision_id)
216
            except errors.CannotSetRevisionId:
217
                # This format doesn't support supplied revision ids
218
                return
219
            self.assertFalse(builder.random_revid)
220
            try:
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
221
                list(builder.record_iter_changes(tree, tree.last_revision(),
222
                    tree.iter_changes(tree.basis_tree())))
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
223
                builder.finish_inventory()
224
            except:
225
                builder.abort()
226
                raise
227
            self.assertEqual(revision_id, builder.commit('foo bar'))
228
        finally:
229
            tree.unlock()
230
        self.assertTrue(tree.branch.repository.has_revision(revision_id))
231
        # the revision id must be set on the inventory when saving it. This
232
        # does not precisely test that - a repository that wants to can add it
233
        # on deserialisation, but thats all the current contract guarantees
234
        # anyway.
235
        self.assertEqual(revision_id,
6113.1.4 by Jelmer Vernooij
Use revision_tree for testing, it's always present.
236
            tree.branch.repository.revision_tree(revision_id).get_revision_id())
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
237
5222.1.1 by Aaron Bentley
Refuse to commit trees with no root.
238
    def test_commit_without_root_errors(self):
239
        tree = self.make_branch_and_tree(".")
240
        tree.lock_write()
241
        try:
242
            builder = tree.branch.get_commit_builder([])
243
            def do_commit():
244
                try:
245
                    list(builder.record_iter_changes(
246
                        tree, tree.last_revision(), []))
247
                    builder.finish_inventory()
248
                except:
249
                    builder.abort()
250
                    raise
6202.2.1 by Jelmer Vernooij
Commit in commit builder test to prevent masking errors.
251
                else:
252
                    builder.commit("msg")
5222.1.1 by Aaron Bentley
Refuse to commit trees with no root.
253
            self.assertRaises(errors.RootMissing, do_commit)
254
        finally:
255
            tree.unlock()
256
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
257
    def test_commit_without_root_or_record_iter_changes_errors(self):
1910.2.8 by Aaron Bentley
Fix commit_builder when root not passed to record_entry_contents
258
        tree = self.make_branch_and_tree(".")
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
259
        tree.lock_write()
260
        try:
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
261
            self.build_tree(['foo'])
262
            tree.add('foo', 'foo-id')
5856.1.2 by Jelmer Vernooij
Delay accessing inventory in tests until necessary.
263
            builder = tree.branch.get_commit_builder([])
264
            if not builder.supports_record_entry_contents:
265
                raise tests.TestNotApplicable("CommitBuilder doesn't support "
266
                    "record_entry_contents")
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
267
            entry = tree.inventory['foo-id']
2871.1.2 by Robert Collins
* ``CommitBuilder.record_entry_contents`` now requires the root entry of a
268
            self.assertRaises(errors.RootMissing,
2776.4.4 by Robert Collins
Move content summary generation outside of record_entry_contents.
269
                builder.record_entry_contents, entry, [], 'foo', tree,
270
                    tree.path_content_summary('foo'))
2871.1.2 by Robert Collins
* ``CommitBuilder.record_entry_contents`` now requires the root entry of a
271
            builder.abort()
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
272
        finally:
273
            tree.unlock()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
274
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
275
    def test_commit_unchanged_root_record_entry_contents(self):
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
276
        tree = self.make_branch_and_tree(".")
2903.2.3 by Martin Pool
CommitBuilder tests should expect the root to be in the delta iff it's changed in the commit
277
        old_revision_id = tree.commit('')
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
278
        tree.lock_write()
279
        parent_tree = tree.basis_tree()
280
        parent_tree.lock_read()
281
        self.addCleanup(parent_tree.unlock)
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
282
        builder = tree.branch.get_commit_builder([old_revision_id])
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
283
        try:
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
284
            if not builder.supports_record_entry_contents:
285
                raise tests.TestNotApplicable("CommitBuilder doesn't support "
286
                    "record_entry_contents")
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
287
            ie = inventory.make_entry('directory', '', None,
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
288
                    tree.get_root_id())
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
289
            delta, version_recorded, fs_hash = builder.record_entry_contents(
2776.4.13 by Robert Collins
Merge bzr.dev.
290
                ie, [parent_tree.inventory], '', tree,
2871.1.4 by Robert Collins
Merge bzr.dev.
291
                tree.path_content_summary(''))
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
292
            # Regardless of repository root behaviour we should consider this a
293
            # pointless commit.
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
294
            self.assertFalse(builder.any_changes())
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
295
            self.assertFalse(version_recorded)
2903.2.3 by Martin Pool
CommitBuilder tests should expect the root to be in the delta iff it's changed in the commit
296
            # if the repository format recorded a new root revision, that
297
            # should be in the delta
298
            got_new_revision = ie.revision != old_revision_id
299
            if got_new_revision:
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
300
                self.assertEqual(('', '', ie.file_id, ie), delta)
301
                # The delta should be tracked
302
                self.assertEqual(delta, builder._basis_delta[-1])
2903.2.3 by Martin Pool
CommitBuilder tests should expect the root to be in the delta iff it's changed in the commit
303
            else:
304
                self.assertEqual(None, delta)
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
305
            # Directories do not get hashed.
306
            self.assertEqual(None, fs_hash)
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
307
            builder.abort()
308
        except:
309
            builder.abort()
310
            tree.unlock()
311
            raise
312
        else:
313
            tree.unlock()
1910.2.8 by Aaron Bentley
Fix commit_builder when root not passed to record_entry_contents
314
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
315
    def test_commit_unchanged_root_record_iter_changes(self):
316
        tree = self.make_branch_and_tree(".")
317
        old_revision_id = tree.commit('')
318
        tree.lock_write()
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
319
        builder = tree.branch.get_commit_builder([old_revision_id])
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
320
        try:
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
321
            list(builder.record_iter_changes(tree, old_revision_id, []))
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
322
            # Regardless of repository root behaviour we should consider this a
323
            # pointless commit.
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
324
            self.assertFalse(builder.any_changes())
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
325
            builder.finish_inventory()
6362.5.5 by Jelmer Vernooij
Don't access revision tree before commit.
326
            builder.commit('')
5878.1.1 by Jelmer Vernooij
Avoid inventory usage in a commit builder test.
327
            builder_tree = builder.revision_tree()
328
            new_root_id = builder_tree.get_root_id()
329
            new_root_revision = builder_tree.get_file_revision(new_root_id)
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
330
            if tree.branch.repository.supports_rich_root():
331
                # We should not have seen a new root revision
5878.1.1 by Jelmer Vernooij
Avoid inventory usage in a commit builder test.
332
                self.assertEqual(old_revision_id, new_root_revision)
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
333
            else:
334
                # We should see a new root revision
5878.1.1 by Jelmer Vernooij
Avoid inventory usage in a commit builder test.
335
                self.assertNotEqual(old_revision_id, new_root_revision)
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
336
        finally:
337
            tree.unlock()
338
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
339
    def test_commit_record_entry_contents(self):
1740.3.8 by Jelmer Vernooij
Move make_revision() to commit builder.
340
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
341
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
342
        try:
343
            builder = tree.branch.get_commit_builder([])
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
344
            if not builder.supports_record_entry_contents:
345
                raise tests.TestNotApplicable("CommitBuilder doesn't "
346
                    "support record_entry_contents")
2617.6.8 by Robert Collins
Review feedback and documentation.
347
            self.record_root(builder, tree)
348
            builder.finish_inventory()
349
            rev_id = builder.commit('foo bar')
350
        finally:
351
            tree.unlock()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
352
        self.assertNotEqual(None, rev_id)
353
        self.assertTrue(tree.branch.repository.has_revision(rev_id))
1757.1.2 by Robert Collins
Bugfix CommitBuilders recording of the inventory revision id.
354
        # the revision id must be set on the inventory when saving it. This does not
355
        # precisely test that - a repository that wants to can add it on deserialisation,
356
        # but thats all the current contract guarantees anyway.
357
        self.assertEqual(rev_id, tree.branch.repository.get_inventory(rev_id).revision_id)
2041.1.1 by John Arbash Meinel
Add a 'get_tree()' call that returns a RevisionTree for the newly committed tree
358
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
359
    def test_get_basis_delta(self):
360
        tree = self.make_branch_and_tree(".")
361
        self.build_tree(["foo"])
362
        tree.add(["foo"], ["foo-id"])
363
        old_revision_id = tree.commit("added foo")
364
        tree.lock_write()
365
        try:
366
            self.build_tree(['bar'])
367
            tree.add(['bar'], ['bar-id'])
368
            basis = tree.branch.repository.revision_tree(old_revision_id)
369
            basis.lock_read()
370
            self.addCleanup(basis.unlock)
371
            builder = tree.branch.get_commit_builder([old_revision_id])
372
            total_delta = []
373
            try:
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
374
                if not builder.supports_record_entry_contents:
375
                    raise tests.TestNotApplicable("CommitBuilder doesn't "
376
                        "support record_entry_contents")
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
377
                parent_invs = [basis.inventory]
378
                builder.will_record_deletes()
379
                if builder.record_root_entry:
380
                    ie = basis.inventory.root.copy()
381
                    delta, _, _ = builder.record_entry_contents(ie, parent_invs,
382
                        '', tree, tree.path_content_summary(''))
383
                    if delta is not None:
384
                        total_delta.append(delta)
385
                delta = builder.record_delete("foo", "foo-id")
386
                total_delta.append(delta)
387
                new_bar = inventory.make_entry('file', 'bar',
388
                    parent_id=tree.get_root_id(), file_id='bar-id')
389
                delta, _, _ = builder.record_entry_contents(new_bar, parent_invs,
390
                    'bar', tree, tree.path_content_summary('bar'))
391
                total_delta.append(delta)
392
                # All actions should have been recorded in the basis_delta
393
                self.assertEqual(total_delta, builder.get_basis_delta())
394
                builder.finish_inventory()
395
                builder.commit('delete foo, add bar')
396
            except:
397
                tree.branch.repository.abort_write_group()
398
                raise
399
        finally:
400
            tree.unlock()
401
402
    def test_get_basis_delta_without_notification(self):
403
        tree = self.make_branch_and_tree(".")
404
        old_revision_id = tree.commit('')
405
        tree.lock_write()
406
        try:
407
            parent_tree = tree.basis_tree()
408
            parent_tree.lock_read()
409
            self.addCleanup(parent_tree.unlock)
410
            builder = tree.branch.get_commit_builder([old_revision_id])
411
            # It is an error to expect builder.get_basis_delta() to be correct,
412
            # if you have not also called will_record_deletes() to indicate you
413
            # will be calling record_delete() when appropriate
414
            self.assertRaises(AssertionError, builder.get_basis_delta)
415
            tree.branch.repository.abort_write_group()
416
        finally:
417
            tree.unlock()
418
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
419
    def test_record_delete(self):
420
        tree = self.make_branch_and_tree(".")
421
        self.build_tree(["foo"])
422
        tree.add(["foo"], ["foo-id"])
423
        rev_id = tree.commit("added foo")
424
        # Remove the inventory details for foo-id, because
425
        # record_entry_contents ends up copying root verbatim.
426
        tree.unversion(["foo-id"])
427
        tree.lock_write()
428
        try:
429
            basis = tree.branch.repository.revision_tree(rev_id)
430
            builder = tree.branch.get_commit_builder([rev_id])
431
            try:
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
432
                if not builder.supports_record_entry_contents:
433
                    raise tests.TestNotApplicable("CommitBuilder doesn't "
434
                        "support record_entry_contents")
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
435
                builder.will_record_deletes()
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
436
                if builder.record_root_entry is True:
437
                    parent_invs = [basis.inventory]
438
                    del basis.inventory.root.children['foo']
439
                    builder.record_entry_contents(basis.inventory.root,
440
                        parent_invs, '', tree, tree.path_content_summary(''))
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
441
                # the delta should be returned, and recorded in _basis_delta
442
                delta = builder.record_delete("foo", "foo-id")
443
                self.assertEqual(("foo", None, "foo-id", None), delta)
444
                self.assertEqual(delta, builder._basis_delta[-1])
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
445
                builder.finish_inventory()
446
                rev_id2 = builder.commit('delete foo')
447
            except:
448
                tree.branch.repository.abort_write_group()
449
                raise
450
        finally:
451
            tree.unlock()
452
        rev_tree = builder.revision_tree()
453
        rev_tree.lock_read()
454
        self.addCleanup(rev_tree.unlock)
455
        self.assertFalse(rev_tree.path2id('foo'))
456
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
457
    def test_record_delete_record_iter_changes(self):
458
        tree = self.make_branch_and_tree(".")
459
        self.build_tree(["foo"])
460
        tree.add(["foo"], ["foo-id"])
461
        rev_id = tree.commit("added foo")
462
        tree.lock_write()
463
        try:
464
            builder = tree.branch.get_commit_builder([rev_id])
465
            try:
466
                delete_change = ('foo-id', ('foo', None), True, (True, False),
467
                    (tree.path2id(''), None), ('foo', None), ('file', None),
468
                    (False, None))
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
469
                list(builder.record_iter_changes(tree, rev_id,
470
                    [delete_change]))
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
471
                self.assertEqual(("foo", None, "foo-id", None),
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
472
                    builder._basis_delta[0])
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
473
                self.assertTrue(builder.any_changes())
474
                builder.finish_inventory()
475
                rev_id2 = builder.commit('delete foo')
476
            except:
477
                builder.abort()
478
                raise
479
        finally:
480
            tree.unlock()
481
        rev_tree = builder.revision_tree()
482
        rev_tree.lock_read()
483
        self.addCleanup(rev_tree.unlock)
484
        self.assertFalse(rev_tree.path2id('foo'))
485
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
486
    def test_record_delete_without_notification(self):
487
        tree = self.make_branch_and_tree(".")
488
        self.build_tree(["foo"])
489
        tree.add(["foo"], ["foo-id"])
490
        rev_id = tree.commit("added foo")
491
        tree.lock_write()
492
        try:
493
            builder = tree.branch.get_commit_builder([rev_id])
494
            try:
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
495
                if not builder.supports_record_entry_contents:
496
                    raise tests.TestNotApplicable("CommitBuilder doesn't "
497
                        "support record_entry_contents")
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
498
                self.record_root(builder, tree)
499
                self.assertRaises(AssertionError,
500
                    builder.record_delete, "foo", "foo-id")
501
            finally:
502
                tree.branch.repository.abort_write_group()
503
        finally:
504
            tree.unlock()
505
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
506
    def test_revision_tree_record_entry_contents(self):
2041.1.1 by John Arbash Meinel
Add a 'get_tree()' call that returns a RevisionTree for the newly committed tree
507
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
508
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
509
        try:
510
            builder = tree.branch.get_commit_builder([])
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
511
            if not builder.supports_record_entry_contents:
512
                raise tests.TestNotApplicable("CommitBuilder doesn't "
513
                    "support record_entry_contents")
2617.6.8 by Robert Collins
Review feedback and documentation.
514
            self.record_root(builder, tree)
515
            builder.finish_inventory()
516
            rev_id = builder.commit('foo bar')
517
        finally:
518
            tree.unlock()
2041.1.5 by John Arbash Meinel
CommitBuilder.get_tree => CommitBuilder.revision_tree
519
        rev_tree = builder.revision_tree()
2041.1.1 by John Arbash Meinel
Add a 'get_tree()' call that returns a RevisionTree for the newly committed tree
520
        # Just a couple simple tests to ensure that it actually follows
521
        # the RevisionTree api.
522
        self.assertEqual(rev_id, rev_tree.get_revision_id())
523
        self.assertEqual([], rev_tree.get_parent_ids())
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
524
3775.2.10 by Robert Collins
CommitBuilder gives a revision tree when used with record_iter_contents.
525
    def test_revision_tree_record_iter_changes(self):
526
        tree = self.make_branch_and_tree(".")
527
        tree.lock_write()
528
        try:
529
            builder = tree.branch.get_commit_builder([])
530
            try:
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
531
                list(builder.record_iter_changes(tree,
532
                    _mod_revision.NULL_REVISION,
533
                    tree.iter_changes(tree.basis_tree())))
3775.2.10 by Robert Collins
CommitBuilder gives a revision tree when used with record_iter_contents.
534
                builder.finish_inventory()
535
                rev_id = builder.commit('foo bar')
536
            except:
537
                builder.abort()
538
                raise
539
            rev_tree = builder.revision_tree()
540
            # Just a couple simple tests to ensure that it actually follows
541
            # the RevisionTree api.
542
            self.assertEqual(rev_id, rev_tree.get_revision_id())
6072.1.1 by Jelmer Vernooij
Various fixes for tests of foreign plugins.
543
            self.assertEqual((), tuple(rev_tree.get_parent_ids()))
3775.2.10 by Robert Collins
CommitBuilder gives a revision tree when used with record_iter_contents.
544
        finally:
545
            tree.unlock()
546
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
547
    def test_root_entry_has_revision(self):
548
        # test the root revision created and put in the basis
549
        # has the right rev id.
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
550
        # XXX: RBC 20081118 - this test is too big, it depends on the exact
551
        # behaviour of tree methods and so on; it should be written to the
552
        # commit builder interface directly.
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
553
        tree = self.make_branch_and_tree('.')
554
        rev_id = tree.commit('message')
555
        basis_tree = tree.basis_tree()
556
        basis_tree.lock_read()
557
        self.addCleanup(basis_tree.unlock)
5819.2.4 by Jelmer Vernooij
Avoid using inventory.
558
        self.assertEqual(rev_id,
559
            basis_tree.get_file_revision(basis_tree.get_root_id()))
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
560
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
561
    def _get_revtrees(self, tree, revision_ids):
2592.3.214 by Robert Collins
Merge bzr.dev.
562
        tree.lock_read()
563
        try:
564
            trees = list(tree.branch.repository.revision_trees(revision_ids))
565
            for _tree in trees:
566
                _tree.lock_read()
567
                self.addCleanup(_tree.unlock)
568
            return trees
569
        finally:
570
            tree.unlock()
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
571
572
    def test_last_modified_revision_after_commit_root_unchanged(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
573
        # commiting without changing the root does not change the
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
574
        # last modified except on non-rich-root-repositories.
575
        tree = self.make_branch_and_tree('.')
576
        rev1 = tree.commit('')
577
        rev2 = tree.commit('')
578
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
5819.2.4 by Jelmer Vernooij
Avoid using inventory.
579
        self.assertEqual(rev1, tree1.get_file_revision(tree1.get_root_id()))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
580
        if tree.branch.repository.supports_rich_root():
5819.2.4 by Jelmer Vernooij
Avoid using inventory.
581
            self.assertEqual(rev1,
582
                tree2.get_file_revision(tree2.get_root_id()))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
583
        else:
5819.2.4 by Jelmer Vernooij
Avoid using inventory.
584
            self.assertEqual(rev2,
585
                tree2.get_file_revision(tree2.get_root_id()))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
586
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
587
    def _add_commit_check_unchanged(self, tree, name, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
588
        tree.add([name], [name + 'id'])
4183.5.3 by Robert Collins
Fix typo.
589
        self._commit_check_unchanged(tree, name, name + 'id',
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
590
            mini_commit=mini_commit)
591
592
    def _commit_check_unchanged(self, tree, name, file_id, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
593
        rev1 = tree.commit('')
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
594
        if mini_commit is None:
595
            mini_commit = self.mini_commit
596
        rev2 = mini_commit(tree, name, name, False, False)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
597
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
598
        self.assertEqual(rev1, tree1.get_file_revision(file_id))
599
        self.assertEqual(rev1, tree2.get_file_revision(file_id))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
600
        expected_graph = {}
601
        expected_graph[(file_id, rev1)] = ()
602
        self.assertFileGraph(expected_graph, tree, (file_id, rev1))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
603
604
    def test_last_modified_revision_after_commit_dir_unchanged(self):
605
        # committing without changing a dir does not change the last modified.
606
        tree = self.make_branch_and_tree('.')
607
        self.build_tree(['dir/'])
608
        self._add_commit_check_unchanged(tree, 'dir')
609
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
610
    def test_last_modified_revision_after_commit_dir_unchanged_ric(self):
611
        # committing without changing a dir does not change the last modified.
612
        tree = self.make_branch_and_tree('.')
613
        self.build_tree(['dir/'])
614
        self._add_commit_check_unchanged(tree, 'dir',
615
            mini_commit=self.mini_commit_record_iter_changes)
616
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
617
    def test_last_modified_revision_after_commit_dir_contents_unchanged(self):
618
        # committing without changing a dir does not change the last modified
619
        # of the dir even the dirs contents are changed.
620
        tree = self.make_branch_and_tree('.')
621
        self.build_tree(['dir/'])
622
        tree.add(['dir'], ['dirid'])
623
        rev1 = tree.commit('')
624
        self.build_tree(['dir/content'])
625
        tree.add(['dir/content'], ['contentid'])
626
        rev2 = tree.commit('')
627
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
628
        self.assertEqual(rev1, tree1.get_file_revision('dirid'))
629
        self.assertEqual(rev1, tree2.get_file_revision('dirid'))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
630
        file_id = 'dirid'
631
        expected_graph = {}
632
        expected_graph[(file_id, rev1)] = ()
633
        self.assertFileGraph(expected_graph, tree, (file_id, rev1))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
634
635
    def test_last_modified_revision_after_commit_file_unchanged(self):
636
        # committing without changing a file does not change the last modified.
637
        tree = self.make_branch_and_tree('.')
638
        self.build_tree(['file'])
639
        self._add_commit_check_unchanged(tree, 'file')
640
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
641
    def test_last_modified_revision_after_commit_file_unchanged_ric(self):
642
        # committing without changing a file does not change the last modified.
643
        tree = self.make_branch_and_tree('.')
644
        self.build_tree(['file'])
645
        self._add_commit_check_unchanged(tree, 'file',
646
            mini_commit=self.mini_commit_record_iter_changes)
647
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
648
    def test_last_modified_revision_after_commit_link_unchanged(self):
649
        # committing without changing a link does not change the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
650
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
651
        tree = self.make_branch_and_tree('.')
652
        os.symlink('target', 'link')
653
        self._add_commit_check_unchanged(tree, 'link')
654
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
655
    def test_last_modified_revision_after_commit_link_unchanged_ric(self):
4183.5.6 by Robert Collins
Review caught a bogus change to test_last_modified_revision_after_commit_link_unchanged_ric.
656
        # committing without changing a link does not change the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
657
        self.requireFeature(features.SymlinkFeature)
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
658
        tree = self.make_branch_and_tree('.')
659
        os.symlink('target', 'link')
660
        self._add_commit_check_unchanged(tree, 'link',
661
            mini_commit=self.mini_commit_record_iter_changes)
662
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
663
    def test_last_modified_revision_after_commit_reference_unchanged(self):
664
        # committing without changing a subtree does not change the last
665
        # modified.
666
        tree = self.make_branch_and_tree('.')
667
        subtree = self.make_reference('reference')
668
        try:
669
            tree.add_reference(subtree)
670
            self._commit_check_unchanged(tree, 'reference',
671
                subtree.get_root_id())
672
        except errors.UnsupportedOperation:
673
            return
674
675
    def test_last_modified_revision_after_commit_reference_unchanged_ric(self):
676
        # committing without changing a subtree does not change the last
677
        # modified.
678
        tree = self.make_branch_and_tree('.')
679
        subtree = self.make_reference('reference')
680
        try:
681
            tree.add_reference(subtree)
682
            self._commit_check_unchanged(tree, 'reference',
683
                subtree.get_root_id(),
684
                mini_commit=self.mini_commit_record_iter_changes)
685
        except errors.UnsupportedOperation:
686
            return
687
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
688
    def _add_commit_renamed_check_changed(self, tree, name,
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
689
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
690
        def rename():
691
            tree.rename_one(name, 'new_' + name)
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
692
        self._add_commit_change_check_changed(tree, name, rename,
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
693
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
694
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
695
    def _commit_renamed_check_changed(self, tree, name, file_id,
696
        expect_fs_hash=False, mini_commit=None):
697
        def rename():
698
            tree.rename_one(name, 'new_' + name)
699
        self._commit_change_check_changed(tree, name, file_id, rename,
700
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
701
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
702
    def test_last_modified_revision_after_rename_dir_changes(self):
703
        # renaming a dir changes the last modified.
704
        tree = self.make_branch_and_tree('.')
705
        self.build_tree(['dir/'])
706
        self._add_commit_renamed_check_changed(tree, 'dir')
707
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
708
    def test_last_modified_revision_after_rename_dir_changes_ric(self):
709
        # renaming a dir changes the last modified.
710
        tree = self.make_branch_and_tree('.')
711
        self.build_tree(['dir/'])
712
        self._add_commit_renamed_check_changed(tree, 'dir',
713
            mini_commit=self.mini_commit_record_iter_changes)
714
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
715
    def test_last_modified_revision_after_rename_file_changes(self):
716
        # renaming a file changes the last modified.
717
        tree = self.make_branch_and_tree('.')
718
        self.build_tree(['file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
719
        self._add_commit_renamed_check_changed(tree, 'file',
720
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
721
3775.2.12 by Robert Collins
CommitBuilder.record_iter_changes handles renamed files.
722
    def test_last_modified_revision_after_rename_file_changes_ric(self):
723
        # renaming a file changes the last modified.
724
        tree = self.make_branch_and_tree('.')
725
        self.build_tree(['file'])
726
        self._add_commit_renamed_check_changed(tree, 'file',
727
            expect_fs_hash=True,
728
            mini_commit=self.mini_commit_record_iter_changes)
729
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
730
    def test_last_modified_revision_after_rename_link_changes(self):
731
        # renaming a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
732
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
733
        tree = self.make_branch_and_tree('.')
734
        os.symlink('target', 'link')
735
        self._add_commit_renamed_check_changed(tree, 'link')
736
3775.2.13 by Robert Collins
CommitBuilder.record_iter_changes handles renamed symlinks.
737
    def test_last_modified_revision_after_rename_link_changes_ric(self):
738
        # renaming a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
739
        self.requireFeature(features.SymlinkFeature)
3775.2.13 by Robert Collins
CommitBuilder.record_iter_changes handles renamed symlinks.
740
        tree = self.make_branch_and_tree('.')
741
        os.symlink('target', 'link')
742
        self._add_commit_renamed_check_changed(tree, 'link',
743
            mini_commit=self.mini_commit_record_iter_changes)
744
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
745
    def test_last_modified_revision_after_rename_ref_changes(self):
746
        # renaming a reference changes the last modified.
747
        tree = self.make_branch_and_tree('.')
748
        subtree = self.make_reference('reference')
749
        try:
750
            tree.add_reference(subtree)
751
            self._commit_renamed_check_changed(tree, 'reference',
752
                subtree.get_root_id())
753
        except errors.UnsupportedOperation:
754
            return
755
756
    def test_last_modified_revision_after_rename_ref_changes_ric(self):
757
        # renaming a reference changes the last modified.
758
        tree = self.make_branch_and_tree('.')
759
        subtree = self.make_reference('reference')
760
        try:
761
            tree.add_reference(subtree)
762
            self._commit_renamed_check_changed(tree, 'reference',
763
                subtree.get_root_id(),
764
                mini_commit=self.mini_commit_record_iter_changes)
765
        except errors.UnsupportedOperation:
766
            return
767
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
768
    def _add_commit_reparent_check_changed(self, tree, name,
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
769
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
770
        self.build_tree(['newparent/'])
771
        tree.add(['newparent'])
772
        def reparent():
773
            tree.rename_one(name, 'newparent/new_' + name)
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
774
        self._add_commit_change_check_changed(tree, name, reparent,
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
775
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
776
777
    def test_last_modified_revision_after_reparent_dir_changes(self):
778
        # reparenting a dir changes the last modified.
779
        tree = self.make_branch_and_tree('.')
780
        self.build_tree(['dir/'])
781
        self._add_commit_reparent_check_changed(tree, 'dir')
782
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
783
    def test_last_modified_revision_after_reparent_dir_changes_ric(self):
784
        # reparenting a dir changes the last modified.
785
        tree = self.make_branch_and_tree('.')
786
        self.build_tree(['dir/'])
787
        self._add_commit_reparent_check_changed(tree, 'dir',
788
            mini_commit=self.mini_commit_record_iter_changes)
789
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
790
    def test_last_modified_revision_after_reparent_file_changes(self):
791
        # reparenting a file changes the last modified.
792
        tree = self.make_branch_and_tree('.')
793
        self.build_tree(['file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
794
        self._add_commit_reparent_check_changed(tree, 'file',
795
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
796
3775.2.15 by Robert Collins
CommitBuilder.record_iter_changes handles reparented files.
797
    def test_last_modified_revision_after_reparent_file_changes_ric(self):
798
        # reparenting a file changes the last modified.
799
        tree = self.make_branch_and_tree('.')
800
        self.build_tree(['file'])
801
        self._add_commit_reparent_check_changed(tree, 'file',
3775.2.17 by Robert Collins
CommitBuilder.record_iter_changes handles changed files.
802
            expect_fs_hash=True,
803
            mini_commit=self.mini_commit_record_iter_changes)
3775.2.15 by Robert Collins
CommitBuilder.record_iter_changes handles reparented files.
804
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
805
    def test_last_modified_revision_after_reparent_link_changes(self):
806
        # reparenting a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
807
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
808
        tree = self.make_branch_and_tree('.')
809
        os.symlink('target', 'link')
810
        self._add_commit_reparent_check_changed(tree, 'link')
811
3775.2.16 by Robert Collins
CommitBuilder.record_iter_changes handles reparented symlinks.
812
    def test_last_modified_revision_after_reparent_link_changes_ric(self):
813
        # reparenting a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
814
        self.requireFeature(features.SymlinkFeature)
3775.2.16 by Robert Collins
CommitBuilder.record_iter_changes handles reparented symlinks.
815
        tree = self.make_branch_and_tree('.')
816
        os.symlink('target', 'link')
817
        self._add_commit_reparent_check_changed(tree, 'link',
818
            mini_commit=self.mini_commit_record_iter_changes)
819
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
820
    def _add_commit_change_check_changed(self, tree, name, changer,
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
821
        expect_fs_hash=False, mini_commit=None, file_id=None):
822
        if file_id is None:
823
            file_id = name + 'id'
824
        tree.add([name], [file_id])
825
        self._commit_change_check_changed(
826
            tree, name, file_id,
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
827
            changer, expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
828
4183.5.3 by Robert Collins
Fix typo.
829
    def _commit_change_check_changed(self, tree, name, file_id, changer,
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
830
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
831
        rev1 = tree.commit('')
832
        changer()
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
833
        if mini_commit is None:
834
            mini_commit = self.mini_commit
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
835
        rev2 = mini_commit(tree, name, tree.id2path(file_id),
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
836
            expect_fs_hash=expect_fs_hash)
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
837
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
838
        self.assertEqual(rev1, tree1.get_file_revision(file_id))
839
        self.assertEqual(rev2, tree2.get_file_revision(file_id))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
840
        expected_graph = {}
841
        expected_graph[(file_id, rev1)] = ()
842
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
843
        self.assertFileGraph(expected_graph, tree, (file_id, rev2))
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
844
845
    def mini_commit(self, tree, name, new_name, records_version=True,
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
846
        delta_against_basis=True, expect_fs_hash=False):
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
847
        """Perform a miniature commit looking for record entry results.
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
848
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
849
        :param tree: The tree to commit.
850
        :param name: The path in the basis tree of the tree being committed.
851
        :param new_name: The path in the tree being committed.
852
        :param records_version: True if the commit of new_name is expected to
853
            record a new version.
854
        :param delta_against_basis: True of the commit of new_name is expected
855
            to have a delta against the basis.
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
856
        :param expect_fs_hash: True or false to indicate whether we expect a
857
            file hash to be returned from the record_entry_contents call.
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
858
        """
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
859
        tree.lock_write()
860
        try:
861
            # mini manual commit here so we can check the return of
862
            # record_entry_contents.
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
863
            parent_ids = tree.get_parent_ids()
864
            builder = tree.branch.get_commit_builder(parent_ids)
5707.1.1 by Jelmer Vernooij
Properly try/except.
865
            try:
5718.4.3 by Jelmer Vernooij
Skip record_entry_contents-using tests for commit builders that don't support it.
866
                if not builder.supports_record_entry_contents:
867
                    raise tests.TestNotApplicable("CommitBuilder doesn't "
868
                        "support record_entry_contents")
5707.1.1 by Jelmer Vernooij
Properly try/except.
869
                parent_tree = tree.basis_tree()
870
                parent_tree.lock_read()
871
                self.addCleanup(parent_tree.unlock)
872
                parent_invs = [parent_tree.inventory]
873
                for parent_id in parent_ids[1:]:
874
                    parent_invs.append(tree.branch.repository.revision_tree(
875
                        parent_id).inventory)
876
                # root
877
                builder.record_entry_contents(
878
                    inventory.make_entry('directory', '', None,
879
                        tree.get_root_id()), parent_invs, '', tree,
880
                        tree.path_content_summary(''))
881
                def commit_id(file_id):
882
                    old_ie = tree.inventory[file_id]
883
                    path = tree.id2path(file_id)
884
                    ie = inventory.make_entry(tree.kind(file_id), old_ie.name,
885
                        old_ie.parent_id, file_id)
886
                    content_summary = tree.path_content_summary(path)
887
                    if content_summary[0] == 'tree-reference':
888
                        content_summary = content_summary[:3] + (
889
                            tree.get_reference_revision(file_id),)
890
                    return builder.record_entry_contents(ie, parent_invs, path,
891
                        tree, content_summary)
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
892
5707.1.1 by Jelmer Vernooij
Properly try/except.
893
                file_id = tree.path2id(new_name)
894
                parent_id = tree.inventory[file_id].parent_id
895
                if parent_id != tree.get_root_id():
896
                    commit_id(parent_id)
897
                # because a change of some sort is meant to have occurred,
898
                # recording the entry must return True.
899
                delta, version_recorded, fs_hash = commit_id(file_id)
900
                if records_version:
901
                    self.assertTrue(version_recorded)
902
                else:
903
                    self.assertFalse(version_recorded)
904
                if expect_fs_hash:
905
                    tree_file_stat = tree.get_file_with_stat(file_id)
906
                    tree_file_stat[0].close()
907
                    self.assertEqual(2, len(fs_hash))
908
                    self.assertEqual(tree.get_file_sha1(file_id), fs_hash[0])
909
                    self.assertEqualStat(tree_file_stat[1], fs_hash[1])
910
                else:
911
                    self.assertEqual(None, fs_hash)
912
                new_entry = builder.new_inventory[file_id]
913
                if delta_against_basis:
914
                    expected_delta = (name, new_name, file_id, new_entry)
915
                    # The delta should be recorded
916
                    self.assertEqual(expected_delta, builder._basis_delta[-1])
917
                else:
918
                    expected_delta = None
919
                self.assertEqual(expected_delta, delta)
920
                builder.finish_inventory()
921
            except:
922
                builder.abort()
923
                raise
924
            else:
925
                rev2 = builder.commit('')
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
926
        except:
927
            tree.unlock()
928
            raise
4245.1.1 by Ian Clatworthy
minor test clean-ups & _reconcile_pack API
929
        try:
930
            tree.set_parent_ids([rev2])
931
        finally:
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
932
            tree.unlock()
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
933
        return rev2
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
934
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
935
    def mini_commit_record_iter_changes(self, tree, name, new_name,
936
        records_version=True, delta_against_basis=True, expect_fs_hash=False):
937
        """Perform a miniature commit looking for record entry results.
938
939
        This version uses the record_iter_changes interface.
940
        
941
        :param tree: The tree to commit.
942
        :param name: The path in the basis tree of the tree being committed.
943
        :param new_name: The path in the tree being committed.
944
        :param records_version: True if the commit of new_name is expected to
945
            record a new version.
946
        :param delta_against_basis: True of the commit of new_name is expected
947
            to have a delta against the basis.
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
948
        :param expect_fs_hash: If true, looks for a fs hash output from
949
            record_iter_changes.
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
950
        """
951
        tree.lock_write()
952
        try:
953
            # mini manual commit here so we can check the return of
954
            # record_entry_contents.
955
            parent_ids = tree.get_parent_ids()
956
            builder = tree.branch.get_commit_builder(parent_ids)
957
            parent_tree = tree.basis_tree()
958
            parent_tree.lock_read()
959
            self.addCleanup(parent_tree.unlock)
5856.1.2 by Jelmer Vernooij
Delay accessing inventory in tests until necessary.
960
            parent_trees = [parent_tree]
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
961
            for parent_id in parent_ids[1:]:
5856.1.2 by Jelmer Vernooij
Delay accessing inventory in tests until necessary.
962
                parent_trees.append(tree.branch.repository.revision_tree(
963
                    parent_id))
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
964
            changes = list(tree.iter_changes(parent_tree))
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
965
            result = list(builder.record_iter_changes(tree, parent_ids[0],
966
                changes))
967
            file_id = tree.path2id(new_name)
968
            if expect_fs_hash:
969
                tree_file_stat = tree.get_file_with_stat(file_id)
970
                tree_file_stat[0].close()
971
                self.assertLength(1, result)
972
                result = result[0]
973
                self.assertEqual(result[:2], (file_id, new_name))
974
                self.assertEqual(result[2][0], tree.get_file_sha1(file_id))
975
                self.assertEqualStat(result[2][1], tree_file_stat[1])
976
            else:
977
                self.assertEqual([], result)
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
978
            delta = builder._basis_delta
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
979
            delta_dict = dict((change[2], change) for change in delta)
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
980
            version_recorded = (file_id in delta_dict and
981
                delta_dict[file_id][3] is not None and
982
                delta_dict[file_id][3].revision == builder._new_revision_id)
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
983
            if records_version:
984
                self.assertTrue(version_recorded)
985
            else:
986
                self.assertFalse(version_recorded)
4789.27.2 by John Arbash Meinel
Add some tests that the record-iter-changes is setting inv_sha1 correctly.
987
            self.assertIs(None, builder.new_inventory)
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
988
            builder.finish_inventory()
5718.4.4 by Jelmer Vernooij
Only check .inventories if present.
989
            if tree.branch.repository._format.supports_full_versioned_files:
990
                inv_key = (builder._new_revision_id,)
991
                inv_sha1 = tree.branch.repository.inventories.get_sha1s(
992
                                [inv_key])[inv_key]
993
                self.assertEqual(inv_sha1, builder.inv_sha1)
4789.27.4 by John Arbash Meinel
Robert says that self.new_inventory shouldn't be set.
994
            self.assertIs(None, builder.new_inventory)
6362.5.5 by Jelmer Vernooij
Don't access revision tree before commit.
995
            rev2 = builder.commit('')
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
996
            new_inventory = builder.revision_tree().inventory
997
            new_entry = new_inventory[file_id]
998
            if delta_against_basis:
999
                expected_delta = (name, new_name, file_id, new_entry)
1000
                self.assertEqual(expected_delta, delta_dict[file_id])
1001
            else:
1002
                expected_delta = None
1003
                self.assertFalse(version_recorded)
1004
            tree.set_parent_ids([rev2])
1005
        except:
1006
            builder.abort()
1007
            tree.unlock()
1008
            raise
1009
        else:
1010
            tree.unlock()
1011
        return rev2
1012
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
1013
    def assertFileGraph(self, expected_graph, tree, tip):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1014
        # all the changes that have occured should be in the ancestry
1015
        # (closest to a public per-file graph API we have today)
1016
        tree.lock_read()
1017
        self.addCleanup(tree.unlock)
5815.5.9 by Jelmer Vernooij
Remove dependencies on texts.
1018
        g = dict(tree.branch.repository.get_file_graph().iter_ancestry([tip]))
5010.2.24 by Vincent Ladeuil
Fix imports in per_repository/test_commit_builder.py.
1019
        self.assertEqual(expected_graph, g)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1020
1021
    def test_last_modified_revision_after_content_file_changes(self):
1022
        # altering a file changes the last modified.
1023
        tree = self.make_branch_and_tree('.')
1024
        self.build_tree(['file'])
1025
        def change_file():
1026
            tree.put_file_bytes_non_atomic('fileid', 'new content')
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1027
        self._add_commit_change_check_changed(tree, 'file', change_file,
1028
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1029
3775.2.17 by Robert Collins
CommitBuilder.record_iter_changes handles changed files.
1030
    def test_last_modified_revision_after_content_file_changes_ric(self):
1031
        # altering a file changes the last modified.
1032
        tree = self.make_branch_and_tree('.')
1033
        self.build_tree(['file'])
1034
        def change_file():
1035
            tree.put_file_bytes_non_atomic('fileid', 'new content')
1036
        self._add_commit_change_check_changed(tree, 'file', change_file,
1037
            expect_fs_hash=True,
1038
            mini_commit=self.mini_commit_record_iter_changes)
1039
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1040
    def test_last_modified_revision_after_content_link_changes(self):
1041
        # changing a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1042
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1043
        tree = self.make_branch_and_tree('.')
1044
        os.symlink('target', 'link')
1045
        def change_link():
1046
            os.unlink('link')
1047
            os.symlink('newtarget', 'link')
1048
        self._add_commit_change_check_changed(tree, 'link', change_link)
1049
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
1050
    def _test_last_mod_rev_after_content_link_changes_ric(
1051
        self, link, target, newtarget, file_id=None):
1052
        if file_id is None:
1053
            file_id = link
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
1054
        # changing a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1055
        self.requireFeature(features.SymlinkFeature)
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
1056
        tree = self.make_branch_and_tree('.')
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
1057
        os.symlink(target, link)
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
1058
        def change_link():
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
1059
            os.unlink(link)
1060
            os.symlink(newtarget, link)
1061
        self._add_commit_change_check_changed(
1062
            tree, link, change_link,
1063
            mini_commit=self.mini_commit_record_iter_changes,
1064
            file_id=file_id)
1065
1066
    def test_last_modified_rev_after_content_link_changes_ric(self):
1067
        self._test_last_mod_rev_after_content_link_changes_ric(
1068
            'link', 'target', 'newtarget')
1069
1070
    def test_last_modified_rev_after_content_unicode_link_changes_ric(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1071
        self.requireFeature(features.UnicodeFilenameFeature)
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
1072
        self._test_last_mod_rev_after_content_link_changes_ric(
1073
            u'li\u1234nk', u'targ\N{Euro Sign}t', u'n\N{Euro Sign}wtarget',
1074
1075
            file_id=u'li\u1234nk'.encode('UTF-8'))
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
1076
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1077
    def _commit_sprout(self, tree, name):
1078
        tree.add([name], [name + 'id'])
1079
        rev_id = tree.commit('')
1080
        return rev_id, tree.bzrdir.sprout('t2').open_workingtree()
1081
1082
    def _rename_in_tree(self, tree, name):
1083
        tree.rename_one(name, 'new_' + name)
1084
        return tree.commit('')
1085
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
1086
    def _commit_sprout_rename_merge(self, tree1, name, expect_fs_hash=False,
1087
        mini_commit=None):
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1088
        """Do a rename in both trees."""
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1089
        rev1, tree2 = self._commit_sprout(tree1, name)
1090
        # change both sides equally
1091
        rev2 = self._rename_in_tree(tree1, name)
1092
        rev3 = self._rename_in_tree(tree2, name)
1093
        tree1.merge_from_branch(tree2.branch)
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
1094
        if mini_commit is None:
1095
            mini_commit = self.mini_commit
1096
        rev4 = mini_commit(tree1, 'new_' + name, 'new_' + name,
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1097
            expect_fs_hash=expect_fs_hash)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1098
        tree3, = self._get_revtrees(tree1, [rev4])
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
1099
        self.assertEqual(rev4, tree3.get_file_revision(name + 'id'))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
1100
        file_id = name + 'id'
1101
        expected_graph = {}
1102
        expected_graph[(file_id, rev1)] = ()
1103
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
1104
        expected_graph[(file_id, rev3)] = ((file_id, rev1),)
1105
        expected_graph[(file_id, rev4)] = ((file_id, rev2), (file_id, rev3),)
1106
        self.assertFileGraph(expected_graph, tree1, (file_id, rev4))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1107
1108
    def test_last_modified_revision_after_merge_dir_changes(self):
1109
        # merge a dir changes the last modified.
1110
        tree1 = self.make_branch_and_tree('t1')
1111
        self.build_tree(['t1/dir/'])
1112
        self._commit_sprout_rename_merge(tree1, 'dir')
1113
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
1114
    def test_last_modified_revision_after_merge_dir_changes_ric(self):
1115
        # merge a dir changes the last modified.
1116
        tree1 = self.make_branch_and_tree('t1')
1117
        self.build_tree(['t1/dir/'])
1118
        self._commit_sprout_rename_merge(tree1, 'dir',
1119
            mini_commit=self.mini_commit_record_iter_changes)
1120
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1121
    def test_last_modified_revision_after_merge_file_changes(self):
1122
        # merge a file changes the last modified.
1123
        tree1 = self.make_branch_and_tree('t1')
1124
        self.build_tree(['t1/file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1125
        self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1126
3775.2.20 by Robert Collins
CommitBuilder.record_iter_changes handles merged files.
1127
    def test_last_modified_revision_after_merge_file_changes_ric(self):
1128
        # merge a file changes the last modified.
1129
        tree1 = self.make_branch_and_tree('t1')
1130
        self.build_tree(['t1/file'])
1131
        self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True,
1132
            mini_commit=self.mini_commit_record_iter_changes)
1133
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1134
    def test_last_modified_revision_after_merge_link_changes(self):
1135
        # merge a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1136
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1137
        tree1 = self.make_branch_and_tree('t1')
1138
        os.symlink('target', 't1/link')
1139
        self._commit_sprout_rename_merge(tree1, 'link')
1140
3775.2.21 by Robert Collins
CommitBuilder.record_iter_changes handles merged symlinks.
1141
    def test_last_modified_revision_after_merge_link_changes_ric(self):
1142
        # merge a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1143
        self.requireFeature(features.SymlinkFeature)
3775.2.21 by Robert Collins
CommitBuilder.record_iter_changes handles merged symlinks.
1144
        tree1 = self.make_branch_and_tree('t1')
1145
        os.symlink('target', 't1/link')
1146
        self._commit_sprout_rename_merge(tree1, 'link',
1147
            mini_commit=self.mini_commit_record_iter_changes)
1148
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
1149
    def _commit_sprout_rename_merge_converged(self, tree1, name,
1150
        mini_commit=None):
1151
        # Make a merge which just incorporates a change from a branch:
1152
        # The per-file graph is straight line, and no alteration occurs
1153
        # in the inventory.
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
1154
        # Part 1: change in the merged branch.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1155
        rev1, tree2 = self._commit_sprout(tree1, name)
1156
        # change on the other side to merge back
1157
        rev2 = self._rename_in_tree(tree2, name)
1158
        tree1.merge_from_branch(tree2.branch)
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
1159
        if mini_commit is None:
1160
            mini_commit = self.mini_commit
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
1161
        def _check_graph(in_tree, changed_in_tree):
1162
            rev3 = mini_commit(in_tree, name, 'new_' + name, False,
1163
                delta_against_basis=changed_in_tree)
1164
            tree3, = self._get_revtrees(in_tree, [rev2])
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
1165
            self.assertEqual(rev2, tree3.get_file_revision(name + 'id'))
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
1166
            file_id = name + 'id'
1167
            expected_graph = {}
1168
            expected_graph[(file_id, rev1)] = ()
1169
            expected_graph[(file_id, rev2)] = ((file_id, rev1),)
1170
            self.assertFileGraph(expected_graph, in_tree, (file_id, rev2))
1171
        _check_graph(tree1, True)
1172
        # Part 2: change in the merged into branch - we use tree2 that has a
1173
        # change to name, branch tree1 and give it an unrelated change, then
1174
        # merge that to t2.
1175
        other_tree = tree1.bzrdir.sprout('t3').open_workingtree()
1176
        other_rev = other_tree.commit('')
1177
        tree2.merge_from_branch(other_tree.branch)
1178
        _check_graph(tree2, False)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1179
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1180
    def _commit_sprout_make_merge(self, tree1, make, mini_commit=None):
1181
        # Make a merge which incorporates the addition of a new object to
1182
        # another branch. The per-file graph shows no additional change
1183
        # in the merge because its a straight line.
1184
        rev1 = tree1.commit('')
1185
        tree2 = tree1.bzrdir.sprout('t2').open_workingtree()
1186
        # make and commit on the other side to merge back
1187
        make('t2/name')
1188
        file_id = 'nameid'
1189
        tree2.add(['name'], [file_id])
1190
        rev2 = tree2.commit('')
1191
        tree1.merge_from_branch(tree2.branch)
1192
        if mini_commit is None:
1193
            mini_commit = self.mini_commit
1194
        rev3 = mini_commit(tree1, None, 'name', False)
1195
        tree3, = self._get_revtrees(tree1, [rev2])
1196
        # in rev2, name should be only changed in rev2
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
1197
        self.assertEqual(rev2, tree3.get_file_revision(file_id))
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1198
        expected_graph = {}
1199
        expected_graph[(file_id, rev2)] = ()
1200
        self.assertFileGraph(expected_graph, tree1, (file_id, rev2))
1201
1202
    def test_last_modified_revision_after_converged_merge_dir_unchanged(self):
1203
        # merge a dir that changed preserves the last modified.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1204
        tree1 = self.make_branch_and_tree('t1')
1205
        self.build_tree(['t1/dir/'])
1206
        self._commit_sprout_rename_merge_converged(tree1, 'dir')
1207
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1208
    def test_last_modified_revision_after_converged_merge_dir_unchanged_ric(self):
1209
        # merge a dir that changed preserves the last modified.
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
1210
        tree1 = self.make_branch_and_tree('t1')
1211
        self.build_tree(['t1/dir/'])
1212
        self._commit_sprout_rename_merge_converged(tree1, 'dir',
1213
            mini_commit=self.mini_commit_record_iter_changes)
1214
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1215
    def test_last_modified_revision_after_converged_merge_file_unchanged(self):
1216
        # merge a file that changed preserves the last modified.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1217
        tree1 = self.make_branch_and_tree('t1')
1218
        self.build_tree(['t1/file'])
1219
        self._commit_sprout_rename_merge_converged(tree1, 'file')
1220
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1221
    def test_last_modified_revision_after_converged_merge_file_unchanged_ric(self):
1222
        # merge a file that changed preserves the last modified.
3775.2.23 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch files.
1223
        tree1 = self.make_branch_and_tree('t1')
1224
        self.build_tree(['t1/file'])
1225
        self._commit_sprout_rename_merge_converged(tree1, 'file',
1226
            mini_commit=self.mini_commit_record_iter_changes)
1227
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1228
    def test_last_modified_revision_after_converged_merge_link_unchanged(self):
1229
        # merge a link that changed preserves the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1230
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1231
        tree1 = self.make_branch_and_tree('t1')
1232
        os.symlink('target', 't1/link')
1233
        self._commit_sprout_rename_merge_converged(tree1, 'link')
1234
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1235
    def test_last_modified_revision_after_converged_merge_link_unchanged_ric(self):
1236
        # merge a link that changed preserves the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1237
        self.requireFeature(features.SymlinkFeature)
3775.2.24 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch symlinks.
1238
        tree1 = self.make_branch_and_tree('t1')
1239
        os.symlink('target', 't1/link')
1240
        self._commit_sprout_rename_merge_converged(tree1, 'link',
1241
            mini_commit=self.mini_commit_record_iter_changes)
1242
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1243
    def test_last_modified_revision_after_merge_new_dir_unchanged(self):
1244
        # merge a new dir does not change the last modified.
1245
        tree1 = self.make_branch_and_tree('t1')
1246
        self._commit_sprout_make_merge(tree1, self.make_dir)
1247
1248
    def test_last_modified_revision_after_merge_new_dir_unchanged_ric(self):
1249
        # merge a new dir does not change the last modified.
1250
        tree1 = self.make_branch_and_tree('t1')
1251
        self._commit_sprout_make_merge(tree1, self.make_dir,
1252
            mini_commit=self.mini_commit_record_iter_changes)
1253
1254
    def test_last_modified_revision_after_merge_new_file_unchanged(self):
1255
        # merge a new file does not change the last modified.
1256
        tree1 = self.make_branch_and_tree('t1')
1257
        self._commit_sprout_make_merge(tree1, self.make_file)
1258
1259
    def test_last_modified_revision_after_merge_new_file_unchanged_ric(self):
1260
        # merge a new file does not change the last modified.
1261
        tree1 = self.make_branch_and_tree('t1')
1262
        self._commit_sprout_make_merge(tree1, self.make_file,
1263
            mini_commit=self.mini_commit_record_iter_changes)
1264
1265
    def test_last_modified_revision_after_merge_new_link_unchanged(self):
1266
        # merge a new link does not change the last modified.
1267
        tree1 = self.make_branch_and_tree('t1')
1268
        self._commit_sprout_make_merge(tree1, self.make_link)
1269
1270
    def test_last_modified_revision_after_merge_new_link_unchanged_ric(self):
1271
        # merge a new link does not change the last modified.
1272
        tree1 = self.make_branch_and_tree('t1')
1273
        self._commit_sprout_make_merge(tree1, self.make_link,
1274
            mini_commit=self.mini_commit_record_iter_changes)
1275
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1276
    def make_dir(self, name):
1277
        self.build_tree([name + '/'])
1278
1279
    def make_file(self, name):
1280
        self.build_tree([name])
1281
1282
    def make_link(self, name):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1283
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1284
        os.symlink('target', name)
1285
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
1286
    def make_reference(self, name):
1287
        tree = self.make_branch_and_tree(name, format='1.9-rich-root')
1288
        tree.commit('foo')
1289
        return tree
1290
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
1291
    def _check_kind_change(self, make_before, make_after, expect_fs_hash=False,
1292
        mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1293
        tree = self.make_branch_and_tree('.')
1294
        path = 'name'
1295
        make_before(path)
2831.5.2 by Vincent Ladeuil
Review feedback.
1296
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1297
        def change_kind():
6164.2.3 by Jelmer Vernooij
Use rmtree, since some vcses include control directories in every directory.
1298
            if osutils.file_kind(path) == "directory":
1299
                osutils.rmtree(path)
1300
            else:
1301
                osutils.delete_any(path)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1302
            make_after(path)
2831.5.2 by Vincent Ladeuil
Review feedback.
1303
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1304
        self._add_commit_change_check_changed(tree, path, change_kind,
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
1305
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1306
1307
    def test_last_modified_dir_file(self):
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1308
        self._check_kind_change(self.make_dir, self.make_file,
1309
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1310
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
1311
    def test_last_modified_dir_file_ric(self):
6217.2.1 by Jelmer Vernooij
Allow tree implementations to not support kind changes.
1312
        try:
1313
            self._check_kind_change(self.make_dir, self.make_file,
1314
                expect_fs_hash=True,
1315
                mini_commit=self.mini_commit_record_iter_changes)
1316
        except errors.UnsupportedKindChange:
1317
            raise tests.TestSkipped(
1318
                "tree does not support changing entry kind from "
1319
                "directory to file")
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
1320
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1321
    def test_last_modified_dir_link(self):
1322
        self._check_kind_change(self.make_dir, self.make_link)
1323
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
1324
    def test_last_modified_dir_link_ric(self):
6217.2.1 by Jelmer Vernooij
Allow tree implementations to not support kind changes.
1325
        try:
1326
            self._check_kind_change(self.make_dir, self.make_link,
1327
                mini_commit=self.mini_commit_record_iter_changes)
1328
        except errors.UnsupportedKindChange:
1329
            raise tests.TestSkipped(
1330
                "tree does not support changing entry kind from "
1331
                "directory to link")
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
1332
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1333
    def test_last_modified_link_file(self):
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1334
        self._check_kind_change(self.make_link, self.make_file,
1335
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1336
3775.2.26 by Robert Collins
CommitBuilder.record_iter_changes handles links becomes directories and files.
1337
    def test_last_modified_link_file_ric(self):
1338
        self._check_kind_change(self.make_link, self.make_file,
1339
            expect_fs_hash=True,
1340
            mini_commit=self.mini_commit_record_iter_changes)
1341
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1342
    def test_last_modified_link_dir(self):
1343
        self._check_kind_change(self.make_link, self.make_dir)
1344
3775.2.26 by Robert Collins
CommitBuilder.record_iter_changes handles links becomes directories and files.
1345
    def test_last_modified_link_dir_ric(self):
1346
        self._check_kind_change(self.make_link, self.make_dir,
1347
            mini_commit=self.mini_commit_record_iter_changes)
1348
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1349
    def test_last_modified_file_dir(self):
1350
        self._check_kind_change(self.make_file, self.make_dir)
1351
3775.2.27 by Robert Collins
CommitBuilder.record_iter_changes handles files becoming directories and links.
1352
    def test_last_modified_file_dir_ric(self):
1353
        self._check_kind_change(self.make_file, self.make_dir,
1354
            mini_commit=self.mini_commit_record_iter_changes)
1355
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1356
    def test_last_modified_file_link(self):
1357
        self._check_kind_change(self.make_file, self.make_link)
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
1358
3775.2.27 by Robert Collins
CommitBuilder.record_iter_changes handles files becoming directories and links.
1359
    def test_last_modified_file_link_ric(self):
1360
        self._check_kind_change(self.make_file, self.make_link,
1361
            mini_commit=self.mini_commit_record_iter_changes)
3775.2.28 by Robert Collins
Merge .dev.
1362
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
1363
    def test_get_commit_builder_with_invalid_revprops(self):
1364
        branch = self.make_branch('.')
1365
        branch.repository.lock_write()
1366
        self.addCleanup(branch.repository.unlock)
1367
        self.assertRaises(ValueError, branch.repository.get_commit_builder,
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
1368
            branch, [], branch.get_config_stack(),
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
1369
            revprops={'invalid': u'property\rwith\r\ninvalid chars'})
1370
1371
    def test_commit_builder_commit_with_invalid_message(self):
1372
        branch = self.make_branch('.')
1373
        branch.repository.lock_write()
1374
        self.addCleanup(branch.repository.unlock)
1375
        builder = branch.repository.get_commit_builder(branch, [],
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
1376
            branch.get_config_stack())
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
1377
        self.addCleanup(branch.repository.abort_write_group)
1378
        self.assertRaises(ValueError, builder.commit,
1379
            u'Invalid\r\ncommit message\r\n')
4595.4.2 by Robert Collins
Disable commit builders on stacked repositories.
1380
5485.4.2 by Martin
Move guard to CommitBuilder.__init__ and test to bt.per_repository
1381
    def test_non_ascii_str_committer_rejected(self):
1382
        """Ensure an error is raised on a non-ascii byte string committer"""
1383
        branch = self.make_branch('.')
1384
        branch.repository.lock_write()
1385
        self.addCleanup(branch.repository.unlock)
1386
        self.assertRaises(UnicodeDecodeError,
1387
            branch.repository.get_commit_builder,
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
1388
            branch, [], branch.get_config_stack(),
5485.4.2 by Martin
Move guard to CommitBuilder.__init__ and test to bt.per_repository
1389
            committer="Erik B\xe5gfors <erik@example.com>")
1390
4595.4.2 by Robert Collins
Disable commit builders on stacked repositories.
1391
    def test_stacked_repositories_reject_commit_builder(self):
1392
        # As per bug 375013, committing to stacked repositories is currently
5557.1.17 by John Arbash Meinel
Fix the test case that was checking we refused to create a commit_builder
1393
        # broken if we aren't in a chk repository. So old repositories with
1394
        # fallbacks refuse to hand out a commit builder.
4595.4.2 by Robert Collins
Disable commit builders on stacked repositories.
1395
        repo_basis = self.make_repository('basis')
1396
        branch = self.make_branch('local')
1397
        repo_local = branch.repository
1398
        try:
1399
            repo_local.add_fallback_repository(repo_basis)
1400
        except errors.UnstackableRepositoryFormat:
1401
            raise tests.TestNotApplicable("not a stackable format.")
5557.1.17 by John Arbash Meinel
Fix the test case that was checking we refused to create a commit_builder
1402
        self.addCleanup(repo_local.lock_write().unlock)
1403
        if not repo_local._format.supports_chks:
1404
            self.assertRaises(errors.BzrError, repo_local.get_commit_builder,
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
1405
                branch, [], branch.get_config_stack())
5557.1.17 by John Arbash Meinel
Fix the test case that was checking we refused to create a commit_builder
1406
        else:
1407
            builder = repo_local.get_commit_builder(branch, [],
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
1408
                                                    branch.get_config_stack())
5557.1.17 by John Arbash Meinel
Fix the test case that was checking we refused to create a commit_builder
1409
            builder.abort()
5050.18.1 by Aaron Bentley
CommitBuilder user committer, not username in revision-id.
1410
1411
    def test_committer_no_username(self):
1412
        # Ensure that when no username is available but a committer is
1413
        # supplied, commit works.
5570.3.9 by Vincent Ladeuil
More use cases for overrideEnv, _cleanEnvironment *may* contain too much variables now.
1414
        self.overrideEnv('EMAIL', None)
5609.31.2 by mbp at sourcefrog
Also turn off whoami inference in per_repository tests
1415
        self.overrideEnv('BZR_EMAIL', None)
1416
        # Also, make sure that it's not inferred from mailname.
1417
        self.overrideAttr(config, '_auto_user_id',
1418
            lambda: (None, None))
5050.18.1 by Aaron Bentley
CommitBuilder user committer, not username in revision-id.
1419
        tree = self.make_branch_and_tree(".")
1420
        tree.lock_write()
1421
        try:
1422
            # Make sure no username is available.
1423
            self.assertRaises(errors.NoWhoami, tree.branch.get_commit_builder,
1424
                              [])
1425
            builder = tree.branch.get_commit_builder(
1426
                [], committer='me@example.com')
1427
            try:
1428
                list(builder.record_iter_changes(tree, tree.last_revision(),
1429
                    tree.iter_changes(tree.basis_tree())))
1430
                builder.finish_inventory()
1431
            except:
1432
                builder.abort()
1433
                raise
1434
            repo = tree.branch.repository
1435
            repo.commit_write_group()
1436
        finally:
1437
            tree.unlock()