/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2006-2011 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
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
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
16
5582.8.1 by Martin
Make bt.test_transform.TestTreeTransform.test_rename_fails not care about the exact stringification of the exception instance
17
import errno
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
18
import os
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
19
from StringIO import StringIO
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
20
import sys
4934.1.1 by John Arbash Meinel
Basic implementation for windows and bug #488724.
21
import time
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
22
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
23
from bzrlib import (
2694.5.4 by Jelmer Vernooij
Move bzrlib.util.bencode to bzrlib._bencode_py.
24
    bencode,
2090.2.1 by Martin Pool
Fix some code which relies on assertions and breaks under python -O
25
    errors,
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
26
    filters,
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
27
    generate_ids,
3199.1.4 by Vincent Ladeuil
Fix 16 leaked tmp dirs. Probably indicates a lock handling problem with TransformPreview
28
    osutils,
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
29
    revision as _mod_revision,
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
30
    rules,
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
31
    symbol_versioning,
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
32
    tests,
5409.1.17 by Vincent Ladeuil
Ensures we fallback to the default policy if a bogus one is specified.
33
    trace,
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
34
    transform,
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
35
    urlutils,
36
    )
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
37
from bzrlib.bzrdir import BzrDir
5162.4.1 by Aaron Bentley
TreeTransform supports normal commit parameters and includes branch nick.
38
from bzrlib.conflicts import (
39
    DeletingParent,
40
    DuplicateEntry,
41
    DuplicateID,
42
    MissingParent,
43
    NonDirectoryParent,
44
    ParentLoop,
45
    UnversionedParent,
46
)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
47
from bzrlib.diff import show_diff_trees
5162.4.1 by Aaron Bentley
TreeTransform supports normal commit parameters and includes branch nick.
48
from bzrlib.errors import (
49
    DuplicateKey,
50
    ExistingLimbo,
51
    ExistingPendingDeletion,
52
    ImmortalLimbo,
53
    ImmortalPendingDeletion,
54
    LockError,
55
    MalformedTransform,
56
    ReusingTransform,
57
)
58
from bzrlib.osutils import (
59
    file_kind,
60
    pathjoin,
61
)
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
62
from bzrlib.merge import Merge3Merger, Merger
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
63
from bzrlib.tests import (
5050.44.1 by Vincent Ladeuil
One more fixed test related to bug #646133
64
    features,
3136.1.1 by Aaron Bentley
Add support for hardlinks to TreeTransform
65
    HardlinkFeature,
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
66
    SymlinkFeature,
67
    TestCaseInTempDir,
68
    TestSkipped,
5162.4.1 by Aaron Bentley
TreeTransform supports normal commit parameters and includes branch nick.
69
)
70
from bzrlib.transform import (
71
    build_tree,
72
    create_from_tree,
73
    cook_conflicts,
74
    _FileMover,
75
    FinalPaths,
76
    resolve_conflicts,
77
    resolve_checkout,
78
    ROOT_PARENT,
79
    TransformPreview,
80
    TreeTransform,
81
)
0.13.13 by Aaron Bentley
Add direct test of serialization records
82
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
83
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
84
class TestTreeTransform(tests.TestCaseWithTransport):
1740.2.4 by Aaron Bentley
Update transform tests and docs
85
1534.7.59 by Aaron Bentley
Simplified tests
86
    def setUp(self):
87
        super(TestTreeTransform, self).setUp()
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
88
        self.wt = self.make_branch_and_tree('.', format='dirstate-with-subtree')
1534.7.161 by Aaron Bentley
Used appropriate control_files
89
        os.chdir('..')
1534.7.59 by Aaron Bentley
Simplified tests
90
91
    def get_transform(self):
92
        transform = TreeTransform(self.wt)
3453.2.7 by Aaron Bentley
Remove test kipple
93
        self.addCleanup(transform.finalize)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
94
        return transform, transform.root
1534.7.59 by Aaron Bentley
Simplified tests
95
5752.3.5 by John Arbash Meinel
Refactor tests into a common helper.
96
    def get_transform_for_sha1_test(self):
97
        trans, root = self.get_transform()
98
        self.wt.lock_tree_write()
99
        self.addCleanup(self.wt.unlock)
100
        contents = ['just some content\n']
101
        sha1 = osutils.sha_strings(contents)
102
        # Roll back the clock
103
        trans._creation_mtime = time.time() - 20.0
104
        return trans, root, contents, sha1
105
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
106
    def test_existing_limbo(self):
107
        transform, root = self.get_transform()
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
108
        limbo_name = transform._limbodir
109
        deletion_path = transform._deletiondir
1534.7.176 by abentley
Fixed up tests for Windows
110
        os.mkdir(pathjoin(limbo_name, 'hehe'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
111
        self.assertRaises(ImmortalLimbo, transform.apply)
112
        self.assertRaises(LockError, self.wt.unlock)
113
        self.assertRaises(ExistingLimbo, self.get_transform)
114
        self.assertRaises(LockError, self.wt.unlock)
1534.7.176 by abentley
Fixed up tests for Windows
115
        os.rmdir(pathjoin(limbo_name, 'hehe'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
116
        os.rmdir(limbo_name)
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
117
        os.rmdir(deletion_path)
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
118
        transform, root = self.get_transform()
119
        transform.apply()
1534.7.59 by Aaron Bentley
Simplified tests
120
2733.2.11 by Aaron Bentley
Detect irregularities with the pending-deletion directory
121
    def test_existing_pending_deletion(self):
122
        transform, root = self.get_transform()
123
        deletion_path = self._limbodir = urlutils.local_path_from_url(
3407.2.8 by Martin Pool
Deprecate LockableFiles.controlfilename
124
            transform._tree._transport.abspath('pending-deletion'))
2733.2.11 by Aaron Bentley
Detect irregularities with the pending-deletion directory
125
        os.mkdir(pathjoin(deletion_path, 'blocking-directory'))
126
        self.assertRaises(ImmortalPendingDeletion, transform.apply)
127
        self.assertRaises(LockError, self.wt.unlock)
128
        self.assertRaises(ExistingPendingDeletion, self.get_transform)
129
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
130
    def test_build(self):
3034.2.1 by Aaron Bentley
Fix is_executable tests for win32
131
        transform, root = self.get_transform()
132
        self.wt.lock_tree_write()
133
        self.addCleanup(self.wt.unlock)
1534.7.59 by Aaron Bentley
Simplified tests
134
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
135
        imaginary_id = transform.trans_id_tree_path('imaginary')
1534.10.32 by Aaron Bentley
Test and fix case where name has trailing slash
136
        imaginary_id2 = transform.trans_id_tree_path('imaginary/')
137
        self.assertEqual(imaginary_id, imaginary_id2)
4597.9.7 by Vincent Ladeuil
transform.final_kind() now returns None instead of raising NoSuchFile.
138
        self.assertEqual(root, transform.get_tree_parent(imaginary_id))
139
        self.assertEqual('directory', transform.final_kind(root))
140
        self.assertEqual(self.wt.get_root_id(), transform.final_file_id(root))
1534.7.59 by Aaron Bentley
Simplified tests
141
        trans_id = transform.create_path('name', root)
142
        self.assertIs(transform.final_file_id(trans_id), None)
4597.9.7 by Vincent Ladeuil
transform.final_kind() now returns None instead of raising NoSuchFile.
143
        self.assertIs(None, transform.final_kind(trans_id))
1534.7.59 by Aaron Bentley
Simplified tests
144
        transform.create_file('contents', trans_id)
145
        transform.set_executability(True, trans_id)
146
        transform.version_file('my_pretties', trans_id)
147
        self.assertRaises(DuplicateKey, transform.version_file,
148
                          'my_pretties', trans_id)
149
        self.assertEqual(transform.final_file_id(trans_id), 'my_pretties')
150
        self.assertEqual(transform.final_parent(trans_id), root)
151
        self.assertIs(transform.final_parent(root), ROOT_PARENT)
152
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
153
        oz_id = transform.create_path('oz', root)
154
        transform.create_directory(oz_id)
155
        transform.version_file('ozzie', oz_id)
156
        trans_id2 = transform.create_path('name2', root)
157
        transform.create_file('contents', trans_id2)
158
        transform.set_executability(False, trans_id2)
159
        transform.version_file('my_pretties2', trans_id2)
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
160
        modified_paths = transform.apply().modified_paths
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
161
        self.assertEqual('contents', self.wt.get_file_byname('name').read())
1534.7.59 by Aaron Bentley
Simplified tests
162
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
163
        self.assertIs(self.wt.is_executable('my_pretties'), True)
164
        self.assertIs(self.wt.is_executable('my_pretties2'), False)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
165
        self.assertEqual('directory', file_kind(self.wt.abspath('oz')))
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
166
        self.assertEqual(len(modified_paths), 3)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
167
        tree_mod_paths = [self.wt.id2abspath(f) for f in
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
168
                          ('ozzie', 'my_pretties', 'my_pretties2')]
169
        self.assertSubset(tree_mod_paths, modified_paths)
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
170
        # is it safe to finalize repeatedly?
171
        transform.finalize()
1534.7.59 by Aaron Bentley
Simplified tests
172
        transform.finalize()
1534.7.2 by Aaron Bentley
Added convenience function
173
5752.3.6 by John Arbash Meinel
More direct tests of TreeTransform behavior wrt _observed_sha1s
174
    def test_apply_informs_tree_of_observed_sha1(self):
175
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
176
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
177
                                  sha1=sha1)
178
        calls = []
179
        orig = self.wt._observed_sha1
180
        def _observed_sha1(*args):
181
            calls.append(args)
182
            orig(*args)
183
        self.wt._observed_sha1 = _observed_sha1
184
        trans.apply()
185
        self.assertEqual([(None, 'file1', trans._observed_sha1s[trans_id])],
186
                         calls)
187
5752.3.1 by John Arbash Meinel
Merge up from 2.4-windows-lfstat
188
    def test_create_file_caches_sha1(self):
5752.3.5 by John Arbash Meinel
Refactor tests into a common helper.
189
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
5752.3.1 by John Arbash Meinel
Merge up from 2.4-windows-lfstat
190
        trans_id = trans.create_path('file1', root)
5752.3.5 by John Arbash Meinel
Refactor tests into a common helper.
191
        trans.create_file(contents, trans_id, sha1=sha1)
5752.3.1 by John Arbash Meinel
Merge up from 2.4-windows-lfstat
192
        st_val = osutils.lstat(trans._limbo_name(trans_id))
193
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
194
        self.assertEqual(o_sha1, sha1)
195
        self.assertEqualStat(o_st_val, st_val)
196
197
    def test__apply_insertions_updates_sha1(self):
5752.3.5 by John Arbash Meinel
Refactor tests into a common helper.
198
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
5752.3.1 by John Arbash Meinel
Merge up from 2.4-windows-lfstat
199
        trans_id = trans.create_path('file1', root)
5752.3.5 by John Arbash Meinel
Refactor tests into a common helper.
200
        trans.create_file(contents, trans_id, sha1=sha1)
5752.3.1 by John Arbash Meinel
Merge up from 2.4-windows-lfstat
201
        st_val = osutils.lstat(trans._limbo_name(trans_id))
202
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
203
        self.assertEqual(o_sha1, sha1)
204
        self.assertEqualStat(o_st_val, st_val)
5752.3.5 by John Arbash Meinel
Refactor tests into a common helper.
205
        creation_mtime = trans._creation_mtime + 10.0
5752.3.1 by John Arbash Meinel
Merge up from 2.4-windows-lfstat
206
        # We fake a time difference from when the file was created until now it
207
        # is being renamed by using os.utime. Note that the change we actually
208
        # want to see is the real ctime change from 'os.rename()', but as long
209
        # as we observe a new stat value, we should be fine.
210
        os.utime(trans._limbo_name(trans_id), (creation_mtime, creation_mtime))
211
        trans.apply()
212
        new_st_val = osutils.lstat(self.wt.abspath('file1'))
213
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
214
        self.assertEqual(o_sha1, sha1)
215
        self.assertEqualStat(o_st_val, new_st_val)
216
        self.assertNotEqual(st_val.st_mtime, new_st_val.st_mtime)
217
5752.3.4 by John Arbash Meinel
Add new_file(sha1=XXX) and pass that down to create_file.
218
    def test_new_file_caches_sha1(self):
5752.3.5 by John Arbash Meinel
Refactor tests into a common helper.
219
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
220
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
5752.3.4 by John Arbash Meinel
Add new_file(sha1=XXX) and pass that down to create_file.
221
                                  sha1=sha1)
222
        st_val = osutils.lstat(trans._limbo_name(trans_id))
223
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
224
        self.assertEqual(o_sha1, sha1)
225
        self.assertEqualStat(o_st_val, st_val)
226
5752.3.5 by John Arbash Meinel
Refactor tests into a common helper.
227
    def test_cancel_creation_removes_observed_sha1(self):
228
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
229
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
230
                                  sha1=sha1)
231
        self.assertTrue(trans_id in trans._observed_sha1s)
232
        trans.cancel_creation(trans_id)
233
        self.assertFalse(trans_id in trans._observed_sha1s)
234
4934.1.1 by John Arbash Meinel
Basic implementation for windows and bug #488724.
235
    def test_create_files_same_timestamp(self):
236
        transform, root = self.get_transform()
237
        self.wt.lock_tree_write()
238
        self.addCleanup(self.wt.unlock)
239
        # Roll back the clock, so that we know everything is being set to the
240
        # exact time
4934.1.10 by John Arbash Meinel
Rework the tests a bit.
241
        transform._creation_mtime = creation_mtime = time.time() - 20.0
4934.1.1 by John Arbash Meinel
Basic implementation for windows and bug #488724.
242
        transform.create_file('content-one',
243
                              transform.create_path('one', root))
244
        time.sleep(1) # *ugly*
245
        transform.create_file('content-two',
246
                              transform.create_path('two', root))
247
        transform.apply()
248
        fo, st1 = self.wt.get_file_with_stat(None, path='one', filtered=False)
249
        fo.close()
250
        fo, st2 = self.wt.get_file_with_stat(None, path='two', filtered=False)
251
        fo.close()
4934.2.2 by Martin
Rearrange osutils.fset_mtime tests a little and make them robust on FAT filesystems
252
        # We only guarantee 2s resolution
4934.1.11 by John Arbash Meinel
2 => 2.0 because it looks better.
253
        self.assertTrue(abs(creation_mtime - st1.st_mtime) < 2.0,
4934.1.10 by John Arbash Meinel
Rework the tests a bit.
254
            "%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
4934.1.6 by John Arbash Meinel
It turns out that with os/python/C buffering, we need to flush
255
        # But if we have more than that, all files should get the same result
4934.1.1 by John Arbash Meinel
Basic implementation for windows and bug #488724.
256
        self.assertEqual(st1.st_mtime, st2.st_mtime)
257
4634.122.2 by Aaron Bentley, John Arbash Meinel
Bring the fixup_new_roots code from the nested-trees code.
258
    def test_change_root_id(self):
259
        transform, root = self.get_transform()
260
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
261
        transform.new_directory('', ROOT_PARENT, 'new-root-id')
262
        transform.delete_contents(root)
263
        transform.unversion_file(root)
264
        transform.fixup_new_roots()
265
        transform.apply()
266
        self.assertEqual('new-root-id', self.wt.get_root_id())
267
268
    def test_change_root_id_add_files(self):
269
        transform, root = self.get_transform()
270
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
271
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
272
        transform.new_file('file', new_trans_id, ['new-contents\n'],
273
                           'new-file-id')
274
        transform.delete_contents(root)
275
        transform.unversion_file(root)
276
        transform.fixup_new_roots()
277
        transform.apply()
278
        self.assertEqual('new-root-id', self.wt.get_root_id())
279
        self.assertEqual('new-file-id', self.wt.path2id('file'))
280
        self.assertFileEqual('new-contents\n', self.wt.abspath('file'))
281
282
    def test_add_two_roots(self):
283
        transform, root = self.get_transform()
284
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
285
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'alt-root-id')
286
        self.assertRaises(ValueError, transform.fixup_new_roots)
287
5954.4.7 by Aaron Bentley
Add test for unversioned roots.
288
    def test_add_unversioned_root(self):
289
        transform, root = self.get_transform()
290
        new_trans_id = transform.new_directory('', ROOT_PARENT, None)
291
        transform.fixup_new_roots()
5954.4.11 by Aaron Bentley
Eschew testtools.testcase.ExpectedException from too-new testtools.
292
        self.assertNotIn(transform.root, transform._new_id)
5954.4.7 by Aaron Bentley
Add test for unversioned roots.
293
5993.2.3 by Jelmer Vernooij
Update NEWS, consistently use require_tree_root as argument everywhere.
294
    def test_remove_root_fixup(self):
295
        transform, root = self.get_transform()
296
        old_root_id = self.wt.get_root_id()
297
        self.assertNotEqual('new-root-id', old_root_id)
298
        transform.delete_contents(root)
299
        transform.unversion_file(root)
5993.2.4 by Jelmer Vernooij
Remove feature flag.
300
        transform.fixup_new_roots()
5993.2.3 by Jelmer Vernooij
Update NEWS, consistently use require_tree_root as argument everywhere.
301
        transform.apply()
302
        self.assertEqual(old_root_id, self.wt.get_root_id())
303
304
        transform, root = self.get_transform()
305
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
306
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'alt-root-id')
307
        self.assertRaises(ValueError, transform.fixup_new_roots)
308
5954.4.1 by Aaron Bentley
Never attempt to delete the tree root.
309
    def test_apply_retains_root_directory(self):
310
        # Do not attempt to delete the physical root directory, because that
311
        # is impossible.
312
        transform, root = self.get_transform()
313
        with transform:
314
            transform.delete_contents(root)
5954.4.12 by Aaron Bentley
Eschew more ExpectedException.
315
            e = self.assertRaises(AssertionError, self.assertRaises,
316
                                  errors.TransformRenameFailed,
317
                                  transform.apply)
318
        self.assertContainsRe('TransformRenameFailed not raised', str(e))
5954.4.1 by Aaron Bentley
Never attempt to delete the tree root.
319
3136.1.1 by Aaron Bentley
Add support for hardlinks to TreeTransform
320
    def test_hardlink(self):
321
        self.requireFeature(HardlinkFeature)
322
        transform, root = self.get_transform()
323
        transform.new_file('file1', root, 'contents')
324
        transform.apply()
325
        target = self.make_branch_and_tree('target')
326
        target_transform = TreeTransform(target)
327
        trans_id = target_transform.create_path('file1', target_transform.root)
328
        target_transform.create_hardlink(self.wt.abspath('file1'), trans_id)
329
        target_transform.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
330
        self.assertPathExists('target/file1')
3136.1.1 by Aaron Bentley
Add support for hardlinks to TreeTransform
331
        source_stat = os.stat(self.wt.abspath('file1'))
332
        target_stat = os.stat('target/file1')
333
        self.assertEqual(source_stat, target_stat)
334
1534.7.2 by Aaron Bentley
Added convenience function
335
    def test_convenience(self):
1534.7.59 by Aaron Bentley
Simplified tests
336
        transform, root = self.get_transform()
3034.2.1 by Aaron Bentley
Fix is_executable tests for win32
337
        self.wt.lock_tree_write()
338
        self.addCleanup(self.wt.unlock)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
339
        trans_id = transform.new_file('name', root, 'contents',
1534.7.59 by Aaron Bentley
Simplified tests
340
                                      'my_pretties', True)
341
        oz = transform.new_directory('oz', root, 'oz-id')
342
        dorothy = transform.new_directory('dorothy', oz, 'dorothy-id')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
343
        toto = transform.new_file('toto', dorothy, 'toto-contents',
1534.7.59 by Aaron Bentley
Simplified tests
344
                                  'toto-id', False)
345
346
        self.assertEqual(len(transform.find_conflicts()), 0)
347
        transform.apply()
348
        self.assertRaises(ReusingTransform, transform.find_conflicts)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
349
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
1534.7.59 by Aaron Bentley
Simplified tests
350
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
351
        self.assertIs(self.wt.is_executable('my_pretties'), True)
352
        self.assertEqual(self.wt.path2id('oz'), 'oz-id')
353
        self.assertEqual(self.wt.path2id('oz/dorothy'), 'dorothy-id')
354
        self.assertEqual(self.wt.path2id('oz/dorothy/toto'), 'toto-id')
355
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
356
        self.assertEqual('toto-contents',
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
357
                         self.wt.get_file_byname('oz/dorothy/toto').read())
1534.7.59 by Aaron Bentley
Simplified tests
358
        self.assertIs(self.wt.is_executable('toto-id'), False)
1534.7.6 by Aaron Bentley
Added conflict handling
359
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
360
    def test_tree_reference(self):
361
        transform, root = self.get_transform()
362
        tree = transform._tree
363
        trans_id = transform.new_directory('reference', root, 'subtree-id')
364
        transform.set_tree_reference('subtree-revision', trans_id)
365
        transform.apply()
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
366
        tree.lock_read()
367
        self.addCleanup(tree.unlock)
368
        self.assertEqual('subtree-revision',
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
369
                         tree.inventory['subtree-id'].reference_revision)
370
1534.7.6 by Aaron Bentley
Added conflict handling
371
    def test_conflicts(self):
1534.7.59 by Aaron Bentley
Simplified tests
372
        transform, root = self.get_transform()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
373
        trans_id = transform.new_file('name', root, 'contents',
1534.7.59 by Aaron Bentley
Simplified tests
374
                                      'my_pretties')
375
        self.assertEqual(len(transform.find_conflicts()), 0)
376
        trans_id2 = transform.new_file('name', root, 'Crontents', 'toto')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
377
        self.assertEqual(transform.find_conflicts(),
1534.7.59 by Aaron Bentley
Simplified tests
378
                         [('duplicate', trans_id, trans_id2, 'name')])
379
        self.assertRaises(MalformedTransform, transform.apply)
380
        transform.adjust_path('name', trans_id, trans_id2)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
381
        self.assertEqual(transform.find_conflicts(),
1534.7.59 by Aaron Bentley
Simplified tests
382
                         [('non-directory parent', trans_id)])
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
383
        tinman_id = transform.trans_id_tree_path('tinman')
1534.7.59 by Aaron Bentley
Simplified tests
384
        transform.adjust_path('name', tinman_id, trans_id2)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
385
        self.assertEqual(transform.find_conflicts(),
386
                         [('unversioned parent', tinman_id),
1534.7.59 by Aaron Bentley
Simplified tests
387
                          ('missing parent', tinman_id)])
388
        lion_id = transform.create_path('lion', root)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
389
        self.assertEqual(transform.find_conflicts(),
390
                         [('unversioned parent', tinman_id),
1534.7.59 by Aaron Bentley
Simplified tests
391
                          ('missing parent', tinman_id)])
392
        transform.adjust_path('name', lion_id, trans_id2)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
393
        self.assertEqual(transform.find_conflicts(),
1534.7.59 by Aaron Bentley
Simplified tests
394
                         [('unversioned parent', lion_id),
395
                          ('missing parent', lion_id)])
