/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2006 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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
from errno import EISDIR
20
import os
21
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
22
from bzrlib import inventory
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.
23
from bzrlib.errors import NonAsciiRevisionId, CannotSetRevisionId
1740.3.1 by Jelmer Vernooij
Introduce and use CommitBuilder objects.
24
from bzrlib.repository import CommitBuilder
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
25
from bzrlib import tests
1740.3.1 by Jelmer Vernooij
Introduce and use CommitBuilder objects.
26
from bzrlib.tests.repository_implementations.test_repository import TestCaseWithRepository
27
28
29
class TestCommitBuilder(TestCaseWithRepository):
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
30
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
31
    def test_get_commit_builder(self):
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
32
        branch = self.make_branch('.')
33
        branch.repository.lock_write()
34
        builder = branch.repository.get_commit_builder(
35
            branch, [], branch.get_config())
1740.3.1 by Jelmer Vernooij
Introduce and use CommitBuilder objects.
36
        self.assertIsInstance(builder, CommitBuilder)
2805.6.1 by Robert Collins
Set random_revid on CommitBuilder when a commit generated its own revision id.
37
        self.assertTrue(builder.random_revid)
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
38
        branch.repository.commit_write_group()
39
        branch.repository.unlock()
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
40
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
41
    def record_root(self, builder, tree):
42
        if builder.record_root_entry is True:
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
43
            tree.lock_read()
44
            try:
45
                ie = tree.inventory.root
46
            finally:
47
                tree.unlock()
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
48
            parent_tree = tree.branch.repository.revision_tree(None)
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
49
            parent_invs = []
2776.4.4 by Robert Collins
Move content summary generation outside of record_entry_contents.
50
            builder.record_entry_contents(ie, parent_invs, '', tree,
51
                tree.path_content_summary(''))
1731.1.33 by Aaron Bentley
Revert no-special-root changes
52
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
53
    def test_finish_inventory(self):
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
54
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
55
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
56
        try:
57
            builder = tree.branch.get_commit_builder([])
58
            self.record_root(builder, tree)
59
            builder.finish_inventory()
60
            tree.branch.repository.commit_write_group()
61
        finally:
62
            tree.unlock()
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
63
2749.3.1 by Jelmer Vernooij
Add CommitBuilder.abort().
64
    def test_abort(self):
65
        tree = self.make_branch_and_tree(".")
66
        tree.lock_write()
67
        try:
68
            builder = tree.branch.get_commit_builder([])
69
            self.record_root(builder, tree)
70
            builder.finish_inventory()
71
            builder.abort()
72
        finally:
73
            tree.unlock()
74
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
75
    def test_commit_message(self):
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
76
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
77
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
78
        try:
79
            builder = tree.branch.get_commit_builder([])
80
            self.record_root(builder, tree)
81
            builder.finish_inventory()
82
            rev_id = builder.commit('foo bar blah')
83
        finally:
84
            tree.unlock()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
85
        rev = tree.branch.repository.get_revision(rev_id)
86
        self.assertEqual('foo bar blah', rev.message)
87
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
88
    def test_commit_with_revision_id(self):
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
89
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
90
        tree.lock_write()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
91
        try:
2617.6.8 by Robert Collins
Review feedback and documentation.
92
            # use a unicode revision id to test more corner cases.
93
            # The repository layer is meant to handle this.
94
            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.
95
            try:
2617.6.8 by Robert Collins
Review feedback and documentation.
96
                try:
97
                    builder = tree.branch.get_commit_builder([],
98
                        revision_id=revision_id)
99
                except NonAsciiRevisionId:
100
                    revision_id = 'abc'
101
                    builder = tree.branch.get_commit_builder([],
102
                        revision_id=revision_id)
103
            except CannotSetRevisionId:
104
                # This format doesn't support supplied revision ids
105
                return
2805.6.1 by Robert Collins
Set random_revid on CommitBuilder when a commit generated its own revision id.
106
            self.assertFalse(builder.random_revid)
2617.6.8 by Robert Collins
Review feedback and documentation.
107
            self.record_root(builder, tree)
