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