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