396
        transform.version_file("Courage", lion_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
397
        self.assertEqual(transform.find_conflicts(),
398
                         [('missing parent', lion_id),
1534.7.59 by Aaron Bentley
Simplified tests
399
                          ('versioning no contents', lion_id)])
400
        transform.adjust_path('name2', root, trans_id2)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
401
        self.assertEqual(transform.find_conflicts(),
1534.7.59 by Aaron Bentley
Simplified tests
402
                         [('versioning no contents', lion_id)])
403
        transform.create_file('Contents, okay?', lion_id)
404
        transform.adjust_path('name2', trans_id2, trans_id2)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
405
        self.assertEqual(transform.find_conflicts(),
406
                         [('parent loop', trans_id2),
1534.7.59 by Aaron Bentley
Simplified tests
407
                          ('non-directory parent', trans_id2)])
408
        transform.adjust_path('name2', root, trans_id2)
409
        oz_id = transform.new_directory('oz', root)
410
        transform.set_executability(True, oz_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
411
        self.assertEqual(transform.find_conflicts(),
1534.7.59 by Aaron Bentley
Simplified tests
412
                         [('unversioned executability', oz_id)])
413
        transform.version_file('oz-id', oz_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
414
        self.assertEqual(transform.find_conflicts(),
1534.7.59 by Aaron Bentley
Simplified tests
415
                         [('non-file executability', oz_id)])
416
        transform.set_executability(None, oz_id)
1534.7.71 by abentley
All tests pass under Windows
417
        tip_id = transform.new_file('tip', oz_id, 'ozma', 'tip-id')
1534.7.59 by Aaron Bentley
Simplified tests
418
        transform.apply()
419
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
420
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
421
        transform2, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
422
        oz_id = transform2.trans_id_tree_file_id('oz-id')
1534.7.59 by Aaron Bentley
Simplified tests
423
        newtip = transform2.new_file('tip', oz_id, 'other', 'tip-id')
424
        result = transform2.find_conflicts()
1534.7.135 by Aaron Bentley
Fixed deletion handling
425
        fp = FinalPaths(transform2)
1534.7.59 by Aaron Bentley
Simplified tests
426
        self.assert_('oz/tip' in transform2._tree_path_ids)
1534.7.176 by abentley
Fixed up tests for Windows
427
        self.assertEqual(fp.get_path(newtip), pathjoin('oz', 'tip'))
1534.7.59 by Aaron Bentley
Simplified tests
428
        self.assertEqual(len(result), 2)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
429
        self.assertEqual((result[0][0], result[0][1]),
1534.7.59 by Aaron Bentley
Simplified tests
430
                         ('duplicate', newtip))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
431
        self.assertEqual((result[1][0], result[1][2]),
1534.7.59 by Aaron Bentley
Simplified tests
432
                         ('duplicate id', newtip))
1534.7.73 by Aaron Bentley
Changed model again. Now iterator is used immediately.
433
        transform2.finalize()
1534.7.59 by Aaron Bentley
Simplified tests
434
        transform3 = TreeTransform(self.wt)
435
        self.addCleanup(transform3.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
436
        oz_id = transform3.trans_id_tree_file_id('oz-id')
1534.7.59 by Aaron Bentley
Simplified tests
437
        transform3.delete_contents(oz_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
438
        self.assertEqual(transform3.find_conflicts(),
1534.7.59 by Aaron Bentley
Simplified tests
439
                         [('missing parent', oz_id)])
1731.1.33 by Aaron Bentley
Revert no-special-root changes
440
        root_id = transform3.root
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
441
        tip_id = transform3.trans_id_tree_file_id('tip-id')
1534.7.59 by Aaron Bentley
Simplified tests
442
        transform3.adjust_path('tip', root_id, tip_id)
443
        transform3.apply()
1534.7.36 by Aaron Bentley
Added rename tests
444
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
445
    def test_conflict_on_case_insensitive(self):
446
        tree = self.make_branch_and_tree('tree')
447
        # Don't try this at home, kids!
448
        # Force the tree to report that it is case sensitive, for conflict
449
        # resolution tests
450
        tree.case_sensitive = True
451
        transform = TreeTransform(tree)
452
        self.addCleanup(transform.finalize)
453
        transform.new_file('file', transform.root, 'content')
454
        transform.new_file('FiLe', transform.root, 'content')
455
        result = transform.find_conflicts()
456
        self.assertEqual([], result)
3008.1.15 by Aaron Bentley
Make case_sensitive an aspect of the transform, not the source tree
457
        transform.finalize()
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
458
        # Force the tree to report that it is case insensitive, for conflict
459
        # generation tests
460
        tree.case_sensitive = False
3008.1.15 by Aaron Bentley
Make case_sensitive an aspect of the transform, not the source tree
461
        transform = TreeTransform(tree)
462
        self.addCleanup(transform.finalize)
463
        transform.new_file('file', transform.root, 'content')
464
        transform.new_file('FiLe', transform.root, 'content')
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
465
        result = transform.find_conflicts()
466
        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
467
3034.4.7 by Aaron Bentley
Add test for filename conflicts with existing files
468
    def test_conflict_on_case_insensitive_existing(self):
469
        tree = self.make_branch_and_tree('tree')
470
        self.build_tree(['tree/FiLe'])
471
        # Don't try this at home, kids!
472
        # Force the tree to report that it is case sensitive, for conflict
473
        # resolution tests
474
        tree.case_sensitive = True
475
        transform = TreeTransform(tree)
476
        self.addCleanup(transform.finalize)
477
        transform.new_file('file', transform.root, 'content')
478
        result = transform.find_conflicts()
479
        self.assertEqual([], result)
3008.1.15 by Aaron Bentley
Make case_sensitive an aspect of the transform, not the source tree
480
        transform.finalize()
3034.4.7 by Aaron Bentley
Add test for filename conflicts with existing files
481
        # Force the tree to report that it is case insensitive, for conflict
482
        # generation tests
483
        tree.case_sensitive = False
3008.1.15 by Aaron Bentley
Make case_sensitive an aspect of the transform, not the source tree
484
        transform = TreeTransform(tree)
485
        self.addCleanup(transform.finalize)
486
        transform.new_file('file', transform.root, 'content')
3034.4.7 by Aaron Bentley
Add test for filename conflicts with existing files
487
        result = transform.find_conflicts()
488
        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
489
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
490
    def test_resolve_case_insensitive_conflict(self):
491
        tree = self.make_branch_and_tree('tree')
492
        # Don't try this at home, kids!
493
        # Force the tree to report that it is case insensitive, for conflict
494
        # resolution tests
495
        tree.case_sensitive = False
496
        transform = TreeTransform(tree)
497
        self.addCleanup(transform.finalize)
498
        transform.new_file('file', transform.root, 'content')
499
        transform.new_file('FiLe', transform.root, 'content')
500
        resolve_conflicts(transform)
501
        transform.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
502
        self.assertPathExists('tree/file')
503
        self.assertPathExists('tree/FiLe.moved')
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
504
3034.4.2 by Aaron Bentley
Get conflict handling and case-insensitive tree creation under test
505
    def test_resolve_checkout_case_conflict(self):
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
506
        tree = self.make_branch_and_tree('tree')
507
        # Don't try this at home, kids!
508
        # Force the tree to report that it is case insensitive, for conflict
509
        # resolution tests
510
        tree.case_sensitive = False
511
        transform = TreeTransform(tree)
512
        self.addCleanup(transform.finalize)
513
        transform.new_file('file', transform.root, 'content')
514
        transform.new_file('FiLe', transform.root, 'content')
3034.4.2 by Aaron Bentley
Get conflict handling and case-insensitive tree creation under test
515
        resolve_conflicts(transform,
516
                          pass_func=lambda t, c: resolve_checkout(t, c, []))
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
517
        transform.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
518
        self.assertPathExists('tree/file')
519
        self.assertPathExists('tree/FiLe.moved')
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
520
3034.4.2 by Aaron Bentley
Get conflict handling and case-insensitive tree creation under test
521
    def test_apply_case_conflict(self):
3034.4.6 by Aaron Bentley
Update apply_case_conflict tests
522
        """Ensure that a transform with case conflicts can always be applied"""
3034.4.2 by Aaron Bentley
Get conflict handling and case-insensitive tree creation under test
523
        tree = self.make_branch_and_tree('tree')
524
        transform = TreeTransform(tree)
525
        self.addCleanup(transform.finalize)
526
        transform.new_file('file', transform.root, 'content')
527
        transform.new_file('FiLe', transform.root, 'content')
3034.4.6 by Aaron Bentley
Update apply_case_conflict tests
528
        dir = transform.new_directory('dir', transform.root)
529
        transform.new_file('dirfile', dir, 'content')
530
        transform.new_file('dirFiLe', dir, 'content')
531
        resolve_conflicts(transform)
3034.4.2 by Aaron Bentley
Get conflict handling and case-insensitive tree creation under test
532
        transform.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
533
        self.assertPathExists('tree/file')
3034.4.3 by Aaron Bentley
Add case-sensitivity handling to WorkingTree
534
        if not os.path.exists('tree/FiLe.moved'):
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
535
            self.assertPathExists('tree/FiLe')
536
        self.assertPathExists('tree/dir/dirfile')
3034.4.6 by Aaron Bentley
Update apply_case_conflict tests
537
        if not os.path.exists('tree/dir/dirFiLe.moved'):
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
538
            self.assertPathExists('tree/dir/dirFiLe')
3034.4.2 by Aaron Bentley
Get conflict handling and case-insensitive tree creation under test
539
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
540
    def test_case_insensitive_limbo(self):
541
        tree = self.make_branch_and_tree('tree')
542
        # Don't try this at home, kids!
543
        # Force the tree to report that it is case insensitive
544
        tree.case_sensitive = False
545
        transform = TreeTransform(tree)
546
        self.addCleanup(transform.finalize)
547
        dir = transform.new_directory('dir', transform.root)
548
        first = transform.new_file('file', dir, 'content')
549
        second = transform.new_file('FiLe', dir, 'content')
550
        self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
551
        self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
552
4634.78.1 by Aaron Bentley
adjust_path updatest limbo paths.
553
    def test_adjust_path_updates_child_limbo_names(self):
554
        tree = self.make_branch_and_tree('tree')
555
        transform = TreeTransform(tree)
556
        self.addCleanup(transform.finalize)
557
        foo_id = transform.new_directory('foo', transform.root)
558
        bar_id = transform.new_directory('bar', foo_id)
559
        baz_id = transform.new_directory('baz', bar_id)
560
        qux_id = transform.new_directory('qux', baz_id)
561
        transform.adjust_path('quxx', foo_id, bar_id)
562
        self.assertStartsWith(transform._limbo_name(qux_id),
563
                              transform._limbo_name(bar_id))
564
1558.7.11 by Aaron Bentley
Avoid spurious conflict on add/delete
565
    def test_add_del(self):
566
        start, root = self.get_transform()
567
        start.new_directory('a', root, 'a')
568
        start.apply()
569
        transform, root = self.get_transform()
570
        transform.delete_versioned(transform.trans_id_tree_file_id('a'))
571
        transform.new_directory('a', root, 'a')
572
        transform.apply()
573
1534.7.46 by Aaron Bentley
Ensured a conflict when parents of versioned files are unversioned
574
    def test_unversioning(self):
1534.7.59 by Aaron Bentley
Simplified tests
575
        create_tree, root = self.get_transform()
576
        parent_id = create_tree.new_directory('parent', root, 'parent-id')
577
        create_tree.new_file('child', parent_id, 'child', 'child-id')
578
        create_tree.apply()
579
        unversion = TreeTransform(self.wt)
580
        self.addCleanup(unversion.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
581
        parent = unversion.trans_id_tree_path('parent')
1534.7.59 by Aaron Bentley
Simplified tests
582
        unversion.unversion_file(parent)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
583
        self.assertEqual(unversion.find_conflicts(),
1534.7.59 by Aaron Bentley
Simplified tests
584
                         [('unversioned parent', parent_id)])
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
585
        file_id = unversion.trans_id_tree_file_id('child-id')
1534.7.59 by Aaron Bentley
Simplified tests
586
        unversion.unversion_file(file_id)
587
        unversion.apply()
1534.7.46 by Aaron Bentley
Ensured a conflict when parents of versioned files are unversioned
588
1534.7.36 by Aaron Bentley
Added rename tests
589
    def test_name_invariants(self):
1534.7.59 by Aaron Bentley
Simplified tests
590
        create_tree, root = self.get_transform()
591
        # prepare tree
1731.1.33 by Aaron Bentley
Revert no-special-root changes
592
        root = create_tree.root
1534.7.59 by Aaron Bentley
Simplified tests
593
        create_tree.new_file('name1', root, 'hello1', 'name1')
594
        create_tree.new_file('name2', root, 'hello2', 'name2')
595
        ddir = create_tree.new_directory('dying_directory', root, 'ddir')
596
        create_tree.new_file('dying_file', ddir, 'goodbye1', 'dfile')
597
        create_tree.new_file('moving_file', ddir, 'later1', 'mfile')
598
        create_tree.new_file('moving_file2', root, 'later2', 'mfile2')
599
        create_tree.apply()
600
601
        mangle_tree,root = self.get_transform()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
602
        root = mangle_tree.root
1534.7.59 by Aaron Bentley
Simplified tests
603
        #swap names
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
604
        name1 = mangle_tree.trans_id_tree_file_id('name1')
605
        name2 = mangle_tree.trans_id_tree_file_id('name2')
1534.7.59 by Aaron Bentley
Simplified tests
606
        mangle_tree.adjust_path('name2', root, name1)
607
        mangle_tree.adjust_path('name1', root, name2)
608
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
609
        #tests for deleting parent directories
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
610
        ddir = mangle_tree.trans_id_tree_file_id('ddir')
1534.7.59 by Aaron Bentley
Simplified tests
611
        mangle_tree.delete_contents(ddir)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
612
        dfile = mangle_tree.trans_id_tree_file_id('dfile')
1534.7.59 by Aaron Bentley
Simplified tests
613
        mangle_tree.delete_versioned(dfile)
614
        mangle_tree.unversion_file(dfile)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
615
        mfile = mangle_tree.trans_id_tree_file_id('mfile')
1534.7.59 by Aaron Bentley
Simplified tests
616
        mangle_tree.adjust_path('mfile', root, mfile)
617
618
        #tests for adding parent directories
619
        newdir = mangle_tree.new_directory('new_directory', root, 'newdir')
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
620
        mfile2 = mangle_tree.trans_id_tree_file_id('mfile2')
1534.7.59 by Aaron Bentley
Simplified tests
621
        mangle_tree.adjust_path('mfile2', newdir, mfile2)
622
        mangle_tree.new_file('newfile', newdir, 'hello3', 'dfile')
623
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
624
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
625
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
626
        mangle_tree.apply()
627
        self.assertEqual(file(self.wt.abspath('name1')).read(), 'hello2')
628
        self.assertEqual(file(self.wt.abspath('name2')).read(), 'hello1')
1534.7.176 by abentley
Fixed up tests for Windows
629
        mfile2_path = self.wt.abspath(pathjoin('new_directory','mfile2'))
1534.7.41 by Aaron Bentley
Got inventory ID movement working
630
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
1534.7.38 by Aaron Bentley
Tested adding paths
631
        self.assertEqual(file(mfile2_path).read(), 'later2')
1534.7.59 by Aaron Bentley
Simplified tests
632
        self.assertEqual(self.wt.id2path('mfile2'), 'new_directory/mfile2')
633
        self.assertEqual(self.wt.path2id('new_directory/mfile2'), 'mfile2')
1534.7.176 by abentley
Fixed up tests for Windows
634
        newfile_path = self.wt.abspath(pathjoin('new_directory','newfile'))
1534.7.38 by Aaron Bentley
Tested adding paths
635
        self.assertEqual(file(newfile_path).read(), 'hello3')
1534.7.59 by Aaron Bentley
Simplified tests
636
        self.assertEqual(self.wt.path2id('dying_directory'), 'ddir')
637
        self.assertIs(self.wt.path2id('dying_directory/dying_file'), None)
1534.7.176 by abentley
Fixed up tests for Windows
638
        mfile2_path = self.wt.abspath(pathjoin('new_directory','mfile2'))
1534.7.43 by abentley
Fixed some Windows bugs, introduced a conflicts bug
639
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
640
    def test_both_rename(self):
641
        create_tree,root = self.get_transform()
642
        newdir = create_tree.new_directory('selftest', root, 'selftest-id')
643
        create_tree.new_file('blackbox.py', newdir, 'hello1', 'blackbox-id')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
644
        create_tree.apply()
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
645
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
646
        selftest = mangle_tree.trans_id_tree_file_id('selftest-id')
647
        blackbox = mangle_tree.trans_id_tree_file_id('blackbox-id')
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
648
        mangle_tree.adjust_path('test', root, selftest)
649
        mangle_tree.adjust_path('test_too_much', root, selftest)
650
        mangle_tree.set_executability(True, blackbox)
651
        mangle_tree.apply()
652
653
    def test_both_rename2(self):
654
        create_tree,root = self.get_transform()
655
        bzrlib = create_tree.new_directory('bzrlib', root, 'bzrlib-id')
656
        tests = create_tree.new_directory('tests', bzrlib, 'tests-id')
657
        blackbox = create_tree.new_directory('blackbox', tests, 'blackbox-id')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
658
        create_tree.new_file('test_too_much.py', blackbox, 'hello1',
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
659
                             'test_too_much-id')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
660
        create_tree.apply()
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
661
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
662
        bzrlib = mangle_tree.trans_id_tree_file_id('bzrlib-id')
663
        tests = mangle_tree.trans_id_tree_file_id('tests-id')
664
        test_too_much = mangle_tree.trans_id_tree_file_id('test_too_much-id')
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
665
        mangle_tree.adjust_path('selftest', bzrlib, tests)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
666
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
667
        mangle_tree.set_executability(True, test_too_much)
668
        mangle_tree.apply()
669
670
    def test_both_rename3(self):
671
        create_tree,root = self.get_transform()
672
        tests = create_tree.new_directory('tests', root, 'tests-id')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
673
        create_tree.new_file('test_too_much.py', tests, 'hello1',
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
674
                             'test_too_much-id')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
675
        create_tree.apply()
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
676
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
677
        tests = mangle_tree.trans_id_tree_file_id('tests-id')
678
        test_too_much = mangle_tree.trans_id_tree_file_id('test_too_much-id')
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
679
        mangle_tree.adjust_path('selftest', root, tests)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
680
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
681
        mangle_tree.set_executability(True, test_too_much)
682
        mangle_tree.apply()
683
1534.7.48 by Aaron Bentley
Ensured we can move/rename dangling inventory entries
684
    def test_move_dangling_ie(self):
1534.7.59 by Aaron Bentley
Simplified tests
685
        create_tree, root = self.get_transform()
686
        # prepare tree
1731.1.33 by Aaron Bentley
Revert no-special-root changes
687
        root = create_tree.root
1534.7.59 by Aaron Bentley
Simplified tests
688
        create_tree.new_file('name1', root, 'hello1', 'name1')
689
        create_tree.apply()
690
        delete_contents, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
691
        file = delete_contents.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
692
        delete_contents.delete_contents(file)
693
        delete_contents.apply()
694
        move_id, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
695
        name1 = move_id.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
696
        newdir = move_id.new_directory('dir', root, 'newdir')
697
        move_id.adjust_path('name2', newdir, name1)
698
        move_id.apply()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
699
1534.7.50 by Aaron Bentley
Detect duplicate inventory ids
700
    def test_replace_dangling_ie(self):
1534.7.59 by Aaron Bentley
Simplified tests
701
        create_tree, root = self.get_transform()
702
        # prepare tree
1731.1.33 by Aaron Bentley
Revert no-special-root changes
703
        root = create_tree.root
1534.7.59 by Aaron Bentley
Simplified tests
704
        create_tree.new_file('name1', root, 'hello1', 'name1')
705
        create_tree.apply()
706
        delete_contents = TreeTransform(self.wt)
707
        self.addCleanup(delete_contents.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
708
        file = delete_contents.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
709
        delete_contents.delete_contents(file)
710
        delete_contents.apply()
711
        delete_contents.finalize()
712
        replace = TreeTransform(self.wt)
713
        self.addCleanup(replace.finalize)
714
        name2 = replace.new_file('name2', root, 'hello2', 'name1')
715
        conflicts = replace.find_conflicts()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
716
        name1 = replace.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
717
        self.assertEqual(conflicts, [('duplicate id', name1, name2)])
718
        resolve_conflicts(replace)
719
        replace.apply()
1534.7.48 by Aaron Bentley
Ensured we can move/rename dangling inventory entries
720
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
721
    def _test_symlinks(self, link_name1,link_target1,
722
                       link_name2, link_target2):
723
724
        def ozpath(p): return 'oz/' + p
725
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
726
        self.requireFeature(SymlinkFeature)
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
727
        transform, root = self.get_transform()
1534.7.59 by Aaron Bentley
Simplified tests
728
        oz_id = transform.new_directory('oz', root, 'oz-id')
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
729
        wizard = transform.new_symlink(link_name1, oz_id, link_target1,
1534.7.59 by Aaron Bentley
Simplified tests
730
                                       'wizard-id')
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
731
        wiz_id = transform.create_path(link_name2, oz_id)
732
        transform.create_symlink(link_target2, wiz_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
733
        transform.version_file('wiz-id2', wiz_id)
1534.7.71 by abentley
All tests pass under Windows
734
        transform.set_executability(True, wiz_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
735
        self.assertEqual(transform.find_conflicts(),
1534.7.71 by abentley
All tests pass under Windows
736
                         [('non-file executability', wiz_id)])
737
        transform.set_executability(None, wiz_id)
1534.7.59 by Aaron Bentley
Simplified tests
738
        transform.apply()
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
739
        self.assertEqual(self.wt.path2id(ozpath(link_name1)), 'wizard-id')
740
        self.assertEqual('symlink',
741
                         file_kind(self.wt.abspath(ozpath(link_name1))))
742
        self.assertEqual(link_target2,
743
                         osutils.readlink(self.wt.abspath(ozpath(link_name2))))
744
        self.assertEqual(link_target1,
745
                         osutils.readlink(self.wt.abspath(ozpath(link_name1))))
746
747
    def test_symlinks(self):
748
        self._test_symlinks('wizard', 'wizard-target',
749
                            'wizard2', 'behind_curtain')
750
751
    def test_symlinks_unicode(self):
752
        self.requireFeature(tests.UnicodeFilenameFeature)
753
        self._test_symlinks(u'\N{Euro Sign}wizard',
754
                            u'wizard-targ\N{Euro Sign}t',
755
                            u'\N{Euro Sign}wizard2',
756
                            u'b\N{Euro Sign}hind_curtain')
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
757
3006.2.2 by Alexander Belchenko
tests added.
758
    def test_unable_create_symlink(self):
759
        def tt_helper():
760
            wt = self.make_branch_and_tree('.')
761
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
762
            try:
763
                tt.new_symlink('foo', tt.root, 'bar')
764
                tt.apply()
765
            finally:
766
                wt.unlock()
767
        os_symlink = getattr(os, 'symlink', None)
768
        os.symlink = None
769
        try:
770
            err = self.assertRaises(errors.UnableCreateSymlink, tt_helper)
771
            self.assertEquals(
772
                "Unable to create symlink 'foo' on this platform",
773
                str(err))
774
        finally:
775
            if os_symlink:
776
                os.symlink = os_symlink
777
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
778
    def get_conflicted(self):
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
779
        create,root = self.get_transform()
780
        create.new_file('dorothy', root, 'dorothy', 'dorothy-id')
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
781
        oz = create.new_directory('oz', root, 'oz-id')
782
        create.new_directory('emeraldcity', oz, 'emerald-id')
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
783
        create.apply()
784
        conflicts,root = self.get_transform()
1534.7.65 by Aaron Bentley
Text cleaup/docs
785
        # set up duplicate entry, duplicate id
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
786
        new_dorothy = conflicts.new_file('dorothy', root, 'dorothy',
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
787
                                         'dorothy-id')
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
788
        old_dorothy = conflicts.trans_id_tree_file_id('dorothy-id')
789
        oz = conflicts.trans_id_tree_file_id('oz-id')
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
790
        # set up DeletedParent parent conflict
1534.7.65 by Aaron Bentley
Text cleaup/docs
791
        conflicts.delete_versioned(oz)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
792
        emerald = conflicts.trans_id_tree_file_id('emerald-id')
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
793
        # set up MissingParent conflict
794
        munchkincity = conflicts.trans_id_file_id('munchkincity-id')
795
        conflicts.adjust_path('munchkincity', root, munchkincity)
796
        conflicts.new_directory('auntem', munchkincity, 'auntem-id')
1534.7.65 by Aaron Bentley
Text cleaup/docs
797
        # set up parent loop
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
798
        conflicts.adjust_path('emeraldcity', emerald, emerald)
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
799
        return conflicts, emerald, oz, old_dorothy, new_dorothy
800
801
    def test_conflict_resolution(self):
802
        conflicts, emerald, oz, old_dorothy, new_dorothy =\
803
            self.get_conflicted()
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
804
        resolve_conflicts(conflicts)
805
        self.assertEqual(conflicts.final_name(old_dorothy), 'dorothy.moved')
806
        self.assertIs(conflicts.final_file_id(old_dorothy), None)
807
        self.assertEqual(conflicts.final_name(new_dorothy), 'dorothy')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
808
        self.assertEqual(conflicts.final_file_id(new_dorothy), 'dorothy-id')
1534.7.64 by Aaron Bentley
Extra testing
809
        self.assertEqual(conflicts.final_parent(emerald), oz)
1534.7.63 by Aaron Bentley
Ensure transform can be applied after resolution
810
        conflicts.apply()
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
811
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
812
    def test_cook_conflicts(self):
813
        tt, emerald, oz, old_dorothy, new_dorothy = self.get_conflicted()
814
        raw_conflicts = resolve_conflicts(tt)
815
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
816
        duplicate = DuplicateEntry('Moved existing file to', 'dorothy.moved',
1534.10.20 by Aaron Bentley
Got all tests passing
817
                                   'dorothy', None, 'dorothy-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
818
        self.assertEqual(cooked_conflicts[0], duplicate)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
819
        duplicate_id = DuplicateID('Unversioned existing file',
1534.10.20 by Aaron Bentley
Got all tests passing
820
                                   'dorothy.moved', 'dorothy', None,
821
                                   'dorothy-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
822
        self.assertEqual(cooked_conflicts[1], duplicate_id)
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
823
        missing_parent = MissingParent('Created directory', 'munchkincity',
824
                                       'munchkincity-id')
825
        deleted_parent = DeletingParent('Not deleting', 'oz', 'oz-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
826
        self.assertEqual(cooked_conflicts[2], missing_parent)
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
827
        unversioned_parent = UnversionedParent('Versioned directory',
828
                                               'munchkincity',
829
                                               'munchkincity-id')
830
        unversioned_parent2 = UnversionedParent('Versioned directory', 'oz',
1534.10.20 by Aaron Bentley
Got all tests passing
831
                                               'oz-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
832
        self.assertEqual(cooked_conflicts[3], unversioned_parent)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
833
        parent_loop = ParentLoop('Cancelled move', 'oz/emeraldcity',
1534.10.20 by Aaron Bentley
Got all tests passing
834
                                 'oz/emeraldcity', 'emerald-id', 'emerald-id')
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
835
        self.assertEqual(cooked_conflicts[4], deleted_parent)
836
        self.assertEqual(cooked_conflicts[5], unversioned_parent2)
837
        self.assertEqual(cooked_conflicts[6], parent_loop)
838
        self.assertEqual(len(cooked_conflicts), 7)
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
839
        tt.finalize()
840
841
    def test_string_conflicts(self):
842
        tt, emerald, oz, old_dorothy, new_dorothy = self.get_conflicted()
843
        raw_conflicts = resolve_conflicts(tt)
844
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
845
        tt.finalize()
5898.1.7 by Martin
Fix TestTreeTransform.test_string_conflicts to use unicode()
846
        conflicts_s = [unicode(c) for c in cooked_conflicts]
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
847
        self.assertEqual(len(cooked_conflicts), len(conflicts_s))
848
        self.assertEqual(conflicts_s[0], 'Conflict adding file dorothy.  '
849
                                         'Moved existing file to '
850
                                         'dorothy.moved.')
851
        self.assertEqual(conflicts_s[1], 'Conflict adding id to dorothy.  '
852
                                         'Unversioned existing file '
853
                                         'dorothy.moved.')
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
854
        self.assertEqual(conflicts_s[2], 'Conflict adding files to'
855
                                         ' munchkincity.  Created directory.')
856
        self.assertEqual(conflicts_s[3], 'Conflict because munchkincity is not'
857
                                         ' versioned, but has versioned'
858
                                         ' children.  Versioned directory.')
1551.8.23 by Aaron Bentley
Tweaked conflict message to be more understandable
859
        self.assertEqualDiff(conflicts_s[4], "Conflict: can't delete oz because it"
860
                                         " is not empty.  Not deleting.")
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
861
        self.assertEqual(conflicts_s[5], 'Conflict because oz is not'
862
                                         ' versioned, but has versioned'
863
                                         ' children.  Versioned directory.')
864
        self.assertEqual(conflicts_s[6], 'Conflict moving oz/emeraldcity into'
4597.8.11 by Vincent Ladeuil
The ParentLoop.format has been updated, fix fallouts.
865
                                         ' oz/emeraldcity. Cancelled move.')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
866
3144.4.2 by Aaron Bentley
Handle non-directory parent conflicts (abentley, #177390)
867
    def prepare_wrong_parent_kind(self):
868
        tt, root = self.get_transform()
869
        tt.new_file('parent', root, 'contents', 'parent-id')
870
        tt.apply()
871
        tt, root = self.get_transform()
872
        parent_id = tt.trans_id_file_id('parent-id')
873
        tt.new_file('child,', parent_id, 'contents2', 'file-id')
874
        return tt
875
3144.4.1 by Aaron Bentley
Handle trying to list parents of a non-directory
876
    def test_find_conflicts_wrong_parent_kind(self):
3144.4.2 by Aaron Bentley
Handle non-directory parent conflicts (abentley, #177390)
877
        tt = self.prepare_wrong_parent_kind()
3144.4.1 by Aaron Bentley
Handle trying to list parents of a non-directory
878
        tt.find_conflicts()
879
3144.4.2 by Aaron Bentley
Handle non-directory parent conflicts (abentley, #177390)
880
    def test_resolve_conflicts_wrong_existing_parent_kind(self):
881
        tt = self.prepare_wrong_parent_kind()
882
        raw_conflicts = resolve_conflicts(tt)
883
        self.assertEqual(set([('non-directory parent', 'Created directory',
884
                         'new-3')]), raw_conflicts)
885
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
886
        self.assertEqual([NonDirectoryParent('Created directory', 'parent.new',
887
        'parent-id')], cooked_conflicts)
888
        tt.apply()
889
        self.assertEqual(None, self.wt.path2id('parent'))
890
        self.assertEqual('parent-id', self.wt.path2id('parent.new'))
891
892
    def test_resolve_conflicts_wrong_new_parent_kind(self):
893
        tt, root = self.get_transform()
894
        parent_id = tt.new_directory('parent', root, 'parent-id')
895
        tt.new_file('child,', parent_id, 'contents2', 'file-id')
896
        tt.apply()
897
        tt, root = self.get_transform()
898
        parent_id = tt.trans_id_file_id('parent-id')
899
        tt.delete_contents(parent_id)
900
        tt.create_file('contents', parent_id)
901
        raw_conflicts = resolve_conflicts(tt)
902
        self.assertEqual(set([('non-directory parent', 'Created directory',
903
                         'new-3')]), raw_conflicts)
904
        tt.apply()
905
        self.assertEqual(None, self.wt.path2id('parent'))
906
        self.assertEqual('parent-id', self.wt.path2id('parent.new'))
907
908
    def test_resolve_conflicts_wrong_parent_kind_unversioned(self):
909
        tt, root = self.get_transform()
910
        parent_id = tt.new_directory('parent', root)
911
        tt.new_file('child,', parent_id, 'contents2')
912
        tt.apply()
913
        tt, root = self.get_transform()
914
        parent_id = tt.trans_id_tree_path('parent')
915
        tt.delete_contents(parent_id)
916
        tt.create_file('contents', parent_id)
917
        resolve_conflicts(tt)
918
        tt.apply()
919
        self.assertIs(None, self.wt.path2id('parent'))
920
        self.assertIs(None, self.wt.path2id('parent.new'))
921
5409.5.1 by Vincent Ladeuil
Tweak test_resolve_conflicts_missing_parent (renamed from test_resolve_no_parent), puttinh it in the right place.
922
    def test_resolve_conflicts_missing_parent(self):
923
        wt = self.make_branch_and_tree('.')
924
        tt = TreeTransform(wt)
925
        self.addCleanup(tt.finalize)
926
        parent = tt.trans_id_file_id('parent-id')
927
        tt.new_file('file', parent, 'Contents')
928
        raw_conflicts = resolve_conflicts(tt)
5409.6.2 by Vincent Ladeuil
Fix typo in the comment.
929
        # Since the directory doesn't exist it's seen as 'missing'.  So
930
        # 'resolve_conflicts' create a conflict asking for it to be created.
5409.5.1 by Vincent Ladeuil
Tweak test_resolve_conflicts_missing_parent (renamed from test_resolve_no_parent), puttinh it in the right place.
931
        self.assertLength(1, raw_conflicts)
932
        self.assertEqual(('missing parent', 'Created directory', 'new-1'),
933
                         raw_conflicts.pop())
5409.6.1 by Vincent Ladeuil
Clarify test intent and behaviour.
934
        # apply fail since the missing directory doesn't exist
935
        self.assertRaises(errors.NoFinalPath, tt.apply)
5409.5.1 by Vincent Ladeuil
Tweak test_resolve_conflicts_missing_parent (renamed from test_resolve_no_parent), puttinh it in the right place.
936
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
937
    def test_moving_versioned_directories(self):
938
        create, root = self.get_transform()
939
        kansas = create.new_directory('kansas', root, 'kansas-id')
940
        create.new_directory('house', kansas, 'house-id')
941
        create.new_directory('oz', root, 'oz-id')
942
        create.apply()
943
        cyclone, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
944
        oz = cyclone.trans_id_tree_file_id('oz-id')
945
        house = cyclone.trans_id_tree_file_id('house-id')
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
946
        cyclone.adjust_path('house', oz, house)
947
        cyclone.apply()
1534.7.66 by Aaron Bentley
Ensured we don't accidentally move the root directory
948
949
    def test_moving_root(self):
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
950
        create, root = self.get_transform()
951
        fun = create.new_directory('fun', root, 'fun-id')
952
        create.new_directory('sun', root, 'sun-id')
953
        create.new_directory('moon', root, 'moon')
954
        create.apply()
1534.7.66 by Aaron Bentley
Ensured we don't accidentally move the root directory
955
        transform, root = self.get_transform()
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
956
        transform.adjust_root_path('oldroot', fun)
4634.122.2 by Aaron Bentley, John Arbash Meinel
Bring the fixup_new_roots code from the nested-trees code.
957
        new_root = transform.trans_id_tree_path('')
1534.7.69 by Aaron Bentley
Got real root moves working
958
        transform.version_file('new-root', new_root)
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
959
        transform.apply()
1534.7.93 by Aaron Bentley
Added text merge test
960
1534.7.114 by Aaron Bentley
Added file renaming test case
961
    def test_renames(self):
962
        create, root = self.get_transform()
963
        old = create.new_directory('old-parent', root, 'old-id')
964
        intermediate = create.new_directory('intermediate', old, 'im-id')
965
        myfile = create.new_file('myfile', intermediate, 'myfile-text',
966
                                 'myfile-id')
967
        create.apply()
968
        rename, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
969
        old = rename.trans_id_file_id('old-id')
1534.7.114 by Aaron Bentley
Added file renaming test case
970
        rename.adjust_path('new', root, old)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
971
        myfile = rename.trans_id_file_id('myfile-id')
1534.7.114 by Aaron Bentley
Added file renaming test case
972
        rename.set_executability(True, myfile)
973
        rename.apply()
974
5186.2.4 by Martin Pool
Add failing specific test for 491763
975
    def test_rename_fails(self):
5050.43.1 by Vincent Ladeuil
Fix one more failure when the test suite is run as root.
976
        self.requireFeature(features.not_running_as_root)
5186.2.4 by Martin Pool
Add failing specific test for 491763
977
        # see https://bugs.launchpad.net/bzr/+bug/491763
978
        create, root_id = self.get_transform()
979
        first_dir = create.new_directory('first-dir', root_id, 'first-id')
980
        myfile = create.new_file('myfile', root_id, 'myfile-text',
981
                                 'myfile-id')
982
        create.apply()
5050.15.2 by Martin
Correct bt.test_transform.TestTreeTransform.test_rename_fails on non-posix platforms
983
        if os.name == "posix" and sys.platform != "cygwin":
984
            # posix filesystems fail on renaming if the readonly bit is set
985
            osutils.make_readonly(self.wt.abspath('first-dir'))
986
        elif os.name == "nt":
987
            # windows filesystems fail on renaming open files
988
            self.addCleanup(file(self.wt.abspath('myfile')).close)
989
        else:
990
            self.skip("Don't know how to force a permissions error on rename")
5186.2.4 by Martin Pool
Add failing specific test for 491763
991
        # now transform to rename
992
        rename_transform, root_id = self.get_transform()
993
        file_trans_id = rename_transform.trans_id_file_id('myfile-id')
994
        dir_id = rename_transform.trans_id_file_id('first-id')
995
        rename_transform.adjust_path('newname', dir_id, file_trans_id)
5186.2.5 by Martin Pool
Raise a specific clearer error when a rename fails inside transform
996
        e = self.assertRaises(errors.TransformRenameFailed,
997
            rename_transform.apply)
5050.15.2 by Martin
Correct bt.test_transform.TestTreeTransform.test_rename_fails on non-posix platforms
998
        # On nix looks like: 
5186.2.5 by Martin Pool
Raise a specific clearer error when a rename fails inside transform
999
        # "Failed to rename .../work/.bzr/checkout/limbo/new-1
1000
        # to .../first-dir/newname: [Errno 13] Permission denied"
5050.15.2 by Martin
Correct bt.test_transform.TestTreeTransform.test_rename_fails on non-posix platforms
1001
        # On windows looks like:
1002
        # "Failed to rename .../work/myfile to 
1003
        # .../work/.bzr/checkout/limbo/new-1: [Errno 13] Permission denied"
5582.8.1 by Martin
Make bt.test_transform.TestTreeTransform.test_rename_fails not care about the exact stringification of the exception instance
1004
        # This test isn't concerned with exactly what the error looks like,
1005
        # and the strerror will vary across OS and locales, but the assert
1006
        # that the exeception attributes are what we expect
1007
        self.assertEqual(e.errno, errno.EACCES)
1008
        if os.name == "posix":
1009
            self.assertEndsWith(e.to_path, "/first-dir/newname")
1010
        else:
1011
            self.assertEqual(os.path.basename(e.from_path), "myfile")
5186.2.4 by Martin Pool
Add failing specific test for 491763
1012
1740.2.4 by Aaron Bentley
Update transform tests and docs
1013
    def test_set_executability_order(self):
1014
        """Ensure that executability behaves the same, no matter what order.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1015
1740.2.4 by Aaron Bentley
Update transform tests and docs
1016
        - create file and set executability simultaneously
1017
        - create file and set executability afterward
1018
        - unsetting the executability of a file whose executability has not been
1019
        declared should throw an exception (this may happen when a
1020
        merge attempts to create a file with a duplicate ID)
1021
        """
1022
        transform, root = self.get_transform()
1023
        wt = transform._tree
3034.2.1 by Aaron Bentley
Fix is_executable tests for win32
1024
        wt.lock_read()
1025
        self.addCleanup(wt.unlock)
1740.2.4 by Aaron Bentley
Update transform tests and docs
1026
        transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
1027
                           True)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1028
        sac = transform.new_file('set_after_creation', root,
1029
                                 'Set after creation', 'sac')
1740.2.4 by Aaron Bentley
Update transform tests and docs
1030
        transform.set_executability(True, sac)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1031
        uws = transform.new_file('unset_without_set', root, 'Unset badly',
1032
                                 'uws')
1740.2.4 by Aaron Bentley
Update transform tests and docs
1033
        self.assertRaises(KeyError, transform.set_executability, None, uws)
1034
        transform.apply()
1035
        self.assertTrue(wt.is_executable('soc'))
1036
        self.assertTrue(wt.is_executable('sac'))
1037
1534.12.2 by Aaron Bentley
Added test for preserving file mode
1038
    def test_preserve_mode(self):
1039
        """File mode is preserved when replacing content"""
1040
        if sys.platform == 'win32':
1041
            raise TestSkipped('chmod has no effect on win32')
1042
        transform, root = self.get_transform()
1043
        transform.new_file('file1', root, 'contents', 'file1-id', True)
1044
        transform.apply()
3146.4.12 by Aaron Bentley
Add needed write lock to test
1045
        self.wt.lock_write()
1046
        self.addCleanup(self.wt.unlock)
1534.12.2 by Aaron Bentley
Added test for preserving file mode
1047
        self.assertTrue(self.wt.is_executable('file1-id'))
1048
        transform, root = self.get_transform()
1049
        file1_id = transform.trans_id_tree_file_id('file1-id')
1050
        transform.delete_contents(file1_id)
1051
        transform.create_file('contents2', file1_id)
1052
        transform.apply()
1053
        self.assertTrue(self.wt.is_executable('file1-id'))
1054
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
1055
    def test__set_mode_stats_correctly(self):
1056
        """_set_mode stats to determine file mode."""
1057
        if sys.platform == 'win32':
1058
            raise TestSkipped('chmod has no effect on win32')
1059
1060
        stat_paths = []
1061
        real_stat = os.stat
1062
        def instrumented_stat(path):
1063
            stat_paths.append(path)
1064
            return real_stat(path)
1065
1066
        transform, root = self.get_transform()
1067
1068
        bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
1069
                                     file_id='bar-id-1', executable=False)
1070
        transform.apply()
1071
1072
        transform, root = self.get_transform()
1073
        bar1_id = transform.trans_id_tree_path('bar')
1074
        bar2_id = transform.trans_id_tree_path('bar2')
1075
        try:
1076
            os.stat = instrumented_stat
1077
            transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
1078
        finally:
1079
            os.stat = real_stat
1080
            transform.finalize()
1081
1082
        bar1_abspath = self.wt.abspath('bar')
1083
        self.assertEqual([bar1_abspath], stat_paths)
1084
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1085
    def test_iter_changes(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1086
        self.wt.set_root_id('eert_toor')
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1087
        transform, root = self.get_transform()
1088
        transform.new_file('old', root, 'blah', 'id-1', True)
1089
        transform.apply()
1090
        transform, root = self.get_transform()
1091
        try:
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1092
            self.assertEqual([], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1093
            old = transform.trans_id_tree_file_id('id-1')
1094
            transform.unversion_file(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1095
            self.assertEqual([('id-1', ('old', None), False, (True, False),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1096
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1097
                (True, True))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1098
            transform.new_directory('new', root, 'id-1')
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1099
            self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1100
                ('eert_toor', 'eert_toor'), ('old', 'new'),
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1101
                ('file', 'directory'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1102
                (True, False))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1103
        finally:
1104
            transform.finalize()
1105
1106
    def test_iter_changes_new(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1107
        self.wt.set_root_id('eert_toor')
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1108
        transform, root = self.get_transform()
1109
        transform.new_file('old', root, 'blah')
1110
        transform.apply()
1111
        transform, root = self.get_transform()
1112
        try:
1113
            old = transform.trans_id_tree_path('old')
1114
            transform.version_file('id-1', old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1115
            self.assertEqual([('id-1', (None, 'old'), False, (False, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1116
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1117
                (False, False))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1118
        finally:
1119
            transform.finalize()
1120
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1121
    def test_iter_changes_modifications(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1122
        self.wt.set_root_id('eert_toor')
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1123
        transform, root = self.get_transform()
1124
        transform.new_file('old', root, 'blah', 'id-1')
1125
        transform.new_file('new', root, 'blah')
1126
        transform.new_directory('subdir', root, 'subdir-id')
1127
        transform.apply()
1128
        transform, root = self.get_transform()
1129
        try:
1130
            old = transform.trans_id_tree_path('old')
1131
            subdir = transform.trans_id_tree_file_id('subdir-id')
1132
            new = transform.trans_id_tree_path('new')
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1133
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1134
1135
            #content deletion
1136
            transform.delete_contents(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1137
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1138
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1139
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1140
1141
            #content change
1142
            transform.create_file('blah', old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1143
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1144
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1145
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1146
            transform.cancel_deletion(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1147
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1148
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1149
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1150
            transform.cancel_creation(old)
1151
1152
            # move file_id to a different file
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1153
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1154
            transform.unversion_file(old)
1155
            transform.version_file('id-1', new)
1156
            transform.adjust_path('old', root, new)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1157
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1158
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1159
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1160
            transform.cancel_versioning(new)
1161
            transform._removed_id = set()
1162
1163
            #execute bit
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1164
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1165
            transform.set_executability(True, old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1166
            self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1167
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1168
                (False, True))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1169
            transform.set_executability(None, old)
1170
1171
            # filename
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1172
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1173
            transform.adjust_path('new', root, old)
1174
            transform._new_parent = {}
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1175
            self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1176
                ('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1177
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1178
            transform._new_name = {}
1179
1180
            # parent directory
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1181
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1182
            transform.adjust_path('new', subdir, old)
1183
            transform._new_name = {}
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1184
            self.assertEqual([('id-1', ('old', 'subdir/old'), False,
2255.2.180 by Martin Pool
merge dirstate
1185
                (True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1186
                ('file', 'file'), (False, False))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1187
                list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1188
            transform._new_path = {}
1189
1190
        finally:
1191
            transform.finalize()
1192
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1193
    def test_iter_changes_modified_bleed(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1194
        self.wt.set_root_id('eert_toor')
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1195
        """Modified flag should not bleed from one change to another"""
1196
        # unfortunately, we have no guarantee that file1 (which is modified)
1197
        # will be applied before file2.  And if it's applied after file2, it
1198
        # obviously can't bleed into file2's change output.  But for now, it
1199
        # works.
1200
        transform, root = self.get_transform()
1201
        transform.new_file('file1', root, 'blah', 'id-1')
1202
        transform.new_file('file2', root, 'blah', 'id-2')
1203
        transform.apply()
1204
        transform, root = self.get_transform()
1205
        try:
1206
            transform.delete_contents(transform.trans_id_file_id('id-1'))
1207
            transform.set_executability(True,
1208
            transform.trans_id_file_id('id-2'))
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1209
            self.assertEqual([('id-1', (u'file1', u'file1'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1210
                ('eert_toor', 'eert_toor'), ('file1', u'file1'),
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1211
                ('file', None), (False, False)),
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1212
                ('id-2', (u'file2', u'file2'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1213
                ('eert_toor', 'eert_toor'), ('file2', u'file2'),
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1214
                ('file', 'file'), (False, True))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1215
                list(transform.iter_changes()))
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1216
        finally:
1217
            transform.finalize()
1218
1551.10.37 by Aaron Bentley
recommit of TreeTransform._iter_changes fix with missing files
1219
    def test_iter_changes_move_missing(self):
1220
        """Test moving ids with no files around"""
1221
        self.wt.set_root_id('toor_eert')
1222
        # Need two steps because versioning a non-existant file is a conflict.
1223
        transform, root = self.get_transform()
1224
        transform.new_directory('floater', root, 'floater-id')
1225
        transform.apply()
1226
        transform, root = self.get_transform()
1227
        transform.delete_contents(transform.trans_id_tree_path('floater'))
1228
        transform.apply()
1229
        transform, root = self.get_transform()
1230
        floater = transform.trans_id_tree_path('floater')
1231
        try:
1232
            transform.adjust_path('flitter', root, floater)
1233
            self.assertEqual([('floater-id', ('floater', 'flitter'), False,
1234
            (True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1235
            (None, None), (False, False))], list(transform.iter_changes()))
1551.10.37 by Aaron Bentley
recommit of TreeTransform._iter_changes fix with missing files
1236
        finally:
1237
            transform.finalize()
1238
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1239
    def test_iter_changes_pointless(self):
1240
        """Ensure that no-ops are not treated as modifications"""
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1241
        self.wt.set_root_id('eert_toor')
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1242
        transform, root = self.get_transform()
1243
        transform.new_file('old', root, 'blah', 'id-1')
1244
        transform.new_directory('subdir', root, 'subdir-id')
1245
        transform.apply()
1246
        transform, root = self.get_transform()
1247
        try:
1248
            old = transform.trans_id_tree_path('old')
1249
            subdir = transform.trans_id_tree_file_id('subdir-id')
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1250
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1251
            transform.delete_contents(subdir)
1252
            transform.create_directory(subdir)
1253
            transform.set_executability(False, old)
1254
            transform.unversion_file(old)
1255
            transform.version_file('id-1', old)
1256
            transform.adjust_path('old', root, old)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1257
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1258
        finally:
1259
            transform.finalize()
1534.7.93 by Aaron Bentley
Added text merge test
1260
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1261
    def test_rename_count(self):
1262
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1263
        transform.new_file('name1', root, 'contents')
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1264
        self.assertEqual(transform.rename_count, 0)
1265
        transform.apply()
1266
        self.assertEqual(transform.rename_count, 1)
1267
        transform2, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1268
        transform2.adjust_path('name2', root,
1269
                               transform2.trans_id_tree_path('name1'))
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1270
        self.assertEqual(transform2.rename_count, 0)
1271
        transform2.apply()
1272
        self.assertEqual(transform2.rename_count, 2)
1273
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1274
    def test_change_parent(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1275
        """Ensure that after we change a parent, the results are still right.
1276
1277
        Renames and parent changes on pending transforms can happen as part
1278
        of conflict resolution, and are explicitly permitted by the
1279
        TreeTransform API.
1280
1281
        This test ensures they work correctly with the rename-avoidance
1282
        optimization.
1283
        """
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1284
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1285
        parent1 = transform.new_directory('parent1', root)
1286
        child1 = transform.new_file('child1', parent1, 'contents')
1287
        parent2 = transform.new_directory('parent2', root)
1288
        transform.adjust_path('child1', parent2, child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1289
        transform.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1290
        self.assertPathDoesNotExist(self.wt.abspath('parent1/child1'))
1291
        self.assertPathExists(self.wt.abspath('parent2/child1'))
2502.1.8 by Aaron Bentley
Updates from review comments
1292
        # rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
1293
        # no rename for child1 (counting only renames during apply)
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1294
        self.assertEqual(2, transform.rename_count)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1295
1296
    def test_cancel_parent(self):
1297
        """Cancelling a parent doesn't cause deletion of a non-empty directory
1298
1299
        This is like the test_change_parent, except that we cancel the parent
1300
        before adjusting the path.  The transform must detect that the
1301
        directory is non-empty, and move children to safe locations.
1302
        """
1303
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1304
        parent1 = transform.new_directory('parent1', root)
1305
        child1 = transform.new_file('child1', parent1, 'contents')
1306
        child2 = transform.new_file('child2', parent1, 'contents')
1307
        try:
1308
            transform.cancel_creation(parent1)
1309
        except OSError:
1310
            self.fail('Failed to move child1 before deleting parent1')
1311
        transform.cancel_creation(child2)
1312
        transform.create_directory(parent1)
1313
        try:
1314
            transform.cancel_creation(parent1)
1315
        # If the transform incorrectly believes that child2 is still in
1316
        # parent1's limbo directory, it will try to rename it and fail
1317
        # because was already moved by the first cancel_creation.
1318
        except OSError:
1319
            self.fail('Transform still thinks child2 is a child of parent1')
1320
        parent2 = transform.new_directory('parent2', root)
1321
        transform.adjust_path('child1', parent2, child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1322
        transform.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1323
        self.assertPathDoesNotExist(self.wt.abspath('parent1'))
1324
        self.assertPathExists(self.wt.abspath('parent2/child1'))
2502.1.8 by Aaron Bentley
Updates from review comments
1325
        # rename limbo/new-3 => parent2, rename limbo/new-2 => child1
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1326
        self.assertEqual(2, transform.rename_count)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1327
1328
    def test_adjust_and_cancel(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1329
        """Make sure adjust_path keeps track of limbo children properly"""
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1330
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1331
        parent1 = transform.new_directory('parent1', root)
1332
        child1 = transform.new_file('child1', parent1, 'contents')
1333
        parent2 = transform.new_directory('parent2', root)
1334
        transform.adjust_path('child1', parent2, child1)
1335
        transform.cancel_creation(child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1336
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1337
            transform.cancel_creation(parent1)
1338
        # if the transform thinks child1 is still in parent1's limbo
1339
        # directory, it will attempt to move it and fail.
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1340
        except OSError:
2502.1.8 by Aaron Bentley
Updates from review comments
1341
            self.fail('Transform still thinks child1 is a child of parent1')
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1342
        transform.finalize()
1343
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1344
    def test_noname_contents(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1345
        """TreeTransform should permit deferring naming files."""
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1346
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1347
        parent = transform.trans_id_file_id('parent-id')
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1348
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1349
            transform.create_directory(parent)
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1350
        except KeyError:
1351
            self.fail("Can't handle contents with no name")
1352
        transform.finalize()
1353
2502.1.9 by Aaron Bentley
Add additional test for no-name contents
1354
    def test_noname_contents_nested(self):
1355
        """TreeTransform should permit deferring naming files."""
1356
        transform, root = self.get_transform()
1357
        parent = transform.trans_id_file_id('parent-id')
1358
        try:
1359
            transform.create_directory(parent)
1360
        except KeyError:
1361
            self.fail("Can't handle contents with no name")
1362
        child = transform.new_directory('child', parent)
1363
        transform.adjust_path('parent', root, parent)
1364
        transform.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1365
        self.assertPathExists(self.wt.abspath('parent/child'))
2502.1.9 by Aaron Bentley
Add additional test for no-name contents
1366
        self.assertEqual(1, transform.rename_count)
1367
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1368
    def test_reuse_name(self):
1369
        """Avoid reusing the same limbo name for different files"""
1370
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1371
        parent = transform.new_directory('parent', root)
1372
        child1 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1373
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1374
            child2 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1375
        except OSError:
1376
            self.fail('Tranform tried to use the same limbo name twice')
2502.1.8 by Aaron Bentley
Updates from review comments
1377
        transform.adjust_path('child2', parent, child2)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1378
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1379
        # limbo/new-1 => parent, limbo/new-3 => parent/child2
1380
        # child2 is put into top-level limbo because child1 has already
1381
        # claimed the direct limbo path when child2 is created.  There is no
1382
        # advantage in renaming files once they're in top-level limbo, except
1383
        # as part of apply.
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1384
        self.assertEqual(2, transform.rename_count)
1385
1386
    def test_reuse_when_first_moved(self):
1387
        """Don't avoid direct paths when it is safe to use them"""
1388
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1389
        parent = transform.new_directory('parent', root)
1390
        child1 = transform.new_directory('child', parent)
1391
        transform.adjust_path('child1', parent, child1)
1392
        child2 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1393
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1394
        # limbo/new-1 => parent
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1395
        self.assertEqual(1, transform.rename_count)
1396
1397
    def test_reuse_after_cancel(self):
1398
        """Don't avoid direct paths when it is safe to use them"""
1399
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1400
        parent2 = transform.new_directory('parent2', root)
1401
        child1 = transform.new_directory('child1', parent2)
1402
        transform.cancel_creation(parent2)
1403
        transform.create_directory(parent2)
1404
        child2 = transform.new_directory('child1', parent2)
1405
        transform.adjust_path('child2', parent2, child1)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1406
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1407
        # limbo/new-1 => parent2, limbo/new-2 => parent2/child1
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1408
        self.assertEqual(2, transform.rename_count)
1409
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1410
    def test_finalize_order(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1411
        """Finalize must be done in child-to-parent order"""
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1412
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1413
        parent = transform.new_directory('parent', root)
1414
        child = transform.new_directory('child', parent)
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1415
        try:
1416
            transform.finalize()
1417
        except OSError:
2502.1.8 by Aaron Bentley
Updates from review comments
1418
            self.fail('Tried to remove parent before child1')
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1419
2502.1.13 by Aaron Bentley
Updates from review
1420
    def test_cancel_with_cancelled_child_should_succeed(self):
2502.1.12 by Aaron Bentley
Avoid renaming children with no content
1421
        transform, root = self.get_transform()
1422
        parent = transform.new_directory('parent', root)
1423
        child = transform.new_directory('child', parent)
1424
        transform.cancel_creation(child)
2502.1.13 by Aaron Bentley
Updates from review
1425
        transform.cancel_creation(parent)
2502.1.12 by Aaron Bentley
Avoid renaming children with no content
1426
        transform.finalize()
1427
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1428
    def test_rollback_on_directory_clash(self):
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1429
        def tt_helper():
3638.3.17 by Vincent Ladeuil
Fixed as per Aaron's review.
1430
            wt = self.make_branch_and_tree('.')
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1431
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1432
            try:
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1433
                foo = tt.new_directory('foo', tt.root)
1434
                tt.new_file('bar', foo, 'foobar')
1435
                baz = tt.new_directory('baz', tt.root)
1436
                tt.new_file('qux', baz, 'quux')
1437
                # Ask for a rename 'foo' -> 'baz'
1438
                tt.adjust_path('baz', tt.root, foo)
3063.1.3 by Aaron Bentley
Update for Linux
1439
                # Lie to tt that we've already resolved all conflicts.
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1440
                tt.apply(no_conflicts=True)
3063.1.3 by Aaron Bentley
Update for Linux
1441
            except:
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1442
                wt.unlock()
3063.1.3 by Aaron Bentley
Update for Linux
1443
                raise
3638.3.17 by Vincent Ladeuil
Fixed as per Aaron's review.
1444
        # The rename will fail because the target directory is not empty (but
1445
        # raises FileExists anyway).
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1446
        err = self.assertRaises(errors.FileExists, tt_helper)
1447
        self.assertContainsRe(str(err),
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1448
            "^File exists: .+/baz")
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1449
3063.1.2 by Alexander Belchenko
test for two directories clash
1450
    def test_two_directories_clash(self):
1451
        def tt_helper():
1452
            wt = self.make_branch_and_tree('.')
1453
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1454
            try:
3063.1.3 by Aaron Bentley
Update for Linux
1455
                foo_1 = tt.new_directory('foo', tt.root)
1456
                tt.new_directory('bar', foo_1)
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1457
                # Adding the same directory with a different content
3063.1.3 by Aaron Bentley
Update for Linux
1458
                foo_2 = tt.new_directory('foo', tt.root)
1459
                tt.new_directory('baz', foo_2)
1460
                # Lie to tt that we've already resolved all conflicts.
3063.1.2 by Alexander Belchenko
test for two directories clash
1461
                tt.apply(no_conflicts=True)
3063.1.3 by Aaron Bentley
Update for Linux
1462
            except:
3063.1.2 by Alexander Belchenko
test for two directories clash
1463
                wt.unlock()
3063.1.3 by Aaron Bentley
Update for Linux
1464
                raise
3063.1.2 by Alexander Belchenko
test for two directories clash
1465
        err = self.assertRaises(errors.FileExists, tt_helper)
1466
        self.assertContainsRe(str(err),
1467
            "^File exists: .+/foo")
1468
3100.1.1 by Aaron Bentley
Fix ImmortalLimbo errors when transforms fail
1469
    def test_two_directories_clash_finalize(self):
1470
        def tt_helper():
1471
            wt = self.make_branch_and_tree('.')
1472
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1473
            try:
1474
                foo_1 = tt.new_directory('foo', tt.root)
1475
                tt.new_directory('bar', foo_1)
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1476
                # Adding the same directory with a different content
3100.1.1 by Aaron Bentley
Fix ImmortalLimbo errors when transforms fail
1477
                foo_2 = tt.new_directory('foo', tt.root)
1478
                tt.new_directory('baz', foo_2)
1479
                # Lie to tt that we've already resolved all conflicts.
1480
                tt.apply(no_conflicts=True)
1481
            except:
1482
                tt.finalize()
1483
                raise
1484
        err = self.assertRaises(errors.FileExists, tt_helper)
1485
        self.assertContainsRe(str(err),
1486
            "^File exists: .+/foo")
1487
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1488
    def test_file_to_directory(self):
1489
        wt = self.make_branch_and_tree('.')
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1490
        self.build_tree(['foo'])
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1491
        wt.add(['foo'])
3590.3.1 by James Westby
Make TreeTransform update the inventory with new kind information.
1492
        wt.commit("one")
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1493
        tt = TreeTransform(wt)
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1494
        self.addCleanup(tt.finalize)
3535.6.3 by James Westby
Fix the test to not create transform conflicts.
1495
        foo_trans_id = tt.trans_id_tree_path("foo")
1496
        tt.delete_contents(foo_trans_id)
1497
        tt.create_directory(foo_trans_id)
1498
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1499
        tt.create_file(["aa\n"], bar_trans_id)
1500
        tt.version_file("bar-1", bar_trans_id)
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1501
        tt.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1502
        self.assertPathExists("foo/bar")
3590.3.2 by James Westby
Handle ->symlink changes as well.
1503
        wt.lock_read()
1504
        try:
1505
            self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1506
                    "directory")
1507
        finally:
1508
            wt.unlock()
3590.3.1 by James Westby
Make TreeTransform update the inventory with new kind information.
1509
        wt.commit("two")
1510
        changes = wt.changes_from(wt.basis_tree())
1511
        self.assertFalse(changes.has_changed(), changes)
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1512
3590.3.2 by James Westby
Handle ->symlink changes as well.
1513
    def test_file_to_symlink(self):
3590.3.3 by James Westby
Make ->file changes work as well.
1514
        self.requireFeature(SymlinkFeature)
3590.3.2 by James Westby
Handle ->symlink changes as well.
1515
        wt = self.make_branch_and_tree('.')
1516
        self.build_tree(['foo'])
1517
        wt.add(['foo'])
1518
        wt.commit("one")
1519
        tt = TreeTransform(wt)
1520
        self.addCleanup(tt.finalize)
1521
        foo_trans_id = tt.trans_id_tree_path("foo")
1522
        tt.delete_contents(foo_trans_id)
1523
        tt.create_symlink("bar", foo_trans_id)
1524
        tt.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1525
        self.assertPathExists("foo")
3590.3.2 by James Westby
Handle ->symlink changes as well.
1526
        wt.lock_read()
1527
        self.addCleanup(wt.unlock)
1528
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1529
                "symlink")
1530
3590.3.3 by James Westby
Make ->file changes work as well.
1531
    def test_dir_to_file(self):
1532
        wt = self.make_branch_and_tree('.')
1533
        self.build_tree(['foo/', 'foo/bar'])
1534
        wt.add(['foo', 'foo/bar'])
1535
        wt.commit("one")
1536
        tt = TreeTransform(wt)
1537
        self.addCleanup(tt.finalize)
1538
        foo_trans_id = tt.trans_id_tree_path("foo")
1539
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1540
        tt.delete_contents(foo_trans_id)
1541
        tt.delete_versioned(bar_trans_id)
1542
        tt.create_file(["aa\n"], foo_trans_id)
1543
        tt.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1544
        self.assertPathExists("foo")
3590.3.3 by James Westby
Make ->file changes work as well.
1545
        wt.lock_read()
1546
        self.addCleanup(wt.unlock)
1547
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1548
                "file")
1549
3590.3.4 by James Westby
Add a test for creating hardlinks as well.
1550
    def test_dir_to_hardlink(self):
3590.3.5 by James Westby
Use HardlinkFeature for the hardlink test.
1551
        self.requireFeature(HardlinkFeature)
3590.3.4 by James Westby
Add a test for creating hardlinks as well.
1552
        wt = self.make_branch_and_tree('.')
1553
        self.build_tree(['foo/', 'foo/bar'])
1554
        wt.add(['foo', 'foo/bar'])
1555
        wt.commit("one")
1556
        tt = TreeTransform(wt)
1557
        self.addCleanup(tt.finalize)
1558
        foo_trans_id = tt.trans_id_tree_path("foo")
1559
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1560
        tt.delete_contents(foo_trans_id)
1561
        tt.delete_versioned(bar_trans_id)
1562
        self.build_tree(['baz'])
1563
        tt.create_hardlink("baz", foo_trans_id)
1564
        tt.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1565
        self.assertPathExists("foo")
1566
        self.assertPathExists("baz")
3590.3.4 by James Westby
Add a test for creating hardlinks as well.
1567
        wt.lock_read()
1568
        self.addCleanup(wt.unlock)
1569
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1570
                "file")
1571
3619.2.10 by Aaron Bentley
Compensate for stale entries in TT._needs_rename
1572
    def test_no_final_path(self):
1573
        transform, root = self.get_transform()
1574
        trans_id = transform.trans_id_file_id('foo')
1575
        transform.create_file('bar', trans_id)
1576
        transform.cancel_creation(trans_id)
1577
        transform.apply()
1578
3363.17.24 by Aaron Bentley
Implement create_by_tree
1579
    def test_create_from_tree(self):
1580
        tree1 = self.make_branch_and_tree('tree1')
1581
        self.build_tree_contents([('tree1/foo/',), ('tree1/bar', 'baz')])
1582
        tree1.add(['foo', 'bar'], ['foo-id', 'bar-id'])
1583
        tree2 = self.make_branch_and_tree('tree2')
1584
        tt = TreeTransform(tree2)
1585
        foo_trans_id = tt.create_path('foo', tt.root)
1586
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1587
        bar_trans_id = tt.create_path('bar', tt.root)
1588
        create_from_tree(tt, bar_trans_id, tree1, 'bar-id')
1589
        tt.apply()
1590
        self.assertEqual('directory', osutils.file_kind('tree2/foo'))
1591
        self.assertFileEqual('baz', 'tree2/bar')
1592
3363.17.25 by Aaron Bentley
remove get_inventory_entry, replace with create_from_tree
1593
    def test_create_from_tree_bytes(self):
1594
        """Provided lines are used instead of tree content."""
1595
        tree1 = self.make_branch_and_tree('tree1')
1596
        self.build_tree_contents([('tree1/foo', 'bar'),])
1597
        tree1.add('foo', 'foo-id')
1598
        tree2 = self.make_branch_and_tree('tree2')
1599
        tt = TreeTransform(tree2)
1600
        foo_trans_id = tt.create_path('foo', tt.root)
1601
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id', bytes='qux')
1602
        tt.apply()
1603
        self.assertFileEqual('qux', 'tree2/foo')
1604
1605
    def test_create_from_tree_symlink(self):
3363.17.24 by Aaron Bentley
Implement create_by_tree
1606
        self.requireFeature(SymlinkFeature)
1607
        tree1 = self.make_branch_and_tree('tree1')
1608
        os.symlink('bar', 'tree1/foo')
1609
        tree1.add('foo', 'foo-id')
1610
        tt = TreeTransform(self.make_branch_and_tree('tree2'))
1611
        foo_trans_id = tt.create_path('foo', tt.root)
1612
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1613
        tt.apply()
1614
        self.assertEqual('bar', os.readlink('tree2/foo'))
1615
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1616
1534.7.93 by Aaron Bentley
Added text merge test
1617
class TransformGroup(object):
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1618
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1619
    def __init__(self, dirname, root_id):
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1620
        self.name = dirname
1534.7.93 by Aaron Bentley
Added text merge test
1621
        os.mkdir(dirname)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
1622
        self.wt = BzrDir.create_standalone_workingtree(dirname)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1623
        self.wt.set_root_id(root_id)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
1624
        self.b = self.wt.branch
1534.7.93 by Aaron Bentley
Added text merge test
1625
        self.tt = TreeTransform(self.wt)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
1626
        self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
1534.7.93 by Aaron Bentley
Added text merge test
1627
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1628
1534.7.95 by Aaron Bentley
Added more text merge tests
1629
def conflict_text(tree, merge):
1630
    template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
1631
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
1632
1534.7.93 by Aaron Bentley
Added text merge test
1633
5954.2.2 by Aaron Bentley
Include parent id changes for changed inventory entries.
1634
class TestInventoryAltered(tests.TestCaseWithTransport):
1635
1636
    def test_inventory_altered_unchanged(self):
1637
        tree = self.make_branch_and_tree('tree')
1638
        self.build_tree(['tree/foo'])
1639
        tree.add('foo', 'foo-id')
1640
        with TransformPreview(tree) as tt:
1641
            self.assertEqual([], tt._inventory_altered())
1642
1643
    def test_inventory_altered_changed_parent_id(self):
1644
        tree = self.make_branch_and_tree('tree')
1645
        self.build_tree(['tree/foo'])
1646
        tree.add('foo', 'foo-id')
1647
        with TransformPreview(tree) as tt:
1648
            tt.unversion_file(tt.root)
1649
            tt.version_file('new-id', tt.root)
1650
            foo_trans_id = tt.trans_id_tree_file_id('foo-id')
1651
            foo_tuple = ('foo', foo_trans_id)
1652
            root_tuple = ('', tt.root)
1653
            self.assertEqual([root_tuple, foo_tuple], tt._inventory_altered())
1654
1655
    def test_inventory_altered_noop_changed_parent_id(self):
1656
        tree = self.make_branch_and_tree('tree')
1657
        self.build_tree(['tree/foo'])
1658
        tree.add('foo', 'foo-id')
1659
        with TransformPreview(tree) as tt:
1660
            tt.unversion_file(tt.root)
1661
            tt.version_file(tree.get_root_id(), tt.root)
1662
            foo_trans_id = tt.trans_id_tree_file_id('foo-id')
1663
            self.assertEqual([], tt._inventory_altered())
1664
1665
1534.7.93 by Aaron Bentley
Added text merge test
1666
class TestTransformMerge(TestCaseInTempDir):
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
1667
1534.7.93 by Aaron Bentley
Added text merge test
1668
    def test_text_merge(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1669
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1670
        base = TransformGroup("base", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1671
        base.tt.new_file('a', base.root, 'a\nb\nc\nd\be\n', 'a')
1534.7.95 by Aaron Bentley
Added more text merge tests
1672
        base.tt.new_file('b', base.root, 'b1', 'b')
1673
        base.tt.new_file('c', base.root, 'c', 'c')
1674
        base.tt.new_file('d', base.root, 'd', 'd')
1675
        base.tt.new_file('e', base.root, 'e', 'e')
1676
        base.tt.new_file('f', base.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1677
        base.tt.new_directory('g', base.root, 'g')
1534.7.97 by Aaron Bentley
Ensured foo.BASE is a directory if there's a conflict
1678
        base.tt.new_directory('h', base.root, 'h')
1534.7.93 by Aaron Bentley
Added text merge test
1679
        base.tt.apply()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1680
        other = TransformGroup("other", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1681
        other.tt.new_file('a', other.root, 'y\nb\nc\nd\be\n', 'a')
1534.7.95 by Aaron Bentley
Added more text merge tests
1682
        other.tt.new_file('b', other.root, 'b2', 'b')
1683
        other.tt.new_file('c', other.root, 'c2', 'c')
1684
        other.tt.new_file('d', other.root, 'd', 'd')
1685
        other.tt.new_file('e', other.root, 'e2', 'e')
1686
        other.tt.new_file('f', other.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1687
        other.tt.new_file('g', other.root, 'g', 'g')
1534.7.97 by Aaron Bentley
Ensured foo.BASE is a directory if there's a conflict
1688
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1689
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
1690
        other.tt.apply()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1691
        this = TransformGroup("this", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1692
        this.tt.new_file('a', this.root, 'a\nb\nc\nd\bz\n', 'a')
1534.7.95 by Aaron Bentley
Added more text merge tests
1693
        this.tt.new_file('b', this.root, 'b', 'b')
1694
        this.tt.new_file('c', this.root, 'c', 'c')
1695
        this.tt.new_file('d', this.root, 'd2', 'd')
1696
        this.tt.new_file('e', this.root, 'e2', 'e')
1697
        this.tt.new_file('f', this.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1698
        this.tt.new_file('g', this.root, 'g', 'g')
1534.7.97 by Aaron Bentley
Ensured foo.BASE is a directory if there's a conflict
1699
        this.tt.new_file('h', this.root, '1\n2\n3\n4\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1700
        this.tt.new_file('i', this.root, '1\n2\n3\n4\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
1701
        this.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1702
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
3008.1.6 by Michael Hudson
chop up Merge3Merger.__init__ into pieces
1703
1534.7.95 by Aaron Bentley
Added more text merge tests
1704
        # textual merge
1534.7.93 by Aaron Bentley
Added text merge test
1705
        self.assertEqual(this.wt.get_file('a').read(), 'y\nb\nc\nd\bz\n')
1534.7.95 by Aaron Bentley
Added more text merge tests
1706
        # three-way text conflict
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1707
        self.assertEqual(this.wt.get_file('b').read(),
1534.7.95 by Aaron Bentley
Added more text merge tests
1708
                         conflict_text('b', 'b2'))
1709
        # OTHER wins
1710
        self.assertEqual(this.wt.get_file('c').read(), 'c2')
1711
        # THIS wins
1712
        self.assertEqual(this.wt.get_file('d').read(), 'd2')
1713
        # Ambigious clean merge
1714
        self.assertEqual(this.wt.get_file('e').read(), 'e2')
1715
        # No change
1716
        self.assertEqual(this.wt.get_file('f').read(), 'f')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1717
        # Correct correct results when THIS == OTHER
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1718
        self.assertEqual(this.wt.get_file('g').read(), 'g')
1534.7.97 by Aaron Bentley
Ensured foo.BASE is a directory if there's a conflict
1719
        # Text conflict when THIS & OTHER are text and BASE is dir
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1720
        self.assertEqual(this.wt.get_file('h').read(),
1534.7.97 by Aaron Bentley
Ensured foo.BASE is a directory if there's a conflict
1721
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
1722
        self.assertEqual(this.wt.get_file_byname('h.THIS').read(),
1723
                         '1\n2\n3\n4\n')
1724
        self.assertEqual(this.wt.get_file_byname('h.OTHER').read(),
1725
                         'h\ni\nj\nk\n')
1726
        self.assertEqual(file_kind(this.wt.abspath('h.BASE')), 'directory')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1727
        self.assertEqual(this.wt.get_file('i').read(),
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1728
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
1729
        self.assertEqual(this.wt.get_file_byname('i.THIS').read(),
1730
                         '1\n2\n3\n4\n')
1731
        self.assertEqual(this.wt.get_file_byname('i.OTHER').read(),
1732
                         'h\ni\nj\nk\n')
1733
        self.assertEqual(os.path.exists(this.wt.abspath('i.BASE')), False)
1534.7.192 by Aaron Bentley
Record hashes produced by merges
1734
        modified = ['a', 'b', 'c', 'h', 'i']
1735
        merge_modified = this.wt.merge_modified()
1736
        self.assertSubset(merge_modified, modified)
1737
        self.assertEqual(len(merge_modified), len(modified))
1738
        file(this.wt.id2abspath('a'), 'wb').write('booga')
1739
        modified.pop(0)
1740
        merge_modified = this.wt.merge_modified()
1741
        self.assertSubset(merge_modified, modified)
1742
        self.assertEqual(len(merge_modified), len(modified))
1558.12.10 by Aaron Bentley
Be robust when merge_hash file_id not in inventory
1743
        this.wt.remove('b')
2796.1.4 by Aaron Bentley
Fix up various test cases
1744
        this.wt.revert()
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1745
1746
    def test_file_merge(self):
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1747
        self.requireFeature(SymlinkFeature)
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1748
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1749
        base = TransformGroup("BASE", root_id)
1750
        this = TransformGroup("THIS", root_id)
1751
        other = TransformGroup("OTHER", root_id)
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1752
        for tg in this, base, other:
1753
            tg.tt.new_directory('a', tg.root, 'a')
1754
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
1755
            tg.tt.new_file('c', tg.root, 'c', 'c')
1756
            tg.tt.new_symlink('d', tg.root, tg.name, 'd')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1757
        targets = ((base, 'base-e', 'base-f', None, None),
1758
                   (this, 'other-e', 'this-f', 'other-g', 'this-h'),
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1759
                   (other, 'other-e', None, 'other-g', 'other-h'))
1760
        for tg, e_target, f_target, g_target, h_target in targets:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1761
            for link, target in (('e', e_target), ('f', f_target),
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1762
                                 ('g', g_target), ('h', h_target)):
1763
                if target is not None:
1764
                    tg.tt.new_symlink(link, tg.root, target, link)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1765
1766
        for tg in this, base, other:
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1767
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1768
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1769
        self.assertIs(os.path.isdir(this.wt.abspath('a')), True)
1770
        self.assertIs(os.path.islink(this.wt.abspath('b')), True)
1771
        self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
1772
        for suffix in ('THIS', 'BASE', 'OTHER'):
1773
            self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1774
        self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1775
        self.assertEqual(this.wt.id2path('d'), 'd.OTHER')
1776
        self.assertEqual(this.wt.id2path('f'), 'f.THIS')
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1777
        self.assertEqual(os.readlink(this.wt.abspath('e')), 'other-e')
1778
        self.assertIs(os.path.lexists(this.wt.abspath('e.THIS')), False)
1779
        self.assertIs(os.path.lexists(this.wt.abspath('e.OTHER')), False)
1780
        self.assertIs(os.path.lexists(this.wt.abspath('e.BASE')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1781
        self.assertIs(os.path.lexists(this.wt.abspath('g')), True)
1782
        self.assertIs(os.path.lexists(this.wt.abspath('g.BASE')), False)
1783
        self.assertIs(os.path.lexists(this.wt.abspath('h')), False)
1784
        self.assertIs(os.path.lexists(this.wt.abspath('h.BASE')), False)
1785
        self.assertIs(os.path.lexists(this.wt.abspath('h.THIS')), True)
1786
        self.assertIs(os.path.lexists(this.wt.abspath('h.OTHER')), True)
1534.7.105 by Aaron Bentley
Got merge with rename working
1787
1788
    def test_filename_merge(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1789
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1790
        base = TransformGroup("BASE", root_id)
1791
        this = TransformGroup("THIS", root_id)
1792
        other = TransformGroup("OTHER", root_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1793
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a')
1534.7.105 by Aaron Bentley
Got merge with rename working
1794
                                   for t in [base, this, other]]
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1795
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b')
1534.7.105 by Aaron Bentley
Got merge with rename working
1796
                                   for t in [base, this, other]]
1797
        base.tt.new_directory('c', base_a, 'c')
1798
        this.tt.new_directory('c1', this_a, 'c')
1799
        other.tt.new_directory('c', other_b, 'c')
1800
1801
        base.tt.new_directory('d', base_a, 'd')
1802
        this.tt.new_directory('d1', this_b, 'd')
1803
        other.tt.new_directory('d', other_a, 'd')
1804
1805
        base.tt.new_directory('e', base_a, 'e')
1806
        this.tt.new_directory('e', this_a, 'e')
1807
        other.tt.new_directory('e1', other_b, 'e')
1808
1809
        base.tt.new_directory('f', base_a, 'f')
1810
        this.tt.new_directory('f1', this_b, 'f')
1811
        other.tt.new_directory('f1', other_b, 'f')
1812
1813
        for tg in [this, base, other]:
1814
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1815
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.176 by abentley
Fixed up tests for Windows
1816
        self.assertEqual(this.wt.id2path('c'), pathjoin('b/c1'))
1817
        self.assertEqual(this.wt.id2path('d'), pathjoin('b/d1'))
1818
        self.assertEqual(this.wt.id2path('e'), pathjoin('b/e1'))
1819
        self.assertEqual(this.wt.id2path('f'), pathjoin('b/f1'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1820
1821
    def test_filename_merge_conflicts(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1822
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1823
        base = TransformGroup("BASE", root_id)
1824
        this = TransformGroup("THIS", root_id)
1825
        other = TransformGroup("OTHER", root_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1826
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a')
1534.7.105 by Aaron Bentley
Got merge with rename working
1827
                                   for t in [base, this, other]]
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1828
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b')
1534.7.105 by Aaron Bentley
Got merge with rename working
1829
                                   for t in [base, this, other]]
1830
1831
        base.tt.new_file('g', base_a, 'g', 'g')
1832
        other.tt.new_file('g1', other_b, 'g1', 'g')
1833
1834
        base.tt.new_file('h', base_a, 'h', 'h')
1835
        this.tt.new_file('h1', this_b, 'h1', 'h')
1836
1837
        base.tt.new_file('i', base.root, 'i', 'i')
1534.7.153 by Aaron Bentley
Handled test cases involving symlinks
1838
        other.tt.new_directory('i1', this_b, 'i')
1534.7.105 by Aaron Bentley
Got merge with rename working
1839
1840
        for tg in [this, base, other]:
1841
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1842
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.105 by Aaron Bentley
Got merge with rename working
1843
1534.7.176 by abentley
Fixed up tests for Windows
1844
        self.assertEqual(this.wt.id2path('g'), pathjoin('b/g1.OTHER'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1845
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.BASE')), True)
1846
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.THIS')), False)
1534.7.176 by abentley
Fixed up tests for Windows
1847
        self.assertEqual(this.wt.id2path('h'), pathjoin('b/h1.THIS'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1848
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.BASE')), True)
1849
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.OTHER')), False)
1534.7.176 by abentley
Fixed up tests for Windows
1850
        self.assertEqual(this.wt.id2path('i'), pathjoin('b/i1.OTHER'))
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1851
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
1852
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1853
class TestBuildTree(tests.TestCaseWithTransport):
1854
3006.2.2 by Alexander Belchenko
tests added.
1855
    def test_build_tree_with_symlinks(self):
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1856
        self.requireFeature(SymlinkFeature)
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1857
        os.mkdir('a')
1858
        a = BzrDir.create_standalone_workingtree('a')
1859
        os.mkdir('a/foo')
1860
        file('a/foo/bar', 'wb').write('contents')
1861
        os.symlink('a/foo/bar', 'a/foo/baz')
1862
        a.add(['foo', 'foo/bar', 'foo/baz'])
1863
        a.commit('initial commit')
1864
        b = BzrDir.create_standalone_workingtree('b')
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
1865
        basis = a.basis_tree()
1866
        basis.lock_read()
1867
        self.addCleanup(basis.unlock)
1868
        build_tree(basis, b)
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1869
        self.assertIs(os.path.isdir('b/foo'), True)
1870
        self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
1871
        self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1872
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
1873
    def test_build_with_references(self):
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
1874
        tree = self.make_branch_and_tree('source',
1875
            format='dirstate-with-subtree')
1876
        subtree = self.make_branch_and_tree('source/subtree',
1877
            format='dirstate-with-subtree')
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
1878
        tree.add_reference(subtree)
1879
        tree.commit('a revision')
1880
        tree.branch.create_checkout('target')
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1881
        self.assertPathExists('target')
1882
        self.assertPathExists('target/subtree')
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
1883
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1884
    def test_file_conflict_handling(self):
1885
        """Ensure that when building trees, conflict handling is done"""
1886
        source = self.make_branch_and_tree('source')
1887
        target = self.make_branch_and_tree('target')
1888
        self.build_tree(['source/file', 'target/file'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1889
        source.add('file', 'new-file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1890
        source.commit('added file')
1891
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1892
        self.assertEqual([DuplicateEntry('Moved existing file to',
1893
                          'file.moved', 'file', None, 'new-file')],
1894
                         target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1895
        target2 = self.make_branch_and_tree('target2')
1896
        target_file = file('target2/file', 'wb')
1897
        try:
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1898
            source_file = file('source/file', 'rb')
1899
            try:
1900
                target_file.write(source_file.read())
1901
            finally:
1902
                source_file.close()
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1903
        finally:
1904
            target_file.close()
1905
        build_tree(source.basis_tree(), target2)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1906
        self.assertEqual([], target2.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1907
1908
    def test_symlink_conflict_handling(self):
1909
        """Ensure that when building trees, conflict handling is done"""
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1910
        self.requireFeature(SymlinkFeature)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1911
        source = self.make_branch_and_tree('source')
1912
        os.symlink('foo', 'source/symlink')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1913
        source.add('symlink', 'new-symlink')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1914
        source.commit('added file')
1915
        target = self.make_branch_and_tree('target')
1916
        os.symlink('bar', 'target/symlink')
1917
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1918
        self.assertEqual([DuplicateEntry('Moved existing file to',
1919
            'symlink.moved', 'symlink', None, 'new-symlink')],
1920
            target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1921
        target = self.make_branch_and_tree('target2')
1922
        os.symlink('foo', 'target2/symlink')
1923
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1924
        self.assertEqual([], target.conflicts())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1925
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1926
    def test_directory_conflict_handling(self):
1927
        """Ensure that when building trees, conflict handling is done"""
1928
        source = self.make_branch_and_tree('source')
1929
        target = self.make_branch_and_tree('target')
1930
        self.build_tree(['source/dir1/', 'source/dir1/file', 'target/dir1/'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1931
        source.add(['dir1', 'dir1/file'], ['new-dir1', 'new-file'])
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1932
        source.commit('added file')
1933
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1934
        self.assertEqual([], target.conflicts())
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1935
        self.assertPathExists('target/dir1/file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1936
1937
        # Ensure contents are merged
1938
        target = self.make_branch_and_tree('target2')
1939
        self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
1940
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1941
        self.assertEqual([], target.conflicts())
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1942
        self.assertPathExists('target2/dir1/file2')
1943
        self.assertPathExists('target2/dir1/file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1944
1945
        # Ensure new contents are suppressed for existing branches
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1946
        target = self.make_branch_and_tree('target3')
1947
        self.make_branch('target3/dir1')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1948
        self.build_tree(['target3/dir1/file2'])
1949
        build_tree(source.basis_tree(), target)
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1950
        self.assertPathDoesNotExist('target3/dir1/file')
1951
        self.assertPathExists('target3/dir1/file2')
1952
        self.assertPathExists('target3/dir1.diverted/file')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1953
        self.assertEqual([DuplicateEntry('Diverted to',
1954
            'dir1.diverted', 'dir1', 'new-dir1', None)],
1955
            target.conflicts())
1956
1957
        target = self.make_branch_and_tree('target4')
1958
        self.build_tree(['target4/dir1/'])
1959
        self.make_branch('target4/dir1/file')
1960
        build_tree(source.basis_tree(), target)
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1961
        self.assertPathExists('target4/dir1/file')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1962
        self.assertEqual('directory', file_kind('target4/dir1/file'))
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
1963
        self.assertPathExists('target4/dir1/file.diverted')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1964
        self.assertEqual([DuplicateEntry('Diverted to',
1965
            'dir1/file.diverted', 'dir1/file', 'new-file', None)],
1966
            target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1967
1968
    def test_mixed_conflict_handling(self):
1969
        """Ensure that when building trees, conflict handling is done"""
1970
        source = self.make_branch_and_tree('source')
1971
        target = self.make_branch_and_tree('target')
1972
        self.build_tree(['source/name', 'target/name/'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1973
        source.add('name', 'new-name')
1974
        source.commit('added file')
1975
        build_tree(source.basis_tree(), target)
1976
        self.assertEqual([DuplicateEntry('Moved existing file to',
1977
            'name.moved', 'name', None, 'new-name')], target.conflicts())
1978
1979
    def test_raises_in_populated(self):
1980
        source = self.make_branch_and_tree('source')
1981
        self.build_tree(['source/name'])
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1982
        source.add('name')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1983
        source.commit('added name')
1984
        target = self.make_branch_and_tree('target')
1985
        self.build_tree(['target/name'])
1986
        target.add('name')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1987
        self.assertRaises(errors.WorkingTreeAlreadyPopulated,
2090.2.1 by Martin Pool
Fix some code which relies on assertions and breaks under python -O
1988
            build_tree, source.basis_tree(), target)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1989
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1990
    def test_build_tree_rename_count(self):
1991
        source = self.make_branch_and_tree('source')
1992
        self.build_tree(['source/file1', 'source/dir1/'])
1993
        source.add(['file1', 'dir1'])
1994
        source.commit('add1')
1995
        target1 = self.make_branch_and_tree('target1')
2502.1.6 by Aaron Bentley
Update from review comments
1996
        transform_result = build_tree(source.basis_tree(), target1)
1997
        self.assertEqual(2, transform_result.rename_count)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1998
1999
        self.build_tree(['source/dir1/file2'])
2000
        source.add(['dir1/file2'])
2001
        source.commit('add3')
2002
        target2 = self.make_branch_and_tree('target2')
2502.1.6 by Aaron Bentley
Update from review comments
2003
        transform_result = build_tree(source.basis_tree(), target2)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
2004
        # children of non-root directories should not be renamed
2502.1.6 by Aaron Bentley
Update from review comments
2005
        self.assertEqual(2, transform_result.rename_count)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
2006
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
2007
    def create_ab_tree(self):
2008
        """Create a committed test tree with two files"""
2009
        source = self.make_branch_and_tree('source')
2010
        self.build_tree_contents([('source/file1', 'A')])
2011
        self.build_tree_contents([('source/file2', 'B')])
2012
        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
2013
        source.commit('commit files')
2014
        source.lock_write()
2015
        self.addCleanup(source.unlock)
2016
        return source
2017
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
2018
    def test_build_tree_accelerator_tree(self):
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
2019
        source = self.create_ab_tree()
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
2020
        self.build_tree_contents([('source/file2', 'C')])
2021
        calls = []
2022
        real_source_get_file = source.get_file
2023
        def get_file(file_id, path=None):
2024
            calls.append(file_id)
2025
            return real_source_get_file(file_id, path)
2026
        source.get_file = get_file
2027
        target = self.make_branch_and_tree('target')
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
2028
        revision_tree = source.basis_tree()
2029
        revision_tree.lock_read()
2030
        self.addCleanup(revision_tree.unlock)
2031
        build_tree(revision_tree, target, source)
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
2032
        self.assertEqual(['file1-id'], calls)
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
2033
        target.lock_read()
2034
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2035
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
2036
5752.5.1 by John Arbash Meinel
Merge up transform-create-file
2037
    def test_build_tree_accelerator_tree_observes_sha1(self):
2038
        source = self.create_ab_tree()
2039
        sha1 = osutils.sha_string('A')
2040
        target = self.make_branch_and_tree('target')
2041
        target.lock_write()
2042
        self.addCleanup(target.unlock)
2043
        state = target.current_dirstate()
2044
        state._cutoff_time = time.time() + 60
2045
        build_tree(source.basis_tree(), target, source)
2046
        entry = state._get_entry(0, path_utf8='file1')
2047
        self.assertEqual(sha1, entry[1][0][1])
2048
3123.5.4 by Aaron Bentley
Use an accelerator tree when branching, handle no-such-id correctly
2049
    def test_build_tree_accelerator_tree_missing_file(self):
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
2050
        source = self.create_ab_tree()
3123.5.4 by Aaron Bentley
Use an accelerator tree when branching, handle no-such-id correctly
2051
        os.unlink('source/file1')
2052
        source.remove(['file2'])
2053
        target = self.make_branch_and_tree('target')
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
2054
        revision_tree = source.basis_tree()
2055
        revision_tree.lock_read()
2056
        self.addCleanup(revision_tree.unlock)
2057
        build_tree(revision_tree, target, source)
2058
        target.lock_read()
2059
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2060
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3123.5.4 by Aaron Bentley
Use an accelerator tree when branching, handle no-such-id correctly
2061
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
2062
    def test_build_tree_accelerator_wrong_kind(self):
3146.4.8 by Aaron Bentley
Add missing symlink requirement
2063
        self.requireFeature(SymlinkFeature)
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
2064
        source = self.make_branch_and_tree('source')
2065
        self.build_tree_contents([('source/file1', '')])
2066
        self.build_tree_contents([('source/file2', '')])
2067
        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
2068
        source.commit('commit files')
2069
        os.unlink('source/file2')
2070
        self.build_tree_contents([('source/file2/', 'C')])
2071
        os.unlink('source/file1')
2072
        os.symlink('file2', 'source/file1')
2073
        calls = []
2074
        real_source_get_file = source.get_file
2075
        def get_file(file_id, path=None):
2076
            calls.append(file_id)
2077
            return real_source_get_file(file_id, path)
2078
        source.get_file = get_file
2079
        target = self.make_branch_and_tree('target')
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
2080
        revision_tree = source.basis_tree()
2081
        revision_tree.lock_read()
2082
        self.addCleanup(revision_tree.unlock)
2083
        build_tree(revision_tree, target, source)
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
2084
        self.assertEqual([], calls)
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
2085
        target.lock_read()
2086
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2087
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
2088
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
2089
    def test_build_tree_hardlink(self):
2090
        self.requireFeature(HardlinkFeature)
2091
        source = self.create_ab_tree()
2092
        target = self.make_branch_and_tree('target')
2093
        revision_tree = source.basis_tree()
2094
        revision_tree.lock_read()
2095
        self.addCleanup(revision_tree.unlock)
2096
        build_tree(revision_tree, target, source, hardlink=True)
2097
        target.lock_read()
2098
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2099
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
2100
        source_stat = os.stat('source/file1')
2101
        target_stat = os.stat('target/file1')
2102
        self.assertEqual(source_stat, target_stat)
2103
2104
        # Explicitly disallowing hardlinks should prevent them.
2105
        target2 = self.make_branch_and_tree('target2')
2106
        build_tree(revision_tree, target2, source, hardlink=False)
2107
        target2.lock_read()
2108
        self.addCleanup(target2.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2109
        self.assertEqual([], list(target2.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
2110
        source_stat = os.stat('source/file1')
2111
        target2_stat = os.stat('target2/file1')
2112
        self.assertNotEqual(source_stat, target2_stat)
2113
3137.1.1 by Aaron Bentley
Fix build_tree acceleration when file is moved in accelerator_tree
2114
    def test_build_tree_accelerator_tree_moved(self):
2115
        source = self.make_branch_and_tree('source')
2116
        self.build_tree_contents([('source/file1', 'A')])
2117
        source.add(['file1'], ['file1-id'])
2118
        source.commit('commit files')
2119
        source.rename_one('file1', 'file2')
2120
        source.lock_read()
2121
        self.addCleanup(source.unlock)
2122
        target = self.make_branch_and_tree('target')
2123
        revision_tree = source.basis_tree()
2124
        revision_tree.lock_read()
2125
        self.addCleanup(revision_tree.unlock)
2126
        build_tree(revision_tree, target, source)
2127
        target.lock_read()
2128
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2129
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3137.1.1 by Aaron Bentley
Fix build_tree acceleration when file is moved in accelerator_tree
2130
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
2131
    def test_build_tree_hardlinks_preserve_execute(self):
2132
        self.requireFeature(HardlinkFeature)
2133
        source = self.create_ab_tree()
2134
        tt = TreeTransform(source)
2135
        trans_id = tt.trans_id_tree_file_id('file1-id')
2136
        tt.set_executability(True, trans_id)
2137
        tt.apply()
2138
        self.assertTrue(source.is_executable('file1-id'))
2139
        target = self.make_branch_and_tree('target')
2140
        revision_tree = source.basis_tree()
2141
        revision_tree.lock_read()
2142
        self.addCleanup(revision_tree.unlock)
2143
        build_tree(revision_tree, target, source, hardlink=True)
2144
        target.lock_read()
2145
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2146
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
2147
        self.assertTrue(source.is_executable('file1-id'))
2148
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
2149
    def install_rot13_content_filter(self, pattern):
4985.2.1 by Vincent Ladeuil
Deploy addAttrCleanup on the whole test suite.
2150
        # We could use
2151
        # self.addCleanup(filters._reset_registry, filters._reset_registry())
2152
        # below, but that looks a bit... hard to read even if it's exactly
2153
        # the same thing.
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
2154
        original_registry = filters._reset_registry()
2155
        def restore_registry():
2156
            filters._reset_registry(original_registry)
2157
        self.addCleanup(restore_registry)
2158
        def rot13(chunks, context=None):
2159
            return [''.join(chunks).encode('rot13')]
2160
        rot13filter = filters.ContentFilter(rot13, rot13)
2161
        filters.register_filter_stack_map('rot13', {'yes': [rot13filter]}.get)
2162
        os.mkdir(self.test_home_dir + '/.bazaar')
2163
        rules_filename = self.test_home_dir + '/.bazaar/rules'
4826.1.8 by Andrew Bennetts
Tweaks suggested by John.
2164
        f = open(rules_filename, 'wb')
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
2165
        f.write('[name %s]\nrot13=yes\n' % (pattern,))
2166
        f.close()
2167
        def uninstall_rules():
2168
            os.remove(rules_filename)
2169
            rules.reset_rules()
2170
        self.addCleanup(uninstall_rules)
2171
        rules.reset_rules()
2172
2173
    def test_build_tree_content_filtered_files_are_not_hardlinked(self):
2174
        """build_tree will not hardlink files that have content filtering rules
2175
        applied to them (but will still hardlink other files from the same tree
2176
        if it can).
2177
        """
2178
        self.requireFeature(HardlinkFeature)
2179
        self.install_rot13_content_filter('file1')
2180
        source = self.create_ab_tree()
2181
        target = self.make_branch_and_tree('target')
2182
        revision_tree = source.basis_tree()
2183
        revision_tree.lock_read()
2184
        self.addCleanup(revision_tree.unlock)
2185
        build_tree(revision_tree, target, source, hardlink=True)
2186
        target.lock_read()
2187
        self.addCleanup(target.unlock)
2188
        self.assertEqual([], list(target.iter_changes(revision_tree)))
2189
        source_stat = os.stat('source/file1')
2190
        target_stat = os.stat('target/file1')
2191
        self.assertNotEqual(source_stat, target_stat)
2192
        source_stat = os.stat('source/file2')
2193
        target_stat = os.stat('target/file2')
4826.1.8 by Andrew Bennetts
Tweaks suggested by John.
2194
        self.assertEqualStat(source_stat, target_stat)
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
2195
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
2196
    def test_case_insensitive_build_tree_inventory(self):
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
2197
        if (tests.CaseInsensitiveFilesystemFeature.available()
2198
            or tests.CaseInsCasePresFilenameFeature.available()):
4241.9.4 by Vincent Ladeuil
Fix test_case_insensitive_build_tree_inventory failure on OSX.
2199
            raise tests.UnavailableFeature('Fully case sensitive filesystem')
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
2200
        source = self.make_branch_and_tree('source')
2201
        self.build_tree(['source/file', 'source/FILE'])
2202
        source.add(['file', 'FILE'], ['lower-id', 'upper-id'])
2203
        source.commit('added files')
2204
        # Don't try this at home, kids!
2205
        # Force the tree to report that it is case insensitive
2206
        target = self.make_branch_and_tree('target')
2207
        target.case_sensitive = False
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
2208
        build_tree(source.basis_tree(), target, source, delta_from_tree=True)
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
2209
        self.assertEqual('file.moved', target.id2path('lower-id'))
2210
        self.assertEqual('FILE', target.id2path('upper-id'))
2211
5752.5.1 by John Arbash Meinel
Merge up transform-create-file
2212
    def test_build_tree_observes_sha(self):
2213
        source = self.make_branch_and_tree('source')
2214
        self.build_tree(['source/file1', 'source/dir/', 'source/dir/file2'])
2215
        source.add(['file1', 'dir', 'dir/file2'],
2216
                   ['file1-id', 'dir-id', 'file2-id'])
2217
        source.commit('new files')
2218
        target = self.make_branch_and_tree('target')
2219
        target.lock_write()
2220
        self.addCleanup(target.unlock)
2221
        # We make use of the fact that DirState caches its cutoff time. So we
2222
        # set the 'safe' time to one minute in the future.
2223
        state = target.current_dirstate()
2224
        state._cutoff_time = time.time() + 60
2225
        build_tree(source.basis_tree(), target)
2226
        entry1_sha = osutils.sha_file_by_name('source/file1')
2227
        entry2_sha = osutils.sha_file_by_name('source/dir/file2')
2228
        # entry[1] is the state information, entry[1][0] is the state of the
2229
        # working tree, entry[1][0][1] is the sha value for the current working
2230
        # tree
2231
        entry1 = state._get_entry(0, path_utf8='file1')
2232
        self.assertEqual(entry1_sha, entry1[1][0][1])
2233
        # The 'size' field must also be set.
2234
        self.assertEqual(25, entry1[1][0][2])
2235
        entry1_state = entry1[1][0]
2236
        entry2 = state._get_entry(0, path_utf8='dir/file2')
2237
        self.assertEqual(entry2_sha, entry2[1][0][1])
2238
        self.assertEqual(29, entry2[1][0][2])
2239
        entry2_state = entry2[1][0]
2240
        # Now, make sure that we don't have to re-read the content. The
2241
        # packed_stat should match exactly.
2242
        self.assertEqual(entry1_sha, target.get_file_sha1('file1-id', 'file1'))
2243
        self.assertEqual(entry2_sha,
2244
                         target.get_file_sha1('file2-id', 'dir/file2'))
2245
        self.assertEqual(entry1_state, entry1[1][0])
2246
        self.assertEqual(entry2_state, entry2[1][0])
2247
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
2248
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2249
class TestCommitTransform(tests.TestCaseWithTransport):
2250
2251
    def get_branch(self):
2252
        tree = self.make_branch_and_tree('tree')
2253
        tree.lock_write()
2254
        self.addCleanup(tree.unlock)
2255
        tree.commit('empty commit')
2256
        return tree.branch
2257
2258
    def get_branch_and_transform(self):
2259
        branch = self.get_branch()
2260
        tt = TransformPreview(branch.basis_tree())
2261
        self.addCleanup(tt.finalize)
2262
        return branch, tt
2263
2264
    def test_commit_wrong_basis(self):
2265
        branch = self.get_branch()
2266
        basis = branch.repository.revision_tree(
2267
            _mod_revision.NULL_REVISION)
2268
        tt = TransformPreview(basis)
2269
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
2270
        e = self.assertRaises(ValueError, tt.commit, branch, '')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2271
        self.assertEqual('TreeTransform not based on branch basis: null:',
2272
                         str(e))
2273
2274
    def test_empy_commit(self):
2275
        branch, tt = self.get_branch_and_transform()
2276
        rev = tt.commit(branch, 'my message')
2277
        self.assertEqual(2, branch.revno())
2278
        repo = branch.repository
2279
        self.assertEqual('my message', repo.get_revision(rev).message)
2280
2281
    def test_merge_parents(self):
2282
        branch, tt = self.get_branch_and_transform()
2283
        rev = tt.commit(branch, 'my message', ['rev1b', 'rev1c'])
2284
        self.assertEqual(['rev1b', 'rev1c'],
2285
                         branch.basis_tree().get_parent_ids()[1:])
2286
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2287
    def test_first_commit(self):
2288
        branch = self.make_branch('branch')
2289
        branch.lock_write()
2290
        self.addCleanup(branch.unlock)
2291
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2292
        self.addCleanup(tt.finalize)
4526.9.23 by Robert Collins
Change the tree transform test_first_commit test to set a root id in the new tree, and workaround an apparent bug in TreeTransform._determine_path.
2293
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2294
        rev = tt.commit(branch, 'my message')
2295
        self.assertEqual([], branch.basis_tree().get_parent_ids())
4526.8.5 by Aaron Bentley
Updates from review.
2296
        self.assertNotEqual(_mod_revision.NULL_REVISION,
2297
                            branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2298
4526.8.5 by Aaron Bentley
Updates from review.
2299
    def test_first_commit_with_merge_parents(self):
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2300
        branch = self.make_branch('branch')
2301
        branch.lock_write()
2302
        self.addCleanup(branch.unlock)
2303
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2304
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
2305
        e = self.assertRaises(ValueError, tt.commit, branch,
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2306
                          'my message', ['rev1b-id'])
4526.8.5 by Aaron Bentley
Updates from review.
2307
        self.assertEqual('Cannot supply merge parents for first commit.',
2308
                         str(e))
2309
        self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2310
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2311
    def test_add_files(self):
2312
        branch, tt = self.get_branch_and_transform()
2313
        tt.new_file('file', tt.root, 'contents', 'file-id')
2314
        trans_id = tt.new_directory('dir', tt.root, 'dir-id')
4789.25.2 by John Arbash Meinel
Fix 3 tests that meant to skip exec or symlink testing on win32
2315
        if SymlinkFeature.available():
2316
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2317
        rev = tt.commit(branch, 'message')
2318
        tree = branch.basis_tree()
2319
        self.assertEqual('file', tree.id2path('file-id'))
2320
        self.assertEqual('contents', tree.get_file_text('file-id'))
2321
        self.assertEqual('dir', tree.id2path('dir-id'))
4789.25.2 by John Arbash Meinel
Fix 3 tests that meant to skip exec or symlink testing on win32
2322
        if SymlinkFeature.available():
2323
            self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
2324
            self.assertEqual('target', tree.get_symlink_target('symlink-id'))
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2325
4526.8.2 by Aaron Bentley
Proved strict commit handling.
2326
    def test_add_unversioned(self):
2327
        branch, tt = self.get_branch_and_transform()
2328
        tt.new_file('file', tt.root, 'contents')
2329
        self.assertRaises(errors.StrictCommitFailed, tt.commit, branch,
2330
                          'message', strict=True)
2331
2332
    def test_modify_strict(self):
2333
        branch, tt = self.get_branch_and_transform()
2334
        tt.new_file('file', tt.root, 'contents', 'file-id')
2335
        tt.commit(branch, 'message', strict=True)
2336
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2337
        self.addCleanup(tt.finalize)
4526.8.2 by Aaron Bentley
Proved strict commit handling.
2338
        trans_id = tt.trans_id_file_id('file-id')
2339
        tt.delete_contents(trans_id)
2340
        tt.create_file('contents', trans_id)
2341
        tt.commit(branch, 'message', strict=True)
2342
4526.8.6 by Aaron Bentley
Check for malformed transforms before committing.
2343
    def test_commit_malformed(self):
2344
        """Committing a malformed transform should raise an exception.
2345
2346
        In this case, we are adding a file without adding its parent.
2347
        """
2348
        branch, tt = self.get_branch_and_transform()
2349
        parent_id = tt.trans_id_file_id('parent-id')
2350
        tt.new_file('file', parent_id, 'contents', 'file-id')
2351
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
2352
                          'message')
2353
5162.4.1 by Aaron Bentley
TreeTransform supports normal commit parameters and includes branch nick.
2354
    def test_commit_rich_revision_data(self):
2355
        branch, tt = self.get_branch_and_transform()
5162.4.3 by Aaron Bentley
Fix failing test.
2356
        rev_id = tt.commit(branch, 'message', timestamp=1, timezone=43201,
5162.4.1 by Aaron Bentley
TreeTransform supports normal commit parameters and includes branch nick.
2357
                           committer='me <me@example.com>',
2358
                           revprops={'foo': 'bar'}, revision_id='revid-1',
2359
                           authors=['Author1 <author1@example.com>',
2360
                              'Author2 <author2@example.com>',
2361
                               ])
2362
        self.assertEqual('revid-1', rev_id)
2363
        revision = branch.repository.get_revision(rev_id)
2364
        self.assertEqual(1, revision.timestamp)
5162.4.3 by Aaron Bentley
Fix failing test.
2365
        self.assertEqual(43201, revision.timezone)
5162.4.1 by Aaron Bentley
TreeTransform supports normal commit parameters and includes branch nick.
2366
        self.assertEqual('me <me@example.com>', revision.committer)
2367
        self.assertEqual(['Author1 <author1@example.com>',
2368
                          'Author2 <author2@example.com>'],
2369
                         revision.get_apparent_authors())
2370
        del revision.properties['authors']
2371
        self.assertEqual({'foo': 'bar',
2372
                          'branch-nick': 'tree'},
2373
                         revision.properties)
2374
2375
    def test_no_explicit_revprops(self):
2376
        branch, tt = self.get_branch_and_transform()
2377
        rev_id = tt.commit(branch, 'message', authors=[
2378
            'Author1 <author1@example.com>',
2379
            'Author2 <author2@example.com>', ])
2380
        revision = branch.repository.get_revision(rev_id)
2381
        self.assertEqual(['Author1 <author1@example.com>',
2382
                          'Author2 <author2@example.com>'],
2383
                         revision.get_apparent_authors())
2384
        self.assertEqual('tree', revision.properties['branch-nick'])
2385
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2386
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
2387
class TestBackupName(tests.TestCase):
2388
2389
    def test_deprecations(self):
2390
        class MockTransform(object):
2391
2392
            def has_named_child(self, by_parent, parent_id, name):
2393
                return name in by_parent.get(parent_id, [])
2394
2395
        class MockEntry(object):
2396
2397
            def __init__(self):
2398
                object.__init__(self)
2399
                self.name = "name"
2400
1534.10.28 by Aaron Bentley
Use numbered backup files
2401
        tt = MockTransform()
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
2402
        name1 = self.applyDeprecated(
5409.8.4 by Vincent Ladeuil
Fix indentations.
2403
            symbol_versioning.deprecated_in((2, 3, 0)),
2404
            transform.get_backup_name, MockEntry(), {'a':[]}, 'a', tt)
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
2405
        self.assertEqual('name.~1~', name1)
2406
        name2 = self.applyDeprecated(
5409.8.4 by Vincent Ladeuil
Fix indentations.
2407
            symbol_versioning.deprecated_in((2, 3, 0)),
2408
            transform._get_backup_name, 'name', {'a':['name.~1~']}, 'a', tt)
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
2409
        self.assertEqual('name.~2~', name2)
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2410
2411
2412
class TestFileMover(tests.TestCaseWithTransport):
2413
2414
    def test_file_mover(self):
2415
        self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
2416
        mover = _FileMover()
2417
        mover.rename('a', 'q')
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2418
        self.assertPathExists('q')
2419
        self.assertPathDoesNotExist('a')
2420
        self.assertPathExists('q/b')
2421
        self.assertPathExists('c')
2422
        self.assertPathExists('c/d')
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2423
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2424
    def test_pre_delete_rollback(self):
2425
        self.build_tree(['a/'])
2426
        mover = _FileMover()
2427
        mover.pre_delete('a', 'q')
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2428
        self.assertPathExists('q')
2429
        self.assertPathDoesNotExist('a')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2430
        mover.rollback()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2431
        self.assertPathDoesNotExist('q')
2432
        self.assertPathExists('a')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2433
2434
    def test_apply_deletions(self):
2733.2.12 by Aaron Bentley
Updates from review
2435
        self.build_tree(['a/', 'b/'])
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2436
        mover = _FileMover()
2437
        mover.pre_delete('a', 'q')
2733.2.12 by Aaron Bentley
Updates from review
2438
        mover.pre_delete('b', 'r')
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2439
        self.assertPathExists('q')
2440
        self.assertPathExists('r')
2441
        self.assertPathDoesNotExist('a')
2442
        self.assertPathDoesNotExist('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2443
        mover.apply_deletions()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2444
        self.assertPathDoesNotExist('q')
2445
        self.assertPathDoesNotExist('r')
2446
        self.assertPathDoesNotExist('a')
2447
        self.assertPathDoesNotExist('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2448
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2449
    def test_file_mover_rollback(self):
2450
        self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
2451
        mover = _FileMover()
2452
        mover.rename('c/d', 'c/f')
2453
        mover.rename('c/e', 'c/d')
2454
        try:
2455
            mover.rename('a', 'c')
3063.1.3 by Aaron Bentley
Update for Linux
2456
        except errors.FileExists, e:
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2457
            mover.rollback()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2458
        self.assertPathExists('a')
2459
        self.assertPathExists('c/d')
2733.2.3 by Aaron Bentley
Test tranform rollback
2460
2461
2462
class Bogus(Exception):
2463
    pass
2464
2465
2466
class TestTransformRollback(tests.TestCaseWithTransport):
2467
2468
    class ExceptionFileMover(_FileMover):
2469
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2470
        def __init__(self, bad_source=None, bad_target=None):
2471
            _FileMover.__init__(self)
2472
            self.bad_source = bad_source
2473
            self.bad_target = bad_target
2474
2733.2.3 by Aaron Bentley
Test tranform rollback
2475
        def rename(self, source, target):
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2476
            if (self.bad_source is not None and
2477
                source.endswith(self.bad_source)):
2478
                raise Bogus
2479
            elif (self.bad_target is not None and
2480
                target.endswith(self.bad_target)):
2733.2.3 by Aaron Bentley
Test tranform rollback
2481
                raise Bogus
2482
            else:
2483
                _FileMover.rename(self, source, target)
2484
2485
    def test_rollback_rename(self):
2486
        tree = self.make_branch_and_tree('.')
2487
        self.build_tree(['a/', 'a/b'])
2488
        tt = TreeTransform(tree)
2489
        self.addCleanup(tt.finalize)
2490
        a_id = tt.trans_id_tree_path('a')
2491
        tt.adjust_path('c', tt.root, a_id)
2492
        tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2493
        self.assertRaises(Bogus, tt.apply,
2494
                          _mover=self.ExceptionFileMover(bad_source='a'))
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2495
        self.assertPathExists('a')
2496
        self.assertPathExists('a/b')
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2497
        tt.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2498
        self.assertPathExists('c')
2499
        self.assertPathExists('c/d')
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2500
2501
    def test_rollback_rename_into_place(self):
2502
        tree = self.make_branch_and_tree('.')
2503
        self.build_tree(['a/', 'a/b'])
2504
        tt = TreeTransform(tree)
2505
        self.addCleanup(tt.finalize)
2506
        a_id = tt.trans_id_tree_path('a')
2507
        tt.adjust_path('c', tt.root, a_id)
2508
        tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
2509
        self.assertRaises(Bogus, tt.apply,
2510
                          _mover=self.ExceptionFileMover(bad_target='c/d'))
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2511
        self.assertPathExists('a')
2512
        self.assertPathExists('a/b')
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2513
        tt.apply()
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2514
        self.assertPathExists('c')
2515
        self.assertPathExists('c/d')
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
2516
2517
    def test_rollback_deletion(self):
2518
        tree = self.make_branch_and_tree('.')
2519
        self.build_tree(['a/', 'a/b'])
2520
        tt = TreeTransform(tree)
2521
        self.addCleanup(tt.finalize)
2522
        a_id = tt.trans_id_tree_path('a')
2523
        tt.delete_contents(a_id)
2524
        tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
2525
        self.assertRaises(Bogus, tt.apply,
2526
                          _mover=self.ExceptionFileMover(bad_target='d'))
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
2527
        self.assertPathExists('a')
2528
        self.assertPathExists('a/b')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2529
2530
5876.3.3 by Martin
Use better test class name
2531
class TestFinalizeRobustness(tests.TestCaseWithTransport):
2532
    """Ensure treetransform creation errors can be safely cleaned up after"""
5876.3.1 by Martin
Tests for DiskTreeTransform.finalize issues when create_file is interrupted
2533
2534
    def _override_globals_in_method(self, instance, method_name, globals):
2535
        """Replace method on instance with one with updated globals"""
2536
        import types
2537
        func = getattr(instance, method_name).im_func
2538
        new_globals = dict(func.func_globals)
2539
        new_globals.update(globals)
2540
        new_func = types.FunctionType(func.func_code, new_globals,
2541
            func.func_name, func.func_defaults)
2542
        setattr(instance, method_name,
2543
            types.MethodType(new_func, instance, instance.__class__))
2544
        self.addCleanup(delattr, instance, method_name)
2545
2546
    @staticmethod
2547
    def _fake_open_raises_before(name, mode):
2548
        """Like open() but raises before doing anything"""
2549
        raise RuntimeError
2550
2551
    @staticmethod
2552
    def _fake_open_raises_after(name, mode):
2553
        """Like open() but raises after creating file without returning"""
2554
        open(name, mode).close()
2555
        raise RuntimeError
2556
2557
    def create_transform_and_root_trans_id(self):
2558
        """Setup a transform creating a file in limbo"""
2559
        tree = self.make_branch_and_tree('.')
2560
        tt = TreeTransform(tree)
2561
        return tt, tt.create_path("a", tt.root)
2562
2563
    def create_transform_and_subdir_trans_id(self):
2564
        """Setup a transform creating a directory containing a file in limbo"""
2565
        tree = self.make_branch_and_tree('.')
2566
        tt = TreeTransform(tree)
2567
        d_trans_id = tt.create_path("d", tt.root)
2568
        tt.create_directory(d_trans_id)
2569
        f_trans_id = tt.create_path("a", d_trans_id)
2570
        tt.adjust_path("a", d_trans_id, f_trans_id)
2571
        return tt, f_trans_id
2572
2573
    def test_root_create_file_open_raises_before_creation(self):
2574
        tt, trans_id = self.create_transform_and_root_trans_id()
2575
        self._override_globals_in_method(tt, "create_file",
2576
            {"open": self._fake_open_raises_before})
2577
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2578
        path = tt._limbo_name(trans_id)
2579
        self.assertPathDoesNotExist(path)
2580
        tt.finalize()
2581
        self.assertPathDoesNotExist(tt._limbodir)
2582
2583
    def test_root_create_file_open_raises_after_creation(self):
2584
        tt, trans_id = self.create_transform_and_root_trans_id()
2585
        self._override_globals_in_method(tt, "create_file",
2586
            {"open": self._fake_open_raises_after})
2587
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2588
        path = tt._limbo_name(trans_id)
2589
        self.assertPathExists(path)
5876.3.2 by Martin
Change test that expects ImmortalLimbo to want the sensible thing instead, and fail for now
2590
        tt.finalize()
2591
        self.assertPathDoesNotExist(path)
2592
        self.assertPathDoesNotExist(tt._limbodir)
5876.3.1 by Martin
Tests for DiskTreeTransform.finalize issues when create_file is interrupted
2593
2594
    def test_subdir_create_file_open_raises_before_creation(self):
2595
        tt, trans_id = self.create_transform_and_subdir_trans_id()
2596
        self._override_globals_in_method(tt, "create_file",
2597
            {"open": self._fake_open_raises_before})
2598
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2599
        path = tt._limbo_name(trans_id)
2600
        self.assertPathDoesNotExist(path)
2601
        tt.finalize()
2602
        self.assertPathDoesNotExist(tt._limbodir)
2603
2604
    def test_subdir_create_file_open_raises_after_creation(self):
2605
        tt, trans_id = self.create_transform_and_subdir_trans_id()
2606
        self._override_globals_in_method(tt, "create_file",
2607
            {"open": self._fake_open_raises_after})
2608
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2609
        path = tt._limbo_name(trans_id)
2610
        self.assertPathExists(path)
2611
        tt.finalize()
2612
        self.assertPathDoesNotExist(path)
2613
        self.assertPathDoesNotExist(tt._limbodir)
2614
5876.4.4 by Andrew Bennetts
Fix edge cases in handling interrupts during _rename_in_limbo, with messy tests
2615
    def test_rename_in_limbo_rename_raises_after_rename(self):
2616
        tt, trans_id = self.create_transform_and_root_trans_id()
2617
        parent1 = tt.new_directory('parent1', tt.root)
2618
        child1 = tt.new_file('child1', parent1, 'contents')
2619
        parent2 = tt.new_directory('parent2', tt.root)
2620
2621
        class FakeOSModule(object):
2622
            def rename(self, old, new):
2623
                os.rename(old, new)
2624
                raise RuntimeError
2625
        self._override_globals_in_method(tt, "_rename_in_limbo",
2626
            {"os": FakeOSModule()})
2627
        self.assertRaises(
2628
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
2629
        path = osutils.pathjoin(tt._limbo_name(parent2), "child1")
2630
        self.assertPathExists(path)
2631
        tt.finalize()
2632
        self.assertPathDoesNotExist(path)
2633
        self.assertPathDoesNotExist(tt._limbodir)
2634
2635
    def test_rename_in_limbo_rename_raises_before_rename(self):
2636
        tt, trans_id = self.create_transform_and_root_trans_id()
2637
        parent1 = tt.new_directory('parent1', tt.root)
2638
        child1 = tt.new_file('child1', parent1, 'contents')
2639
        parent2 = tt.new_directory('parent2', tt.root)
2640
2641
        class FakeOSModule(object):
2642
            def rename(self, old, new):
2643
                raise RuntimeError
2644
        self._override_globals_in_method(tt, "_rename_in_limbo",
2645
            {"os": FakeOSModule()})
2646
        self.assertRaises(
2647
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
2648
        path = osutils.pathjoin(tt._limbo_name(parent1), "child1")
2649
        self.assertPathExists(path)
2650
        tt.finalize()
2651
        self.assertPathDoesNotExist(path)
2652
        self.assertPathDoesNotExist(tt._limbodir)
2653
5876.3.1 by Martin
Tests for DiskTreeTransform.finalize issues when create_file is interrupted
2654
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2655
class TestTransformMissingParent(tests.TestCaseWithTransport):
2656
5409.7.4 by Vincent Ladeuil
Take jam's review comments into account.
2657
    def make_tt_with_versioned_dir(self):
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2658
        wt = self.make_branch_and_tree('.')
2659
        self.build_tree(['dir/',])
2660
        wt.add(['dir'], ['dir-id'])
2661
        wt.commit('Create dir')
2662
        tt = TreeTransform(wt)
2663
        self.addCleanup(tt.finalize)
2664
        return wt, tt
2665
2666
    def test_resolve_create_parent_for_versioned_file(self):
5409.7.4 by Vincent Ladeuil
Take jam's review comments into account.
2667
        wt, tt = self.make_tt_with_versioned_dir()
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2668
        dir_tid = tt.trans_id_tree_file_id('dir-id')
2669
        file_tid = tt.new_file('file', dir_tid, 'Contents', file_id='file-id')
2670
        tt.delete_contents(dir_tid)
2671
        tt.unversion_file(dir_tid)
2672
        conflicts = resolve_conflicts(tt)
2673
        # one conflict for the missing directory, one for the unversioned
2674
        # parent
2675
        self.assertLength(2, conflicts)
2676
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
2677
    def test_non_versioned_file_create_conflict(self):
5409.7.4 by Vincent Ladeuil
Take jam's review comments into account.
2678
        wt, tt = self.make_tt_with_versioned_dir()
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2679
        dir_tid = tt.trans_id_tree_file_id('dir-id')
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
2680
        tt.new_file('file', dir_tid, 'Contents')
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2681
        tt.delete_contents(dir_tid)
2682
        tt.unversion_file(dir_tid)
2683
        conflicts = resolve_conflicts(tt)
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
2684
        # no conflicts or rather: orphaning 'file' resolve the 'dir' conflict
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
2685
        self.assertLength(1, conflicts)
2686
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
2687
                         conflicts.pop())
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2688
2689
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2690
A_ENTRY = ('a-id', ('a', 'a'), True, (True, True),
2691
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2692
                  (False, False))
2693
ROOT_ENTRY = ('TREE_ROOT', ('', ''), False, (True, True), (None, None),
5050.57.1 by Aaron Bentley
Make is_executable treat symlinks and directories the same across tree types.
2694
              ('', ''), ('directory', 'directory'), (False, False))
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2695
2696
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2697
class TestTransformPreview(tests.TestCaseWithTransport):
2698
2699
    def create_tree(self):
2700
        tree = self.make_branch_and_tree('.')
2701
        self.build_tree_contents([('a', 'content 1')])
4600.3.1 by Robert Collins
Set tree root ID in tree transform tests that don't care about the root id.
2702
        tree.set_root_id('TREE_ROOT')
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2703
        tree.add('a', 'a-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2704
        tree.commit('rev1', rev_id='rev1')
2705
        return tree.branch.repository.revision_tree('rev1')
2706
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2707
    def get_empty_preview(self):
2708
        repository = self.make_repository('repo')
2709
        tree = repository.revision_tree(_mod_revision.NULL_REVISION)
3199.1.4 by Vincent Ladeuil
Fix 16 leaked tmp dirs. Probably indicates a lock handling problem with TransformPreview
2710
        preview = TransformPreview(tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2711
        self.addCleanup(preview.finalize)
3199.1.4 by Vincent Ladeuil
Fix 16 leaked tmp dirs. Probably indicates a lock handling problem with TransformPreview
2712
        return preview
2713
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2714
    def test_transform_preview(self):
2715
        revision_tree = self.create_tree()
2716
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2717
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2718
2719
    def test_transform_preview_tree(self):
2720
        revision_tree = self.create_tree()
2721
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2722
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2723
        preview.get_preview_tree()
2724
3008.1.5 by Michael Hudson
a more precise test
2725
    def test_transform_new_file(self):
2726
        revision_tree = self.create_tree()
2727
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2728
        self.addCleanup(preview.finalize)
3008.1.5 by Michael Hudson
a more precise test
2729
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2730
        preview_tree = preview.get_preview_tree()
2731
        self.assertEqual(preview_tree.kind('file2-id'), 'file')
2732
        self.assertEqual(
2733
            preview_tree.get_file('file2-id').read(), 'content B\n')
2734
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2735
    def test_diff_preview_tree(self):
2736
        revision_tree = self.create_tree()
2737
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2738
        self.addCleanup(preview.finalize)
3008.1.4 by Michael Hudson
Merge test enhancements
2739
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2740
        preview_tree = preview.get_preview_tree()
2741
        out = StringIO()
2742
        show_diff_trees(revision_tree, preview_tree, out)
3008.1.4 by Michael Hudson
Merge test enhancements
2743
        lines = out.getvalue().splitlines()
2744
        self.assertEqual(lines[0], "=== added file 'file2'")
2745
        # 3 lines of diff administrivia
2746
        self.assertEqual(lines[4], "+content B")
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2747
2748
    def test_transform_conflicts(self):
2749
        revision_tree = self.create_tree()
2750
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2751
        self.addCleanup(preview.finalize)
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2752
        preview.new_file('a', preview.root, 'content 2')
2753
        resolve_conflicts(preview)
2754
        trans_id = preview.trans_id_file_id('a-id')
2755
        self.assertEqual('a.moved', preview.final_name(trans_id))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2756
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2757
    def get_tree_and_preview_tree(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2758
        revision_tree = self.create_tree()
2759
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2760
        self.addCleanup(preview.finalize)
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2761
        a_trans_id = preview.trans_id_file_id('a-id')
2762
        preview.delete_contents(a_trans_id)
2763
        preview.create_file('b content', a_trans_id)
2764
        preview_tree = preview.get_preview_tree()
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2765
        return revision_tree, preview_tree
2766
2767
    def test_iter_changes(self):
2768
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2769
        root = revision_tree.inventory.root.file_id
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2770
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
2771
                          (root, root), ('a', 'a'), ('file', 'file'),
2772
                          (False, False))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2773
                          list(preview_tree.iter_changes(revision_tree)))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2774
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2775
    def test_include_unchanged_succeeds(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2776
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2777
        changes = preview_tree.iter_changes(revision_tree,
2778
                                            include_unchanged=True)
2779
        root = revision_tree.inventory.root.file_id
2780
2781
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2782
2783
    def test_specific_files(self):
2784
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2785
        changes = preview_tree.iter_changes(revision_tree,
2786
                                            specific_files=[''])
5050.57.1 by Aaron Bentley
Make is_executable treat symlinks and directories the same across tree types.
2787
        self.assertEqual([A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2788
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2789
    def test_want_unversioned(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2790
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2791
        changes = preview_tree.iter_changes(revision_tree,
2792
                                            want_unversioned=True)
5050.57.1 by Aaron Bentley
Make is_executable treat symlinks and directories the same across tree types.
2793
        self.assertEqual([A_ENTRY], list(changes))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2794
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2795
    def test_ignore_extra_trees_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2796
        # extra_trees is harmless without specific_files, so we'll silently
2797
        # accept it, even though we won't use it.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2798
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2799
        preview_tree.iter_changes(revision_tree, extra_trees=[preview_tree])
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2800
2801
    def test_ignore_require_versioned_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2802
        # require_versioned is meaningless without specific_files.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2803
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2804
        preview_tree.iter_changes(revision_tree, require_versioned=False)
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2805
2806
    def test_ignore_pb(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2807
        # pb could be supported, but TT.iter_changes doesn't support it.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2808
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2809
        preview_tree.iter_changes(revision_tree)
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2810
2811
    def test_kind(self):
2812
        revision_tree = self.create_tree()
2813
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2814
        self.addCleanup(preview.finalize)
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2815
        preview.new_file('file', preview.root, 'contents', 'file-id')
2816
        preview.new_directory('directory', preview.root, 'dir-id')
2817
        preview_tree = preview.get_preview_tree()
2818
        self.assertEqual('file', preview_tree.kind('file-id'))
2819
        self.assertEqual('directory', preview_tree.kind('dir-id'))
2820
2821
    def test_get_file_mtime(self):
2822
        preview = self.get_empty_preview()
2823
        file_trans_id = preview.new_file('file', preview.root, 'contents',
2824
                                         'file-id')
2825
        limbo_path = preview._limbo_name(file_trans_id)
2826
        preview_tree = preview.get_preview_tree()
2827
        self.assertEqual(os.stat(limbo_path).st_mtime,
2828
                         preview_tree.get_file_mtime('file-id'))
2829
4635.1.1 by Aaron Bentley
Fix OSError with renamed files in PreviewTree.
2830
    def test_get_file_mtime_renamed(self):
2831
        work_tree = self.make_branch_and_tree('tree')
2832
        self.build_tree(['tree/file'])
2833
        work_tree.add('file', 'file-id')
2834
        preview = TransformPreview(work_tree)
2835
        self.addCleanup(preview.finalize)
2836
        file_trans_id = preview.trans_id_tree_file_id('file-id')
2837
        preview.adjust_path('renamed', preview.root, file_trans_id)
2838
        preview_tree = preview.get_preview_tree()
2839
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
2840
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
2841
5809.3.6 by Aaron Bentley
Fix PreviewTree.get_file_size.
2842
    def test_get_file_size(self):
2843
        work_tree = self.make_branch_and_tree('tree')
2844
        self.build_tree_contents([('tree/old', 'old')])
2845
        work_tree.add('old', 'old-id')
2846
        preview = TransformPreview(work_tree)
2847
        self.addCleanup(preview.finalize)
2848
        new_id = preview.new_file('name', preview.root, 'contents', 'new-id',
2849
                                  'executable')
2850
        tree = preview.get_preview_tree()
2851
        self.assertEqual(len('old'), tree.get_file_size('old-id'))
2852
        self.assertEqual(len('contents'), tree.get_file_size('new-id'))
2853
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2854
    def test_get_file(self):
2855
        preview = self.get_empty_preview()
2856
        preview.new_file('file', preview.root, 'contents', 'file-id')
2857
        preview_tree = preview.get_preview_tree()
2858
        tree_file = preview_tree.get_file('file-id')
2859
        try:
2860
            self.assertEqual('contents', tree_file.read())
2861
        finally:
2862
            tree_file.close()
3228.1.2 by James Henstridge
Simplify test, and move it down to be next to the other _PreviewTree tests.
2863
2864
    def test_get_symlink_target(self):
2865
        self.requireFeature(SymlinkFeature)
2866
        preview = self.get_empty_preview()
2867
        preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2868
        preview_tree = preview.get_preview_tree()
2869
        self.assertEqual('target',
2870
                         preview_tree.get_symlink_target('symlink-id'))
3363.2.18 by Aaron Bentley
Implement correct all_file_ids for PreviewTree
2871
2872
    def test_all_file_ids(self):
2873
        tree = self.make_branch_and_tree('tree')
2874
        self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2875
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2876
        preview = TransformPreview(tree)
2877
        self.addCleanup(preview.finalize)
2878
        preview.unversion_file(preview.trans_id_file_id('b-id'))
2879
        c_trans_id = preview.trans_id_file_id('c-id')
2880
        preview.unversion_file(c_trans_id)
2881
        preview.version_file('c-id', c_trans_id)
2882
        preview_tree = preview.get_preview_tree()
2883
        self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2884
                         preview_tree.all_file_ids())
3363.2.19 by Aaron Bentley
Make PreviewTree.path2id correct
2885
2886
    def test_path2id_deleted_unchanged(self):
2887
        tree = self.make_branch_and_tree('tree')
2888
        self.build_tree(['tree/unchanged', 'tree/deleted'])
2889
        tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2890
        preview = TransformPreview(tree)
2891
        self.addCleanup(preview.finalize)
2892
        preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2893
        preview_tree = preview.get_preview_tree()
2894
        self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2895
        self.assertIs(None, preview_tree.path2id('deleted'))
2896
2897
    def test_path2id_created(self):
2898
        tree = self.make_branch_and_tree('tree')
2899
        self.build_tree(['tree/unchanged'])
2900
        tree.add(['unchanged'], ['unchanged-id'])
2901
        preview = TransformPreview(tree)
2902
        self.addCleanup(preview.finalize)
2903
        preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2904
            'contents', 'new-id')
2905
        preview_tree = preview.get_preview_tree()
2906
        self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2907
2908
    def test_path2id_moved(self):
2909
        tree = self.make_branch_and_tree('tree')
2910
        self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2911
        tree.add(['old_parent', 'old_parent/child'],
2912
                 ['old_parent-id', 'child-id'])
2913
        preview = TransformPreview(tree)
2914
        self.addCleanup(preview.finalize)
2915
        new_parent = preview.new_directory('new_parent', preview.root,
2916
                                           'new_parent-id')
2917
        preview.adjust_path('child', new_parent,
2918
                            preview.trans_id_file_id('child-id'))
2919
        preview_tree = preview.get_preview_tree()
2920
        self.assertIs(None, preview_tree.path2id('old_parent/child'))
2921
        self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2922
2923
    def test_path2id_renamed_parent(self):
2924
        tree = self.make_branch_and_tree('tree')
2925
        self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2926
        tree.add(['old_name', 'old_name/child'],
2927
                 ['parent-id', 'child-id'])
2928
        preview = TransformPreview(tree)
2929
        self.addCleanup(preview.finalize)
2930
        preview.adjust_path('new_name', preview.root,
2931
                            preview.trans_id_file_id('parent-id'))
2932
        preview_tree = preview.get_preview_tree()
2933
        self.assertIs(None, preview_tree.path2id('old_name/child'))
2934
        self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
3363.2.21 by Aaron Bentley
Implement iter_entries_by_dir
2935
2936
    def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2937
        preview_tree = tt.get_preview_tree()
2938
        preview_result = list(preview_tree.iter_entries_by_dir(
2939
                              specific_file_ids))
2940
        tree = tt._tree
2941
        tt.apply()
2942
        actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2943
        self.assertEqual(actual_result, preview_result)
2944
2945
    def test_iter_entries_by_dir_new(self):
2946
        tree = self.make_branch_and_tree('tree')
2947
        tt = TreeTransform(tree)
2948
        tt.new_file('new', tt.root, 'contents', 'new-id')
2949
        self.assertMatchingIterEntries(tt)
2950
2951
    def test_iter_entries_by_dir_deleted(self):
2952
        tree = self.make_branch_and_tree('tree')
2953
        self.build_tree(['tree/deleted'])
2954
        tree.add('deleted', 'deleted-id')
2955
        tt = TreeTransform(tree)
2956
        tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2957
        self.assertMatchingIterEntries(tt)
2958
2959
    def test_iter_entries_by_dir_unversioned(self):
2960
        tree = self.make_branch_and_tree('tree')
2961
        self.build_tree(['tree/removed'])
2962
        tree.add('removed', 'removed-id')
2963
        tt = TreeTransform(tree)
2964
        tt.unversion_file(tt.trans_id_file_id('removed-id'))
2965
        self.assertMatchingIterEntries(tt)
2966
2967
    def test_iter_entries_by_dir_moved(self):
2968
        tree = self.make_branch_and_tree('tree')
2969
        self.build_tree(['tree/moved', 'tree/new_parent/'])
2970
        tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2971
        tt = TreeTransform(tree)
2972
        tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2973
                       tt.trans_id_file_id('moved-id'))
2974
        self.assertMatchingIterEntries(tt)
2975
2976
    def test_iter_entries_by_dir_specific_file_ids(self):
2977
        tree = self.make_branch_and_tree('tree')
2978
        tree.set_root_id('tree-root-id')
2979
        self.build_tree(['tree/parent/', 'tree/parent/child'])
2980
        tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2981
        tt = TreeTransform(tree)
2982
        self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
3363.2.26 by Aaron Bentley
Get symlinks working
2983
2984
    def test_symlink_content_summary(self):
2985
        self.requireFeature(SymlinkFeature)
2986
        preview = self.get_empty_preview()
2987
        preview.new_symlink('path', preview.root, 'target', 'path-id')
2988
        summary = preview.get_preview_tree().path_content_summary('path')
2989
        self.assertEqual(('symlink', None, None, 'target'), summary)
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2990
2991
    def test_missing_content_summary(self):
2992
        preview = self.get_empty_preview()
2993
        summary = preview.get_preview_tree().path_content_summary('path')
2994
        self.assertEqual(('missing', None, None, None), summary)
2995
2996
    def test_deleted_content_summary(self):
2997
        tree = self.make_branch_and_tree('tree')
2998
        self.build_tree(['tree/path/'])
2999
        tree.add('path')
3000
        preview = TransformPreview(tree)
3001
        self.addCleanup(preview.finalize)
3002
        preview.delete_contents(preview.trans_id_tree_path('path'))
3003
        summary = preview.get_preview_tree().path_content_summary('path')
3004
        self.assertEqual(('missing', None, None, None), summary)
3005
3363.2.30 by Aaron Bentley
Improve execute bit testing
3006
    def test_file_content_summary_executable(self):
3007
        preview = self.get_empty_preview()
3008
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
3009
        preview.set_executability(True, path_id)
3010
        summary = preview.get_preview_tree().path_content_summary('path')
3011
        self.assertEqual(4, len(summary))
3012
        self.assertEqual('file', summary[0])
3013
        # size must be known
3014
        self.assertEqual(len('contents'), summary[1])
3015
        # executable
3016
        self.assertEqual(True, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
3017
        # will not have hash (not cheap to determine)
3018
        self.assertIs(None, summary[3])
3363.2.30 by Aaron Bentley
Improve execute bit testing
3019
3020
    def test_change_executability(self):
3021
        tree = self.make_branch_and_tree('tree')
3022
        self.build_tree(['tree/path'])
3023
        tree.add('path')
3024
        preview = TransformPreview(tree)
3025
        self.addCleanup(preview.finalize)
3026
        path_id = preview.trans_id_tree_path('path')
3027
        preview.set_executability(True, path_id)
3028
        summary = preview.get_preview_tree().path_content_summary('path')
3029
        self.assertEqual(True, summary[2])
3030
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
3031
    def test_file_content_summary_non_exec(self):
3032
        preview = self.get_empty_preview()
3033
        preview.new_file('path', preview.root, 'contents', 'path-id')
3034
        summary = preview.get_preview_tree().path_content_summary('path')
3035
        self.assertEqual(4, len(summary))
3036
        self.assertEqual('file', summary[0])
3037
        # size must be known
3363.2.30 by Aaron Bentley
Improve execute bit testing
3038
        self.assertEqual(len('contents'), summary[1])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
3039
        # not executable
4789.15.3 by John Arbash Meinel
PreviewTree now returns False for exec bit properly.
3040
        self.assertEqual(False, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
3041
        # will not have hash (not cheap to determine)
3042
        self.assertIs(None, summary[3])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
3043
3044
    def test_dir_content_summary(self):
3045
        preview = self.get_empty_preview()
3046
        preview.new_directory('path', preview.root, 'path-id')
3047
        summary = preview.get_preview_tree().path_content_summary('path')
3048
        self.assertEqual(('directory', None, None, None), summary)
3049
3050
    def test_tree_content_summary(self):
3051
        preview = self.get_empty_preview()
3052
        path = preview.new_directory('path', preview.root, 'path-id')
3053
        preview.set_tree_reference('rev-1', path)
3054
        summary = preview.get_preview_tree().path_content_summary('path')
3055
        self.assertEqual(4, len(summary))
3056
        self.assertEqual('tree-reference', summary[0])
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
3057
3058
    def test_annotate(self):
3059
        tree = self.make_branch_and_tree('tree')
3060
        self.build_tree_contents([('tree/file', 'a\n')])
3061
        tree.add('file', 'file-id')
3062
        tree.commit('a', rev_id='one')
3063
        self.build_tree_contents([('tree/file', 'a\nb\n')])
3064
        preview = TransformPreview(tree)
3065
        self.addCleanup(preview.finalize)
3066
        file_trans_id = preview.trans_id_file_id('file-id')
3067
        preview.delete_contents(file_trans_id)
3068
        preview.create_file('a\nb\nc\n', file_trans_id)
3069
        preview_tree = preview.get_preview_tree()
3070
        expected = [
3071
            ('one', 'a\n'),
3072
            ('me:', 'b\n'),
3073
            ('me:', 'c\n'),
3074
        ]
3075
        annotation = preview_tree.annotate_iter('file-id', 'me:')
3076
        self.assertEqual(expected, annotation)
3077
3078
    def test_annotate_missing(self):
3079
        preview = self.get_empty_preview()
3080
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
3081
        preview_tree = preview.get_preview_tree()
3082
        expected = [
3083
            ('me:', 'a\n'),
3084
            ('me:', 'b\n'),
3085
            ('me:', 'c\n'),
3086
         ]
3087
        annotation = preview_tree.annotate_iter('file-id', 'me:')
3088
        self.assertEqual(expected, annotation)
3089
3363.7.3 by Aaron Bentley
Add test that annotate correctly handles renames
3090
    def test_annotate_rename(self):
3091
        tree = self.make_branch_and_tree('tree')
3092
        self.build_tree_contents([('tree/file', 'a\n')])
3093
        tree.add('file', 'file-id')
3094
        tree.commit('a', rev_id='one')
3095
        preview = TransformPreview(tree)
3096
        self.addCleanup(preview.finalize)
3097
        file_trans_id = preview.trans_id_file_id('file-id')
3098
        preview.adjust_path('newname', preview.root, file_trans_id)
3099
        preview_tree = preview.get_preview_tree()
3100
        expected = [
3101
            ('one', 'a\n'),
3102
        ]
3103
        annotation = preview_tree.annotate_iter('file-id', 'me:')
3104
        self.assertEqual(expected, annotation)
3105
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
3106
    def test_annotate_deleted(self):
3107
        tree = self.make_branch_and_tree('tree')
3108
        self.build_tree_contents([('tree/file', 'a\n')])
3109
        tree.add('file', 'file-id')
3110
        tree.commit('a', rev_id='one')
3111
        self.build_tree_contents([('tree/file', 'a\nb\n')])
3112
        preview = TransformPreview(tree)
3113
        self.addCleanup(preview.finalize)
3114
        file_trans_id = preview.trans_id_file_id('file-id')
3115
        preview.delete_contents(file_trans_id)
3116
        preview_tree = preview.get_preview_tree()
3117
        annotation = preview_tree.annotate_iter('file-id', 'me:')
3118
        self.assertIs(None, annotation)
3119
3363.2.36 by Aaron Bentley
Fix PreviewTree.stored_kind
3120
    def test_stored_kind(self):
3121
        preview = self.get_empty_preview()
3122
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
3123
        preview_tree = preview.get_preview_tree()
3124
        self.assertEqual('file', preview_tree.stored_kind('file-id'))
3363.2.37 by Aaron Bentley
Fix is_executable
3125
3126
    def test_is_executable(self):
3127
        preview = self.get_empty_preview()
3128
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
3129
        preview.set_executability(True, preview.trans_id_file_id('file-id'))
3130
        preview_tree = preview.get_preview_tree()
3131
        self.assertEqual(True, preview_tree.is_executable('file-id'))
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
3132
3571.1.1 by Aaron Bentley
Allow set/get of parent_ids in PreviewTree
3133
    def test_get_set_parent_ids(self):
3134
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3135
        self.assertEqual([], preview_tree.get_parent_ids())
3136
        preview_tree.set_parent_ids(['rev-1'])
3137
        self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
3138
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
3139
    def test_plan_file_merge(self):
3140
        work_a = self.make_branch_and_tree('wta')
3141
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
3142
        work_a.add('file', 'file-id')
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
3143
        base_id = work_a.commit('base version')
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
3144
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
3145
        preview = TransformPreview(work_a)
3146
        self.addCleanup(preview.finalize)
3147
        trans_id = preview.trans_id_file_id('file-id')
3148
        preview.delete_contents(trans_id)
3149
        preview.create_file('b\nc\nd\ne\n', trans_id)
3150
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
3151
        tree_a = preview.get_preview_tree()
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
3152
        tree_a.set_parent_ids([base_id])
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
3153
        self.assertEqual([
3363.9.5 by Aaron Bentley
Move killed-a from top to bottom
3154
            ('killed-a', 'a\n'),
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
3155
            ('killed-b', 'b\n'),
3156
            ('unchanged', 'c\n'),
3157
            ('unchanged', 'd\n'),
3158
            ('new-a', 'e\n'),
3159
            ('new-b', 'f\n'),
3160
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
3363.9.8 by Aaron Bentley
Ensure plan_file_merge works with a RevisionTree as the basis
3161
3162
    def test_plan_file_merge_revision_tree(self):
3163
        work_a = self.make_branch_and_tree('wta')
3164
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
3165
        work_a.add('file', 'file-id')
3166
        base_id = work_a.commit('base version')
3167
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
3168
        preview = TransformPreview(work_a.basis_tree())
3169
        self.addCleanup(preview.finalize)
3170
        trans_id = preview.trans_id_file_id('file-id')
3171
        preview.delete_contents(trans_id)
3172
        preview.create_file('b\nc\nd\ne\n', trans_id)
3173
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
3174
        tree_a = preview.get_preview_tree()
3175
        tree_a.set_parent_ids([base_id])
3176
        self.assertEqual([
3177
            ('killed-a', 'a\n'),
3178
            ('killed-b', 'b\n'),
3179
            ('unchanged', 'c\n'),
3180
            ('unchanged', 'd\n'),
3181
            ('new-a', 'e\n'),
3182
            ('new-b', 'f\n'),
3183
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
3184
3185
    def test_walkdirs(self):
3186
        preview = self.get_empty_preview()
4634.57.3 by Aaron Bentley
Fix failing test.
3187
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
3188
        # FIXME: new_directory should mark root.
4634.122.6 by John Arbash Meinel
Fix a test that used 'adjust_path' to set the root.
3189
        preview.fixup_new_roots()
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
3190
        preview_tree = preview.get_preview_tree()
3191
        file_trans_id = preview.new_file('a', preview.root, 'contents',
3192
                                         'a-id')
3193
        expected = [(('', 'tree-root'),
3194
                    [('a', 'a', 'file', None, 'a-id', 'file')])]
3195
        self.assertEqual(expected, list(preview_tree.walkdirs()))
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
3196
3197
    def test_extras(self):
3198
        work_tree = self.make_branch_and_tree('tree')
3199
        self.build_tree(['tree/removed-file', 'tree/existing-file',
3200
                         'tree/not-removed-file'])
3201
        work_tree.add(['removed-file', 'not-removed-file'])
3202
        preview = TransformPreview(work_tree)
3363.13.3 by Aaron Bentley
Add cleanup
3203
        self.addCleanup(preview.finalize)
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
3204
        preview.new_file('new-file', preview.root, 'contents')
3205
        preview.new_file('new-versioned-file', preview.root, 'contents',
3206
                         'new-versioned-id')
3207
        tree = preview.get_preview_tree()
3208
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
3209
        self.assertEqual(set(['new-file', 'removed-file', 'existing-file']),
3210
                         set(tree.extras()))
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
3211
3363.17.2 by Aaron Bentley
Add text checking
3212
    def test_merge_into_preview(self):
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
3213
        work_tree = self.make_branch_and_tree('tree')
3363.17.2 by Aaron Bentley
Add text checking
3214
        self.build_tree_contents([('tree/file','b\n')])
3215
        work_tree.add('file', 'file-id')
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
3216
        work_tree.commit('first commit')
3217
        child_tree = work_tree.bzrdir.sprout('child').open_workingtree()
3363.17.2 by Aaron Bentley
Add text checking
3218
        self.build_tree_contents([('child/file','b\nc\n')])
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
3219
        child_tree.commit('child commit')
3220
        child_tree.lock_write()
3221
        self.addCleanup(child_tree.unlock)
3222
        work_tree.lock_write()
3223
        self.addCleanup(work_tree.unlock)
3224
        preview = TransformPreview(work_tree)
3225
        self.addCleanup(preview.finalize)
3363.17.6 by Aaron Bentley
Improve test scenario
3226
        file_trans_id = preview.trans_id_file_id('file-id')
3227
        preview.delete_contents(file_trans_id)
3228
        preview.create_file('a\nb\n', file_trans_id)
4634.57.2 by Aaron Bentley
Fix failing test.
3229
        preview_tree = preview.get_preview_tree()
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
3230
        merger = Merger.from_revision_ids(None, preview_tree,
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
3231
                                          child_tree.branch.last_revision(),
3232
                                          other_branch=child_tree.branch,
3233
                                          tree_branch=work_tree.branch)
3234
        merger.merge_type = Merge3Merger
3235
        tt = merger.make_merger().make_preview_transform()
3363.17.2 by Aaron Bentley
Add text checking
3236
        self.addCleanup(tt.finalize)
3237
        final_tree = tt.get_preview_tree()
3238
        self.assertEqual('a\nb\nc\n', final_tree.get_file_text('file-id'))
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
3239
3240
    def test_merge_preview_into_workingtree(self):
3241
        tree = self.make_branch_and_tree('tree')
4600.3.1 by Robert Collins
Set tree root ID in tree transform tests that don't care about the root id.
3242
        tree.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
3243
        tt = TransformPreview(tree)
3244
        self.addCleanup(tt.finalize)
3245
        tt.new_file('name', tt.root, 'content', 'file-id')
3246
        tree2 = self.make_branch_and_tree('tree2')
4600.3.1 by Robert Collins
Set tree root ID in tree transform tests that don't care about the root id.
3247
        tree2.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
3248
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
3249
                                         None, tree.basis_tree())
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
3250
        merger.merge_type = Merge3Merger
3251
        merger.do_merge()
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
3252
3363.17.21 by Aaron Bentley
Conflicts are handled when merging from preview trees
3253
    def test_merge_preview_into_workingtree_handles_conflicts(self):
3254
        tree = self.make_branch_and_tree('tree')
3255
        self.build_tree_contents([('tree/foo', 'bar')])
3256
        tree.add('foo', 'foo-id')
3257
        tree.commit('foo')
3258
        tt = TransformPreview(tree)
3259
        self.addCleanup(tt.finalize)
3260
        trans_id = tt.trans_id_file_id('foo-id')
3261
        tt.delete_contents(trans_id)
3262
        tt.create_file('baz', trans_id)
3263
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
3264
        self.build_tree_contents([('tree2/foo', 'qux')])
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
3265
        pb = None
3363.17.21 by Aaron Bentley
Conflicts are handled when merging from preview trees
3266
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
3267
                                         pb, tree.basis_tree())
3268
        merger.merge_type = Merge3Merger
3269
        merger.do_merge()
3270
5809.3.2 by Aaron Bentley
Support PreviewTree.has_filename.
3271
    def test_has_filename(self):
3272
        wt = self.make_branch_and_tree('tree')
3273
        self.build_tree(['tree/unmodified', 'tree/removed', 'tree/modified'])
3274
        tt = TransformPreview(wt)
3275
        removed_id = tt.trans_id_tree_path('removed')
3276
        tt.delete_contents(removed_id)
3277
        tt.new_file('new', tt.root, 'contents')
3278
        modified_id = tt.trans_id_tree_path('modified')
3279
        tt.delete_contents(modified_id)
3280
        tt.create_file('modified-contents', modified_id)
3281
        self.addCleanup(tt.finalize)
3282
        tree = tt.get_preview_tree()
3283
        self.assertTrue(tree.has_filename('unmodified'))
3284
        self.assertFalse(tree.has_filename('not-present'))
3285
        self.assertFalse(tree.has_filename('removed'))
3286
        self.assertTrue(tree.has_filename('new'))
3287
        self.assertTrue(tree.has_filename('modified'))
3288
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
3289
    def test_is_executable(self):
3290
        tree = self.make_branch_and_tree('tree')
3291
        preview = TransformPreview(tree)
3292
        self.addCleanup(preview.finalize)
3293
        preview.new_file('foo', preview.root, 'bar', 'baz-id')
3294
        preview_tree = preview.get_preview_tree()
3295
        self.assertEqual(False, preview_tree.is_executable('baz-id',
3296
                                                           'tree/foo'))
3297
        self.assertEqual(False, preview_tree.is_executable('baz-id'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3298
4354.4.4 by Aaron Bentley
Simplify by using CommitBuilder directly
3299
    def test_commit_preview_tree(self):
3300
        tree = self.make_branch_and_tree('tree')
3301
        rev_id = tree.commit('rev1')
3302
        tree.branch.lock_write()
3303
        self.addCleanup(tree.branch.unlock)
3304
        tt = TransformPreview(tree)
3305
        tt.new_file('file', tt.root, 'contents', 'file_id')
3306
        self.addCleanup(tt.finalize)
3307
        preview = tt.get_preview_tree()
3308
        preview.set_parent_ids([rev_id])
3309
        builder = tree.branch.get_commit_builder([rev_id])
3310
        list(builder.record_iter_changes(preview, rev_id, tt.iter_changes()))
3311
        builder.finish_inventory()
3312
        rev2_id = builder.commit('rev2')
3313
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
3314
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
3315
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
3316
    def test_ascii_limbo_paths(self):
4634.79.2 by Aaron Bentley
Avoid runing test on non-unicode filesystems.
3317
        self.requireFeature(tests.UnicodeFilenameFeature)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
3318
        branch = self.make_branch('any')
3319
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
3320
        tt = TransformPreview(tree)
4789.25.7 by John Arbash Meinel
We can run the executable tests.
3321
        self.addCleanup(tt.finalize)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
3322
        foo_id = tt.new_directory('', ROOT_PARENT)
3323
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
3324
        limbo_path = tt._limbo_name(bar_id)
3325
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
3326
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3327
0.13.13 by Aaron Bentley
Add direct test of serialization records
3328
class FakeSerializer(object):
3329
    """Serializer implementation that simply returns the input.
3330
3331
    The input is returned in the order used by pack.ContainerPushParser.
3332
    """
3333
    @staticmethod
3334
    def bytes_record(bytes, names):
3335
        return names, bytes
3336
3337
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3338
class TestSerializeTransform(tests.TestCaseWithTransport):
3339
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
3340
    _test_needs_features = [tests.UnicodeFilenameFeature]
3341
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3342
    def get_preview(self, tree=None):
3343
        if tree is None:
3344
            tree = self.make_branch_and_tree('tree')
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
3345
        tt = TransformPreview(tree)
3346
        self.addCleanup(tt.finalize)
3347
        return tt
3348
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3349
    def assertSerializesTo(self, expected, tt):
3350
        records = list(tt.serialize(FakeSerializer()))
3351
        self.assertEqual(expected, records)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3352
0.13.13 by Aaron Bentley
Add direct test of serialization records
3353
    @staticmethod
3354
    def default_attribs():
3355
        return {
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3356
            '_id_number': 1,
0.13.13 by Aaron Bentley
Add direct test of serialization records
3357
            '_new_name': {},
3358
            '_new_parent': {},
3359
            '_new_executability': {},
3360
            '_new_id': {},
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3361
            '_tree_path_ids': {'': 'new-0'},
0.13.13 by Aaron Bentley
Add direct test of serialization records
3362
            '_removed_id': [],
3363
            '_removed_contents': [],
3364
            '_non_present_ids': {},
3365
            }
3366
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3367
    def make_records(self, attribs, contents):
3368
        records = [
3369
            (((('attribs'),),), bencode.bencode(attribs))]
3370
        records.extend([(((n, k),), c) for n, k, c in contents])
3371
        return records
3372
0.13.13 by Aaron Bentley
Add direct test of serialization records
3373
    def creation_records(self):
3374
        attribs = self.default_attribs()
3375
        attribs['_id_number'] = 3
3376
        attribs['_new_name'] = {
3377
            'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
3378
        attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
3379
        attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
3380
        attribs['_new_executability'] = {'new-1': 1}
3381
        contents = [
3382
            ('new-1', 'file', 'i 1\nbar\n'),
3383
            ('new-2', 'directory', ''),
3384
            ]
3385
        return self.make_records(attribs, contents)
3386
3387
    def test_serialize_creation(self):
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
3388
        tt = self.get_preview()
0.13.13 by Aaron Bentley
Add direct test of serialization records
3389
        tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
3390
        tt.new_directory('qux', tt.root, 'quxx')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
3391
        self.assertSerializesTo(self.creation_records(), tt)
0.13.13 by Aaron Bentley
Add direct test of serialization records
3392
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
3393
    def test_deserialize_creation(self):
3394
        tt = self.get_preview()
3395
        tt.deserialize(iter(self.creation_records()))
3396
        self.assertEqual(3, tt._id_number)
3397
        self.assertEqual({'new-1': u'foo\u1234',
3398
                          'new-2': 'qux'}, tt._new_name)
3399
        self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
3400
        self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
3401
        self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
3402
        self.assertEqual({'new-1': True}, tt._new_executability)
3403
        self.assertEqual({'new-1': 'file',
3404
                          'new-2': 'directory'}, tt._new_contents)
3405
        foo_limbo = open(tt._limbo_name('new-1'), 'rb')
3406
        try:
3407
            foo_content = foo_limbo.read()
3408
        finally:
3409
            foo_limbo.close()
3410
        self.assertEqual('bar', foo_content)
3411
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3412
    def symlink_creation_records(self):
3413
        attribs = self.default_attribs()
3414
        attribs['_id_number'] = 2
3415
        attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
3416
        attribs['_new_parent'] = {'new-1': 'new-0'}
3417
        contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
3418
        return self.make_records(attribs, contents)
3419
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3420
    def test_serialize_symlink_creation(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3421
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3422
        tt = self.get_preview()
0.13.16 by Aaron Bentley
Add unicode symlink targets to tests
3423
        tt.new_symlink(u'foo\u1234', tt.root, u'bar\u1234')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
3424
        self.assertSerializesTo(self.symlink_creation_records(), tt)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3425
3426
    def test_deserialize_symlink_creation(self):
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
3427
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3428
        tt = self.get_preview()
3429
        tt.deserialize(iter(self.symlink_creation_records()))
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
3430
        abspath = tt._limbo_name('new-1')
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
3431
        foo_content = osutils.readlink(abspath)
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
3432
        self.assertEqual(u'bar\u1234', foo_content)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3433
0.13.19 by Aaron Bentley
Clean up serialization tests
3434
    def make_destruction_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3435
        tree = self.make_branch_and_tree('.')
3436
        self.build_tree([u'foo\u1234', 'bar'])
3437
        tree.add([u'foo\u1234', 'bar'], ['foo-id', 'bar-id'])
0.13.19 by Aaron Bentley
Clean up serialization tests
3438
        return self.get_preview(tree)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3439
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3440
    def destruction_records(self):
3441
        attribs = self.default_attribs()
3442
        attribs['_id_number'] = 3
3443
        attribs['_removed_id'] = ['new-1']
3444
        attribs['_removed_contents'] = ['new-2']
3445
        attribs['_tree_path_ids'] = {
3446
            '': 'new-0',
3447
            u'foo\u1234'.encode('utf-8'): 'new-1',
3448
            'bar': 'new-2',
3449
            }
3450
        return self.make_records(attribs, [])
3451
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3452
    def test_serialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
3453
        tt = self.make_destruction_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3454
        foo_trans_id = tt.trans_id_tree_file_id('foo-id')
3455
        tt.unversion_file(foo_trans_id)
3456
        bar_trans_id = tt.trans_id_tree_file_id('bar-id')
3457
        tt.delete_contents(bar_trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3458
        self.assertSerializesTo(self.destruction_records(), tt)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3459
3460
    def test_deserialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
3461
        tt = self.make_destruction_preview()
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3462
        tt.deserialize(iter(self.destruction_records()))
3463
        self.assertEqual({u'foo\u1234': 'new-1',
3464
                          'bar': 'new-2',
3465
                          '': tt.root}, tt._tree_path_ids)
3466
        self.assertEqual({'new-1': u'foo\u1234',
3467
                          'new-2': 'bar',
3468
                          tt.root: ''}, tt._tree_id_paths)
3469
        self.assertEqual(set(['new-1']), tt._removed_id)
3470
        self.assertEqual(set(['new-2']), tt._removed_contents)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3471
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3472
    def missing_records(self):
3473
        attribs = self.default_attribs()
3474
        attribs['_id_number'] = 2
3475
        attribs['_non_present_ids'] = {
3476
            'boo': 'new-1',}
3477
        return self.make_records(attribs, [])
3478
3479
    def test_serialize_missing(self):
3480
        tt = self.get_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3481
        boo_trans_id = tt.trans_id_file_id('boo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3482
        self.assertSerializesTo(self.missing_records(), tt)
3483
3484
    def test_deserialize_missing(self):
3485
        tt = self.get_preview()
3486
        tt.deserialize(iter(self.missing_records()))
3487
        self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
3488
3489
    def make_modification_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3490
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3491
        LINES_TWO = 'z\nbb\nx\ndd\n'
3492
        tree = self.make_branch_and_tree('tree')
3493
        self.build_tree_contents([('tree/file', LINES_ONE)])
3494
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3495
        return self.get_preview(tree), LINES_TWO
3496
3497
    def modification_records(self):
3498
        attribs = self.default_attribs()
3499
        attribs['_id_number'] = 2
3500
        attribs['_tree_path_ids'] = {
3501
            'file': 'new-1',
3502
            '': 'new-0',}
3503
        attribs['_removed_contents'] = ['new-1']
3504
        contents = [('new-1', 'file',
3505
                     'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
3506
        return self.make_records(attribs, contents)
3507
3508
    def test_serialize_modification(self):
3509
        tt, LINES = self.make_modification_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3510
        trans_id = tt.trans_id_file_id('file-id')
3511
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3512
        tt.create_file(LINES, trans_id)
3513
        self.assertSerializesTo(self.modification_records(), tt)
3514
3515
    def test_deserialize_modification(self):
3516
        tt, LINES = self.make_modification_preview()
3517
        tt.deserialize(iter(self.modification_records()))
3518
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3519
3520
    def make_kind_change_preview(self):
3521
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3522
        tree = self.make_branch_and_tree('tree')
3523
        self.build_tree(['tree/foo/'])
3524
        tree.add('foo', 'foo-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3525
        return self.get_preview(tree), LINES
3526
3527
    def kind_change_records(self):
3528
        attribs = self.default_attribs()
3529
        attribs['_id_number'] = 2
3530
        attribs['_tree_path_ids'] = {
3531
            'foo': 'new-1',
3532
            '': 'new-0',}
3533
        attribs['_removed_contents'] = ['new-1']
3534
        contents = [('new-1', 'file',
3535
                     'i 4\na\nb\nc\nd\n\n')]
3536
        return self.make_records(attribs, contents)
3537
3538
    def test_serialize_kind_change(self):
3539
        tt, LINES = self.make_kind_change_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3540
        trans_id = tt.trans_id_file_id('foo-id')
3541
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3542
        tt.create_file(LINES, trans_id)
3543
        self.assertSerializesTo(self.kind_change_records(), tt)
3544
3545
    def test_deserialize_kind_change(self):
3546
        tt, LINES = self.make_kind_change_preview()
3547
        tt.deserialize(iter(self.kind_change_records()))
3548
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3549
3550
    def make_add_contents_preview(self):
3551
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3552
        tree = self.make_branch_and_tree('tree')
3553
        self.build_tree(['tree/foo'])
3554
        tree.add('foo')
3555
        os.unlink('tree/foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3556
        return self.get_preview(tree), LINES
3557
3558
    def add_contents_records(self):
3559
        attribs = self.default_attribs()
3560
        attribs['_id_number'] = 2
3561
        attribs['_tree_path_ids'] = {
3562
            'foo': 'new-1',
3563
            '': 'new-0',}
3564
        contents = [('new-1', 'file',
3565
                     'i 4\na\nb\nc\nd\n\n')]
3566
        return self.make_records(attribs, contents)
3567
3568
    def test_serialize_add_contents(self):
3569
        tt, LINES = self.make_add_contents_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3570
        trans_id = tt.trans_id_tree_path('foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3571
        tt.create_file(LINES, trans_id)
3572
        self.assertSerializesTo(self.add_contents_records(), tt)
3573
3574
    def test_deserialize_add_contents(self):
3575
        tt, LINES = self.make_add_contents_preview()
3576
        tt.deserialize(iter(self.add_contents_records()))
3577
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3578
3579
    def test_get_parents_lines(self):
3580
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3581
        LINES_TWO = 'z\nbb\nx\ndd\n'
3582
        tree = self.make_branch_and_tree('tree')
3583
        self.build_tree_contents([('tree/file', LINES_ONE)])
3584
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3585
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3586
        trans_id = tt.trans_id_tree_path('file')
3587
        self.assertEqual((['aa\n', 'bb\n', 'cc\n', 'dd\n'],),
3588
            tt._get_parents_lines(trans_id))
3589
3590
    def test_get_parents_texts(self):
3591
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3592
        LINES_TWO = 'z\nbb\nx\ndd\n'
3593
        tree = self.make_branch_and_tree('tree')
3594
        self.build_tree_contents([('tree/file', LINES_ONE)])
3595
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3596
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3597
        trans_id = tt.trans_id_tree_path('file')
3598
        self.assertEqual((LINES_ONE,),
3599
            tt._get_parents_texts(trans_id))
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
3600
3601
3602
class TestOrphan(tests.TestCaseWithTransport):
3603
3604
    def test_no_orphan_for_transform_preview(self):
3605
        tree = self.make_branch_and_tree('tree')
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3606
        tt = transform.TransformPreview(tree)
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
3607
        self.addCleanup(tt.finalize)
3608
        self.assertRaises(NotImplementedError, tt.new_orphan, 'foo', 'bar')
3609
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3610
    def _set_orphan_policy(self, wt, policy):
5409.1.24 by Vincent Ladeuil
Rename bzrlib.transform.orphan_policy to bzr.transform.orphan_policy.
3611
        wt.branch.get_config().set_user_option('bzr.transform.orphan_policy',
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3612
                                               policy)
3613
3614
    def _prepare_orphan(self, wt):
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3615
        self.build_tree(['dir/', 'dir/file', 'dir/foo'])
3616
        wt.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
3617
        wt.commit('add dir and file ignoring foo')
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3618
        tt = transform.TreeTransform(wt)
3619
        self.addCleanup(tt.finalize)
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3620
        # dir and bar are deleted
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3621
        dir_tid = tt.trans_id_tree_path('dir')
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3622
        file_tid = tt.trans_id_tree_path('dir/file')
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3623
        orphan_tid = tt.trans_id_tree_path('dir/foo')
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3624
        tt.delete_contents(file_tid)
3625
        tt.unversion_file(file_tid)
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3626
        tt.delete_contents(dir_tid)
3627
        tt.unversion_file(dir_tid)
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3628
        # There should be a conflict because dir still contain foo
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3629
        raw_conflicts = tt.find_conflicts()
3630
        self.assertLength(1, raw_conflicts)
3631
        self.assertEqual(('missing parent', 'new-1'), raw_conflicts[0])
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3632
        return tt, orphan_tid
3633
3634
    def test_new_orphan_created(self):
3635
        wt = self.make_branch_and_tree('.')
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
3636
        self._set_orphan_policy(wt, 'move')
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3637
        tt, orphan_tid = self._prepare_orphan(wt)
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3638
        warnings = []
3639
        def warning(*args):
3640
            warnings.append(args[0] % args[1:])
3641
        self.overrideAttr(trace, 'warning', warning)
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3642
        remaining_conflicts = resolve_conflicts(tt)
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3643
        self.assertEquals(['dir/foo has been orphaned in bzr-orphans'],
3644
                          warnings)
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3645
        # Yeah for resolved conflicts !
3646
        self.assertLength(0, remaining_conflicts)
3647
        # We have a new orphan
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3648
        self.assertEquals('foo.~1~', tt.final_name(orphan_tid))
5409.7.4 by Vincent Ladeuil
Take jam's review comments into account.
3649
        self.assertEquals('bzr-orphans',
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3650
                          tt.final_name(tt.final_parent(orphan_tid)))
3651
3652
    def test_never_orphan(self):
3653
        wt = self.make_branch_and_tree('.')
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
3654
        self._set_orphan_policy(wt, 'conflict')
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3655
        tt, orphan_tid = self._prepare_orphan(wt)
3656
        remaining_conflicts = resolve_conflicts(tt)
3657
        self.assertLength(1, remaining_conflicts)
3658
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
3659
                         remaining_conflicts.pop())
3660
3661
    def test_orphan_error(self):
3662
        def bogus_orphan(tt, orphan_id, parent_id):
3663
            raise transform.OrphaningError(tt.final_name(orphan_id),
3664
                                           tt.final_name(parent_id))
3665
        transform.orphaning_registry.register('bogus', bogus_orphan,
3666
                                              'Raise an error when orphaning')
3667
        wt = self.make_branch_and_tree('.')
3668
        self._set_orphan_policy(wt, 'bogus')
3669
        tt, orphan_tid = self._prepare_orphan(wt)
3670
        remaining_conflicts = resolve_conflicts(tt)
3671
        self.assertLength(1, remaining_conflicts)
3672
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
3673
                         remaining_conflicts.pop())
5409.1.17 by Vincent Ladeuil
Ensures we fallback to the default policy if a bogus one is specified.
3674
3675
    def test_unknown_orphan_policy(self):
3676
        wt = self.make_branch_and_tree('.')
3677
        # Set a fictional policy nobody ever implemented
3678
        self._set_orphan_policy(wt, 'donttouchmypreciouuus')
3679
        tt, orphan_tid = self._prepare_orphan(wt)
3680
        warnings = []
3681
        def warning(*args):
3682
            warnings.append(args[0] % args[1:])
3683
        self.overrideAttr(trace, 'warning', warning)
3684
        remaining_conflicts = resolve_conflicts(tt)
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
3685
        # We fallback to the default policy which create a conflict
3686
        self.assertLength(1, remaining_conflicts)
3687
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
3688
                         remaining_conflicts.pop())
3689
        self.assertLength(1, warnings)
3690
        self.assertStartsWith(warnings[0], 'donttouchmypreciouuus')