/brz/remove-bazaar

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