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