~bzr-pqm/bzr/bzr.dev

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