108
            builder.finish_inventory()
109
            self.assertEqual(revision_id, builder.commit('foo bar'))
110
        finally:
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
111
            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.
112
        self.assertTrue(tree.branch.repository.has_revision(revision_id))
113
        # the revision id must be set on the inventory when saving it. This
114
        # does not precisely test that - a repository that wants to can add it
115
        # on deserialisation, but thats all the current contract guarantees
116
        # anyway.
117
        self.assertEqual(revision_id,
118
            tree.branch.repository.get_inventory(revision_id).revision_id)
1740.3.8 by Jelmer Vernooij
Move make_revision() to commit builder.
119
1910.2.8 by Aaron Bentley
Fix commit_builder when root not passed to record_entry_contents
120
    def test_commit_without_root(self):
121
        """This should cause a deprecation warning, not an assertion failure"""
122
        tree = self.make_branch_and_tree(".")
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
123
        tree.lock_write()
124
        try:
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
125
            if tree.branch.repository.supports_rich_root():
126
                raise tests.TestSkipped('Format requires root')
127
            self.build_tree(['foo'])
128
            tree.add('foo', 'foo-id')
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
129
            entry = tree.inventory['foo-id']
130
            builder = tree.branch.get_commit_builder([])
131
            self.callDeprecated(['Root entry should be supplied to'
132
                ' record_entry_contents, as of bzr 0.10.'],
2776.4.4 by Robert Collins
Move content summary generation outside of record_entry_contents.
133
                builder.record_entry_contents, entry, [], 'foo', tree,
134
                    tree.path_content_summary('foo'))
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
135
            builder.finish_inventory()
136
            rev_id = builder.commit('foo bar')
137
        finally:
138
            tree.unlock()
1910.2.8 by Aaron Bentley
Fix commit_builder when root not passed to record_entry_contents
139
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
140
    def test_commit(self):
1740.3.8 by Jelmer Vernooij
Move make_revision() to commit builder.
141
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
142
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
143
        try:
144
            builder = tree.branch.get_commit_builder([])
145
            self.record_root(builder, tree)
146
            builder.finish_inventory()
147
            rev_id = builder.commit('foo bar')
148
        finally:
149
            tree.unlock()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
150
        self.assertNotEqual(None, rev_id)
151
        self.assertTrue(tree.branch.repository.has_revision(rev_id))
1757.1.2 by Robert Collins
Bugfix CommitBuilders recording of the inventory revision id.
152
        # the revision id must be set on the inventory when saving it. This does not
153
        # precisely test that - a repository that wants to can add it on deserialisation,
154
        # but thats all the current contract guarantees anyway.
155
        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
156
2041.1.5 by John Arbash Meinel
CommitBuilder.get_tree => CommitBuilder.revision_tree
157
    def test_revision_tree(self):
2041.1.1 by John Arbash Meinel
Add a 'get_tree()' call that returns a RevisionTree for the newly committed tree
158
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
159
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
160
        try:
161
            builder = tree.branch.get_commit_builder([])
162
            self.record_root(builder, tree)
163
            builder.finish_inventory()
164
            rev_id = builder.commit('foo bar')
165
        finally:
166
            tree.unlock()
2041.1.5 by John Arbash Meinel
CommitBuilder.get_tree => CommitBuilder.revision_tree
167
        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
168
        # Just a couple simple tests to ensure that it actually follows
169
        # the RevisionTree api.
170
        self.assertEqual(rev_id, rev_tree.get_revision_id())
171
        self.assertEqual([], rev_tree.get_parent_ids())
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
172
173
    def test_root_entry_has_revision(self):
174
        # test the root revision created and put in the basis
175
        # has the right rev id.
176
        tree = self.make_branch_and_tree('.')
177
        rev_id = tree.commit('message')
178
        basis_tree = tree.basis_tree()
179
        basis_tree.lock_read()
180
        self.addCleanup(basis_tree.unlock)
181
        self.assertEqual(rev_id, basis_tree.inventory.root.revision)
182
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
183
    def _get_revtrees(self, tree, revision_ids):
184
        trees = list(tree.branch.repository.revision_trees(revision_ids))
185
        for tree in trees:
186
            tree.lock_read()
187
            self.addCleanup(tree.unlock)
188
        return trees
189
190
    def test_last_modified_revision_after_commit_root_unchanged(self):
191
        # commiting without changing the root does not change the 
192
        # last modified except on non-rich-root-repositories.
193
        tree = self.make_branch_and_tree('.')
194
        rev1 = tree.commit('')
195
        rev2 = tree.commit('')
196
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
197
        self.assertEqual(rev1, tree1.inventory.root.revision)
198
        if tree.branch.repository.supports_rich_root():
199
            self.assertEqual(rev1, tree2.inventory.root.revision)
200
        else:
201
            self.assertEqual(rev2, tree2.inventory.root.revision)
202
203
    def _add_commit_check_unchanged(self, tree, name):
204
        tree.add([name], [name + 'id'])
205
        rev1 = tree.commit('')
206
        rev2 = tree.commit('')
207
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
208
        self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
209
        self.assertEqual(rev1, tree2.inventory[name + 'id'].revision)
210
        self.assertFileAncestry([rev1], tree, name)
211
212
    def test_last_modified_revision_after_commit_dir_unchanged(self):
213
        # committing without changing a dir does not change the last modified.
214
        tree = self.make_branch_and_tree('.')
215
        self.build_tree(['dir/'])
216
        self._add_commit_check_unchanged(tree, 'dir')
217
218
    def test_last_modified_revision_after_commit_dir_contents_unchanged(self):
219
        # committing without changing a dir does not change the last modified
220
        # of the dir even the dirs contents are changed.
221
        tree = self.make_branch_and_tree('.')
222
        self.build_tree(['dir/'])
223
        tree.add(['dir'], ['dirid'])
224
        rev1 = tree.commit('')
225
        self.build_tree(['dir/content'])
226
        tree.add(['dir/content'], ['contentid'])
227
        rev2 = tree.commit('')
228
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
229
        self.assertEqual(rev1, tree1.inventory['dirid'].revision)
230
        self.assertEqual(rev1, tree2.inventory['dirid'].revision)
231
        self.assertFileAncestry([rev1], tree, 'dir')
232
233
    def test_last_modified_revision_after_commit_file_unchanged(self):
234
        # committing without changing a file does not change the last modified.
235
        tree = self.make_branch_and_tree('.')
236
        self.build_tree(['file'])
237
        self._add_commit_check_unchanged(tree, 'file')
238
239
    def test_last_modified_revision_after_commit_link_unchanged(self):
240
        # committing without changing a link does not change the last modified.
241
        self.requireFeature(tests.SymlinkFeature)
242
        tree = self.make_branch_and_tree('.')
243
        os.symlink('target', 'link')
244
        self._add_commit_check_unchanged(tree, 'link')
245
246
    def _add_commit_renamed_check_changed(self, tree, name):
247
        def rename():
248
            tree.rename_one(name, 'new_' + name)
249
        self._add_commit_change_check_changed(tree, name, rename)
250
251
    def test_last_modified_revision_after_rename_dir_changes(self):
252
        # renaming a dir changes the last modified.
253
        tree = self.make_branch_and_tree('.')
254
        self.build_tree(['dir/'])
255
        self._add_commit_renamed_check_changed(tree, 'dir')
256
257
    def test_last_modified_revision_after_rename_file_changes(self):
258
        # renaming a file changes the last modified.
259
        tree = self.make_branch_and_tree('.')
260
        self.build_tree(['file'])
261
        self._add_commit_renamed_check_changed(tree, 'file')
262
263
    def test_last_modified_revision_after_rename_link_changes(self):
264
        # renaming a link changes the last modified.
265
        self.requireFeature(tests.SymlinkFeature)
266
        tree = self.make_branch_and_tree('.')
267
        os.symlink('target', 'link')
268
        self._add_commit_renamed_check_changed(tree, 'link')
269
270
    def _add_commit_reparent_check_changed(self, tree, name):
271
        self.build_tree(['newparent/'])
272
        tree.add(['newparent'])
273
        def reparent():
274
            tree.rename_one(name, 'newparent/new_' + name)
275
        self._add_commit_change_check_changed(tree, name, reparent)
276
277
    def test_last_modified_revision_after_reparent_dir_changes(self):
278
        # reparenting a dir changes the last modified.
279
        tree = self.make_branch_and_tree('.')
280
        self.build_tree(['dir/'])
281
        self._add_commit_reparent_check_changed(tree, 'dir')
282
283
    def test_last_modified_revision_after_reparent_file_changes(self):
284
        # reparenting a file changes the last modified.
285
        tree = self.make_branch_and_tree('.')
286
        self.build_tree(['file'])
287
        self._add_commit_reparent_check_changed(tree, 'file')
288
289
    def test_last_modified_revision_after_reparent_link_changes(self):
290
        # reparenting a link changes the last modified.
291
        self.requireFeature(tests.SymlinkFeature)
292
        tree = self.make_branch_and_tree('.')
293
        os.symlink('target', 'link')
294
        self._add_commit_reparent_check_changed(tree, 'link')
295
296
    def _add_commit_change_check_changed(self, tree, name, changer):
297
        tree.add([name], [name + 'id'])
298
        rev1 = tree.commit('')
299
        changer()
300
        rev2 = tree.commit('')
301
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
302
        self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
303
        self.assertEqual(rev2, tree2.inventory[name + 'id'].revision)
304
        self.assertFileAncestry([rev1, rev2], tree, name)
305
306
    def assertFileAncestry(self, ancestry, tree, name, alt_ancestry=None):
307
        # all the changes that have occured should be in the ancestry
308
        # (closest to a public per-file graph API we have today)
309
        tree.lock_read()
310
        self.addCleanup(tree.unlock)
311
        vw = tree.branch.repository.weave_store.get_weave(name + 'id',
312
            tree.branch.repository.get_transaction())
313
        result = vw.get_ancestry([ancestry[-1]])
314
        if alt_ancestry is None:
315
            self.assertEqual(ancestry, result)
316
        else:
317
            self.assertSubset([tuple(result)],
318
                [tuple(ancestry), tuple(alt_ancestry)])
319
320
    def test_last_modified_revision_after_content_file_changes(self):
321
        # altering a file changes the last modified.
322
        tree = self.make_branch_and_tree('.')
323
        self.build_tree(['file'])
324
        def change_file():
325
            tree.put_file_bytes_non_atomic('fileid', 'new content')
326
        self._add_commit_change_check_changed(tree, 'file', change_file)
327
328
    def test_last_modified_revision_after_content_link_changes(self):
329
        # changing a link changes the last modified.
330
        self.requireFeature(tests.SymlinkFeature)
331
        tree = self.make_branch_and_tree('.')
332
        os.symlink('target', 'link')
333
        def change_link():
334
            os.unlink('link')
335
            os.symlink('newtarget', 'link')
336
        self._add_commit_change_check_changed(tree, 'link', change_link)
337
338
    def _commit_sprout(self, tree, name):
339
        tree.add([name], [name + 'id'])
340
        rev_id = tree.commit('')
341
        return rev_id, tree.bzrdir.sprout('t2').open_workingtree()
342
343
    def _rename_in_tree(self, tree, name):
344
        tree.rename_one(name, 'new_' + name)
345
        return tree.commit('')
346
347
    def _commit_sprout_rename_merge(self, tree1, name):
348
        rev1, tree2 = self._commit_sprout(tree1, name)
349
        # change both sides equally
350
        rev2 = self._rename_in_tree(tree1, name)
351
        rev3 = self._rename_in_tree(tree2, name)
352
        tree1.merge_from_branch(tree2.branch)
353
        rev4 = tree1.commit('')
354
        tree3, = self._get_revtrees(tree1, [rev4])
355
        self.assertEqual(rev4, tree3.inventory[name + 'id'].revision)
2776.4.2 by Robert Collins
nuke _read_tree_state and snapshot from inventory, moving responsibility into the commit builder.
356
        # TODO: change this to an assertFileGraph call to check the
357
        # parent order of rev4: it should be rev2, rev3
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
358
        self.assertFileAncestry([rev1, rev2, rev3, rev4], tree1, name,
359
            [rev1, rev3, rev2, rev4])
360
361
    def test_last_modified_revision_after_merge_dir_changes(self):
362
        # merge a dir changes the last modified.
363
        tree1 = self.make_branch_and_tree('t1')
364
        self.build_tree(['t1/dir/'])
365
        self._commit_sprout_rename_merge(tree1, 'dir')
366
367
    def test_last_modified_revision_after_merge_file_changes(self):
368
        # merge a file changes the last modified.
369
        tree1 = self.make_branch_and_tree('t1')
370
        self.build_tree(['t1/file'])
371
        self._commit_sprout_rename_merge(tree1, 'file')
372
373
    def test_last_modified_revision_after_merge_link_changes(self):
374
        # merge a link changes the last modified.
375
        self.requireFeature(tests.SymlinkFeature)
376
        tree1 = self.make_branch_and_tree('t1')
377
        os.symlink('target', 't1/link')
378
        self._commit_sprout_rename_merge(tree1, 'link')
379
380
    def _commit_sprout_rename_merge_converged(self, tree1, name):
381
        rev1, tree2 = self._commit_sprout(tree1, name)
382
        # change on the other side to merge back
383
        rev2 = self._rename_in_tree(tree2, name)
384
        tree1.merge_from_branch(tree2.branch)
385
        rev3 = tree1.commit('')
386
        tree3, = self._get_revtrees(tree1, [rev2])
387
        self.assertEqual(rev2, tree3.inventory[name + 'id'].revision)
388
        self.assertFileAncestry([rev1, rev2], tree1, name)
389
390
    def test_last_modified_revision_after_converged_merge_dir_changes(self):
391
        # merge a dir changes the last modified.
392
        tree1 = self.make_branch_and_tree('t1')
393
        self.build_tree(['t1/dir/'])
394
        self._commit_sprout_rename_merge_converged(tree1, 'dir')
395
396
    def test_last_modified_revision_after_converged_merge_file_changes(self):
397
        # merge a file changes the last modified.
398
        tree1 = self.make_branch_and_tree('t1')
399
        self.build_tree(['t1/file'])
400
        self._commit_sprout_rename_merge_converged(tree1, 'file')
401
402
    def test_last_modified_revision_after_converged_merge_link_changes(self):
403
        # merge a link changes the last modified.
404
        self.requireFeature(tests.SymlinkFeature)
405
        tree1 = self.make_branch_and_tree('t1')
406
        os.symlink('target', 't1/link')
407
        self._commit_sprout_rename_merge_converged(tree1, 'link')
408
409
    def make_dir(self, name):
410
        self.build_tree([name + '/'])
411
412
    def make_file(self, name):
413
        self.build_tree([name])
414
415
    def make_link(self, name):
416
        self.requireFeature(tests.SymlinkFeature)
417
        os.symlink('target', name)
418
419
    def _check_kind_change(self, make_before, make_after):
420
        tree = self.make_branch_and_tree('.')
421
        path = 'name'
422
        make_before(path)
423
        def change_kind():
424
            try:
425
                os.unlink(path)
426
            except OSError, e:
427
                if e.errno != EISDIR:
428
                    raise
429
                os.rmdir(path)
430
            make_after(path)
431
        self._add_commit_change_check_changed(tree, path, change_kind)
432
433
    def test_last_modified_dir_file(self):
434
        self._check_kind_change(self.make_dir, self.make_file)
435
436
    def test_last_modified_dir_link(self):
437
        self._check_kind_change(self.make_dir, self.make_link)
438
439
    def test_last_modified_link_file(self):
440
        self._check_kind_change(self.make_link, self.make_file)
441
442
    def test_last_modified_link_dir(self):
443
        self._check_kind_change(self.make_link, self.make_dir)
444
445
    def test_last_modified_file_dir(self):
446
        self._check_kind_change(self.make_file, self.make_dir)
447
448
    def test_last_modified_file_link(self):
449
        self._check_kind_change(self.make_file, self.make_link)