~bzr-pqm/bzr/bzr.dev

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
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
2065
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2066
class TestCommitTransform(tests.TestCaseWithTransport):
2067
2068
    def get_branch(self):
2069
        tree = self.make_branch_and_tree('tree')
2070
        tree.lock_write()
2071
        self.addCleanup(tree.unlock)
2072
        tree.commit('empty commit')
2073
        return tree.branch
2074
2075
    def get_branch_and_transform(self):
2076
        branch = self.get_branch()
2077
        tt = TransformPreview(branch.basis_tree())
2078
        self.addCleanup(tt.finalize)
2079
        return branch, tt
2080
2081
    def test_commit_wrong_basis(self):
2082
        branch = self.get_branch()
2083
        basis = branch.repository.revision_tree(
2084
            _mod_revision.NULL_REVISION)
2085
        tt = TransformPreview(basis)
2086
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
2087
        e = self.assertRaises(ValueError, tt.commit, branch, '')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2088
        self.assertEqual('TreeTransform not based on branch basis: null:',
2089
                         str(e))
2090
2091
    def test_empy_commit(self):
2092
        branch, tt = self.get_branch_and_transform()
2093
        rev = tt.commit(branch, 'my message')
2094
        self.assertEqual(2, branch.revno())
2095
        repo = branch.repository
2096
        self.assertEqual('my message', repo.get_revision(rev).message)
2097
2098
    def test_merge_parents(self):
2099
        branch, tt = self.get_branch_and_transform()
2100
        rev = tt.commit(branch, 'my message', ['rev1b', 'rev1c'])
2101
        self.assertEqual(['rev1b', 'rev1c'],
2102
                         branch.basis_tree().get_parent_ids()[1:])
2103
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2104
    def test_first_commit(self):
2105
        branch = self.make_branch('branch')
2106
        branch.lock_write()
2107
        self.addCleanup(branch.unlock)
2108
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2109
        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.
2110
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2111
        rev = tt.commit(branch, 'my message')
2112
        self.assertEqual([], branch.basis_tree().get_parent_ids())
4526.8.5 by Aaron Bentley
Updates from review.
2113
        self.assertNotEqual(_mod_revision.NULL_REVISION,
2114
                            branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2115
4526.8.5 by Aaron Bentley
Updates from review.
2116
    def test_first_commit_with_merge_parents(self):
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2117
        branch = self.make_branch('branch')
2118
        branch.lock_write()
2119
        self.addCleanup(branch.unlock)
2120
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2121
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
2122
        e = self.assertRaises(ValueError, tt.commit, branch,
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2123
                          'my message', ['rev1b-id'])
4526.8.5 by Aaron Bentley
Updates from review.
2124
        self.assertEqual('Cannot supply merge parents for first commit.',
2125
                         str(e))
2126
        self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2127
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2128
    def test_add_files(self):
2129
        branch, tt = self.get_branch_and_transform()
2130
        tt.new_file('file', tt.root, 'contents', 'file-id')
2131
        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
2132
        if SymlinkFeature.available():
2133
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2134
        rev = tt.commit(branch, 'message')
2135
        tree = branch.basis_tree()
2136
        self.assertEqual('file', tree.id2path('file-id'))
2137
        self.assertEqual('contents', tree.get_file_text('file-id'))
2138
        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
2139
        if SymlinkFeature.available():
2140
            self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
2141
            self.assertEqual('target', tree.get_symlink_target('symlink-id'))
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2142
4526.8.2 by Aaron Bentley
Proved strict commit handling.
2143
    def test_add_unversioned(self):
2144
        branch, tt = self.get_branch_and_transform()
2145
        tt.new_file('file', tt.root, 'contents')
2146
        self.assertRaises(errors.StrictCommitFailed, tt.commit, branch,
2147
                          'message', strict=True)
2148
2149
    def test_modify_strict(self):
2150
        branch, tt = self.get_branch_and_transform()
2151
        tt.new_file('file', tt.root, 'contents', 'file-id')
2152
        tt.commit(branch, 'message', strict=True)
2153
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2154
        self.addCleanup(tt.finalize)
4526.8.2 by Aaron Bentley
Proved strict commit handling.
2155
        trans_id = tt.trans_id_file_id('file-id')
2156
        tt.delete_contents(trans_id)
2157
        tt.create_file('contents', trans_id)
2158
        tt.commit(branch, 'message', strict=True)
2159
4526.8.6 by Aaron Bentley
Check for malformed transforms before committing.
2160
    def test_commit_malformed(self):
2161
        """Committing a malformed transform should raise an exception.
2162
2163
        In this case, we are adding a file without adding its parent.
2164
        """
2165
        branch, tt = self.get_branch_and_transform()
2166
        parent_id = tt.trans_id_file_id('parent-id')
2167
        tt.new_file('file', parent_id, 'contents', 'file-id')
2168
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
2169
                          'message')
2170
5162.4.1 by Aaron Bentley
TreeTransform supports normal commit parameters and includes branch nick.
2171
    def test_commit_rich_revision_data(self):
2172
        branch, tt = self.get_branch_and_transform()
5162.4.3 by Aaron Bentley
Fix failing test.
2173
        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.
2174
                           committer='me <me@example.com>',
2175
                           revprops={'foo': 'bar'}, revision_id='revid-1',
2176
                           authors=['Author1 <author1@example.com>',
2177
                              'Author2 <author2@example.com>',
2178
                               ])
2179
        self.assertEqual('revid-1', rev_id)
2180
        revision = branch.repository.get_revision(rev_id)
2181
        self.assertEqual(1, revision.timestamp)
5162.4.3 by Aaron Bentley
Fix failing test.
2182
        self.assertEqual(43201, revision.timezone)
5162.4.1 by Aaron Bentley
TreeTransform supports normal commit parameters and includes branch nick.
2183
        self.assertEqual('me <me@example.com>', revision.committer)
2184
        self.assertEqual(['Author1 <author1@example.com>',
2185
                          'Author2 <author2@example.com>'],
2186
                         revision.get_apparent_authors())
2187
        del revision.properties['authors']
2188
        self.assertEqual({'foo': 'bar',
2189
                          'branch-nick': 'tree'},
2190
                         revision.properties)
2191
2192
    def test_no_explicit_revprops(self):
2193
        branch, tt = self.get_branch_and_transform()
2194
        rev_id = tt.commit(branch, 'message', authors=[
2195
            'Author1 <author1@example.com>',
2196
            'Author2 <author2@example.com>', ])
2197
        revision = branch.repository.get_revision(rev_id)
2198
        self.assertEqual(['Author1 <author1@example.com>',
2199
                          'Author2 <author2@example.com>'],
2200
                         revision.get_apparent_authors())
2201
        self.assertEqual('tree', revision.properties['branch-nick'])
2202
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2203
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
2204
class TestBackupName(tests.TestCase):
2205
2206
    def test_deprecations(self):
2207
        class MockTransform(object):
2208
2209
            def has_named_child(self, by_parent, parent_id, name):
2210
                return name in by_parent.get(parent_id, [])
2211
2212
        class MockEntry(object):
2213
2214
            def __init__(self):
2215
                object.__init__(self)
2216
                self.name = "name"
2217
1534.10.28 by Aaron Bentley
Use numbered backup files
2218
        tt = MockTransform()
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
2219
        name1 = self.applyDeprecated(
5409.8.4 by Vincent Ladeuil
Fix indentations.
2220
            symbol_versioning.deprecated_in((2, 3, 0)),
2221
            transform.get_backup_name, MockEntry(), {'a':[]}, 'a', tt)
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
2222
        self.assertEqual('name.~1~', name1)
2223
        name2 = self.applyDeprecated(
5409.8.4 by Vincent Ladeuil
Fix indentations.
2224
            symbol_versioning.deprecated_in((2, 3, 0)),
2225
            transform._get_backup_name, 'name', {'a':['name.~1~']}, 'a', tt)
5409.1.11 by Vincent Ladeuil
Slightly cleanup bzrlib.transform and deprecate unused code.
2226
        self.assertEqual('name.~2~', name2)
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2227
2228
2229
class TestFileMover(tests.TestCaseWithTransport):
2230
2231
    def test_file_mover(self):
2232
        self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
2233
        mover = _FileMover()
2234
        mover.rename('a', 'q')
2235
        self.failUnlessExists('q')
2236
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2237
        self.failUnlessExists('q/b')
2238
        self.failUnlessExists('c')
2239
        self.failUnlessExists('c/d')
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2240
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2241
    def test_pre_delete_rollback(self):
2242
        self.build_tree(['a/'])
2243
        mover = _FileMover()
2244
        mover.pre_delete('a', 'q')
2245
        self.failUnlessExists('q')
2246
        self.failIfExists('a')
2247
        mover.rollback()
2248
        self.failIfExists('q')
2249
        self.failUnlessExists('a')
2250
2251
    def test_apply_deletions(self):
2733.2.12 by Aaron Bentley
Updates from review
2252
        self.build_tree(['a/', 'b/'])
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2253
        mover = _FileMover()
2254
        mover.pre_delete('a', 'q')
2733.2.12 by Aaron Bentley
Updates from review
2255
        mover.pre_delete('b', 'r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2256
        self.failUnlessExists('q')
2733.2.12 by Aaron Bentley
Updates from review
2257
        self.failUnlessExists('r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2258
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2259
        self.failIfExists('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2260
        mover.apply_deletions()
2261
        self.failIfExists('q')
2733.2.12 by Aaron Bentley
Updates from review
2262
        self.failIfExists('r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2263
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2264
        self.failIfExists('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2265
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2266
    def test_file_mover_rollback(self):
2267
        self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
2268
        mover = _FileMover()
2269
        mover.rename('c/d', 'c/f')
2270
        mover.rename('c/e', 'c/d')
2271
        try:
2272
            mover.rename('a', 'c')
3063.1.3 by Aaron Bentley
Update for Linux
2273
        except errors.FileExists, e:
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2274
            mover.rollback()
2275
        self.failUnlessExists('a')
2276
        self.failUnlessExists('c/d')
2733.2.3 by Aaron Bentley
Test tranform rollback
2277
2278
2279
class Bogus(Exception):
2280
    pass
2281
2282
2283
class TestTransformRollback(tests.TestCaseWithTransport):
2284
2285
    class ExceptionFileMover(_FileMover):
2286
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2287
        def __init__(self, bad_source=None, bad_target=None):
2288
            _FileMover.__init__(self)
2289
            self.bad_source = bad_source
2290
            self.bad_target = bad_target
2291
2733.2.3 by Aaron Bentley
Test tranform rollback
2292
        def rename(self, source, target):
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2293
            if (self.bad_source is not None and
2294
                source.endswith(self.bad_source)):
2295
                raise Bogus
2296
            elif (self.bad_target is not None and
2297
                target.endswith(self.bad_target)):
2733.2.3 by Aaron Bentley
Test tranform rollback
2298
                raise Bogus
2299
            else:
2300
                _FileMover.rename(self, source, target)
2301
2302
    def test_rollback_rename(self):
2303
        tree = self.make_branch_and_tree('.')
2304
        self.build_tree(['a/', 'a/b'])
2305
        tt = TreeTransform(tree)
2306
        self.addCleanup(tt.finalize)
2307
        a_id = tt.trans_id_tree_path('a')
2308
        tt.adjust_path('c', tt.root, a_id)
2309
        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
2310
        self.assertRaises(Bogus, tt.apply,
2311
                          _mover=self.ExceptionFileMover(bad_source='a'))
2312
        self.failUnlessExists('a')
2313
        self.failUnlessExists('a/b')
2314
        tt.apply()
2315
        self.failUnlessExists('c')
2316
        self.failUnlessExists('c/d')
2317
2318
    def test_rollback_rename_into_place(self):
2319
        tree = self.make_branch_and_tree('.')
2320
        self.build_tree(['a/', 'a/b'])
2321
        tt = TreeTransform(tree)
2322
        self.addCleanup(tt.finalize)
2323
        a_id = tt.trans_id_tree_path('a')
2324
        tt.adjust_path('c', tt.root, a_id)
2325
        tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
2326
        self.assertRaises(Bogus, tt.apply,
2327
                          _mover=self.ExceptionFileMover(bad_target='c/d'))
2328
        self.failUnlessExists('a')
2329
        self.failUnlessExists('a/b')
2330
        tt.apply()
2331
        self.failUnlessExists('c')
2332
        self.failUnlessExists('c/d')
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
2333
2334
    def test_rollback_deletion(self):
2335
        tree = self.make_branch_and_tree('.')
2336
        self.build_tree(['a/', 'a/b'])
2337
        tt = TreeTransform(tree)
2338
        self.addCleanup(tt.finalize)
2339
        a_id = tt.trans_id_tree_path('a')
2340
        tt.delete_contents(a_id)
2341
        tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
2342
        self.assertRaises(Bogus, tt.apply,
2343
                          _mover=self.ExceptionFileMover(bad_target='d'))
2344
        self.failUnlessExists('a')
2345
        self.failUnlessExists('a/b')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2346
2347
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2348
class TestTransformMissingParent(tests.TestCaseWithTransport):
2349
5409.7.4 by Vincent Ladeuil
Take jam's review comments into account.
2350
    def make_tt_with_versioned_dir(self):
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2351
        wt = self.make_branch_and_tree('.')
2352
        self.build_tree(['dir/',])
2353
        wt.add(['dir'], ['dir-id'])
2354
        wt.commit('Create dir')
2355
        tt = TreeTransform(wt)
2356
        self.addCleanup(tt.finalize)
2357
        return wt, tt
2358
2359
    def test_resolve_create_parent_for_versioned_file(self):
5409.7.4 by Vincent Ladeuil
Take jam's review comments into account.
2360
        wt, tt = self.make_tt_with_versioned_dir()
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2361
        dir_tid = tt.trans_id_tree_file_id('dir-id')
2362
        file_tid = tt.new_file('file', dir_tid, 'Contents', file_id='file-id')
2363
        tt.delete_contents(dir_tid)
2364
        tt.unversion_file(dir_tid)
2365
        conflicts = resolve_conflicts(tt)
2366
        # one conflict for the missing directory, one for the unversioned
2367
        # parent
2368
        self.assertLength(2, conflicts)
2369
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
2370
    def test_non_versioned_file_create_conflict(self):
5409.7.4 by Vincent Ladeuil
Take jam's review comments into account.
2371
        wt, tt = self.make_tt_with_versioned_dir()
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2372
        dir_tid = tt.trans_id_tree_file_id('dir-id')
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
2373
        tt.new_file('file', dir_tid, 'Contents')
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2374
        tt.delete_contents(dir_tid)
2375
        tt.unversion_file(dir_tid)
2376
        conflicts = resolve_conflicts(tt)
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
2377
        # 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.
2378
        self.assertLength(1, conflicts)
2379
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
2380
                         conflicts.pop())
5409.1.6 by Vincent Ladeuil
Add failing tests for bug #323111.
2381
2382
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2383
A_ENTRY = ('a-id', ('a', 'a'), True, (True, True),
2384
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2385
                  (False, False))
2386
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.
2387
              ('', ''), ('directory', 'directory'), (False, False))
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2388
2389
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2390
class TestTransformPreview(tests.TestCaseWithTransport):
2391
2392
    def create_tree(self):
2393
        tree = self.make_branch_and_tree('.')
2394
        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.
2395
        tree.set_root_id('TREE_ROOT')
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2396
        tree.add('a', 'a-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2397
        tree.commit('rev1', rev_id='rev1')
2398
        return tree.branch.repository.revision_tree('rev1')
2399
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2400
    def get_empty_preview(self):
2401
        repository = self.make_repository('repo')
2402
        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
2403
        preview = TransformPreview(tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2404
        self.addCleanup(preview.finalize)
3199.1.4 by Vincent Ladeuil
Fix 16 leaked tmp dirs. Probably indicates a lock handling problem with TransformPreview
2405
        return preview
2406
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2407
    def test_transform_preview(self):
2408
        revision_tree = self.create_tree()
2409
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2410
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2411
2412
    def test_transform_preview_tree(self):
2413
        revision_tree = self.create_tree()
2414
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2415
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2416
        preview.get_preview_tree()
2417
3008.1.5 by Michael Hudson
a more precise test
2418
    def test_transform_new_file(self):
2419
        revision_tree = self.create_tree()
2420
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2421
        self.addCleanup(preview.finalize)
3008.1.5 by Michael Hudson
a more precise test
2422
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2423
        preview_tree = preview.get_preview_tree()
2424
        self.assertEqual(preview_tree.kind('file2-id'), 'file')
2425
        self.assertEqual(
2426
            preview_tree.get_file('file2-id').read(), 'content B\n')
2427
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2428
    def test_diff_preview_tree(self):
2429
        revision_tree = self.create_tree()
2430
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2431
        self.addCleanup(preview.finalize)
3008.1.4 by Michael Hudson
Merge test enhancements
2432
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2433
        preview_tree = preview.get_preview_tree()
2434
        out = StringIO()
2435
        show_diff_trees(revision_tree, preview_tree, out)
3008.1.4 by Michael Hudson
Merge test enhancements
2436
        lines = out.getvalue().splitlines()
2437
        self.assertEqual(lines[0], "=== added file 'file2'")
2438
        # 3 lines of diff administrivia
2439
        self.assertEqual(lines[4], "+content B")
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2440
2441
    def test_transform_conflicts(self):
2442
        revision_tree = self.create_tree()
2443
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2444
        self.addCleanup(preview.finalize)
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2445
        preview.new_file('a', preview.root, 'content 2')
2446
        resolve_conflicts(preview)
2447
        trans_id = preview.trans_id_file_id('a-id')
2448
        self.assertEqual('a.moved', preview.final_name(trans_id))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2449
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2450
    def get_tree_and_preview_tree(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2451
        revision_tree = self.create_tree()
2452
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2453
        self.addCleanup(preview.finalize)
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2454
        a_trans_id = preview.trans_id_file_id('a-id')
2455
        preview.delete_contents(a_trans_id)
2456
        preview.create_file('b content', a_trans_id)
2457
        preview_tree = preview.get_preview_tree()
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2458
        return revision_tree, preview_tree
2459
2460
    def test_iter_changes(self):
2461
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2462
        root = revision_tree.inventory.root.file_id
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2463
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
2464
                          (root, root), ('a', 'a'), ('file', 'file'),
2465
                          (False, False))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2466
                          list(preview_tree.iter_changes(revision_tree)))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2467
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2468
    def test_include_unchanged_succeeds(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2469
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2470
        changes = preview_tree.iter_changes(revision_tree,
2471
                                            include_unchanged=True)
2472
        root = revision_tree.inventory.root.file_id
2473
2474
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2475
2476
    def test_specific_files(self):
2477
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2478
        changes = preview_tree.iter_changes(revision_tree,
2479
                                            specific_files=[''])
5050.57.1 by Aaron Bentley
Make is_executable treat symlinks and directories the same across tree types.
2480
        self.assertEqual([A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2481
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2482
    def test_want_unversioned(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2483
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2484
        changes = preview_tree.iter_changes(revision_tree,
2485
                                            want_unversioned=True)
5050.57.1 by Aaron Bentley
Make is_executable treat symlinks and directories the same across tree types.
2486
        self.assertEqual([A_ENTRY], list(changes))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2487
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2488
    def test_ignore_extra_trees_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2489
        # extra_trees is harmless without specific_files, so we'll silently
2490
        # accept it, even though we won't use it.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2491
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2492
        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
2493
2494
    def test_ignore_require_versioned_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2495
        # require_versioned is meaningless without specific_files.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2496
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2497
        preview_tree.iter_changes(revision_tree, require_versioned=False)
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2498
2499
    def test_ignore_pb(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2500
        # 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
2501
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2502
        preview_tree.iter_changes(revision_tree)
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2503
2504
    def test_kind(self):
2505
        revision_tree = self.create_tree()
2506
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2507
        self.addCleanup(preview.finalize)
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2508
        preview.new_file('file', preview.root, 'contents', 'file-id')
2509
        preview.new_directory('directory', preview.root, 'dir-id')
2510
        preview_tree = preview.get_preview_tree()
2511
        self.assertEqual('file', preview_tree.kind('file-id'))
2512
        self.assertEqual('directory', preview_tree.kind('dir-id'))
2513
2514
    def test_get_file_mtime(self):
2515
        preview = self.get_empty_preview()
2516
        file_trans_id = preview.new_file('file', preview.root, 'contents',
2517
                                         'file-id')
2518
        limbo_path = preview._limbo_name(file_trans_id)
2519
        preview_tree = preview.get_preview_tree()
2520
        self.assertEqual(os.stat(limbo_path).st_mtime,
2521
                         preview_tree.get_file_mtime('file-id'))
2522
4635.1.1 by Aaron Bentley
Fix OSError with renamed files in PreviewTree.
2523
    def test_get_file_mtime_renamed(self):
2524
        work_tree = self.make_branch_and_tree('tree')
2525
        self.build_tree(['tree/file'])
2526
        work_tree.add('file', 'file-id')
2527
        preview = TransformPreview(work_tree)
2528
        self.addCleanup(preview.finalize)
2529
        file_trans_id = preview.trans_id_tree_file_id('file-id')
2530
        preview.adjust_path('renamed', preview.root, file_trans_id)
2531
        preview_tree = preview.get_preview_tree()
2532
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
2533
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
2534
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2535
    def test_get_file(self):
2536
        preview = self.get_empty_preview()
2537
        preview.new_file('file', preview.root, 'contents', 'file-id')
2538
        preview_tree = preview.get_preview_tree()
2539
        tree_file = preview_tree.get_file('file-id')
2540
        try:
2541
            self.assertEqual('contents', tree_file.read())
2542
        finally:
2543
            tree_file.close()
3228.1.2 by James Henstridge
Simplify test, and move it down to be next to the other _PreviewTree tests.
2544
2545
    def test_get_symlink_target(self):
2546
        self.requireFeature(SymlinkFeature)
2547
        preview = self.get_empty_preview()
2548
        preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2549
        preview_tree = preview.get_preview_tree()
2550
        self.assertEqual('target',
2551
                         preview_tree.get_symlink_target('symlink-id'))
3363.2.18 by Aaron Bentley
Implement correct all_file_ids for PreviewTree
2552
2553
    def test_all_file_ids(self):
2554
        tree = self.make_branch_and_tree('tree')
2555
        self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2556
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2557
        preview = TransformPreview(tree)
2558
        self.addCleanup(preview.finalize)
2559
        preview.unversion_file(preview.trans_id_file_id('b-id'))
2560
        c_trans_id = preview.trans_id_file_id('c-id')
2561
        preview.unversion_file(c_trans_id)
2562
        preview.version_file('c-id', c_trans_id)
2563
        preview_tree = preview.get_preview_tree()
2564
        self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2565
                         preview_tree.all_file_ids())
3363.2.19 by Aaron Bentley
Make PreviewTree.path2id correct
2566
2567
    def test_path2id_deleted_unchanged(self):
2568
        tree = self.make_branch_and_tree('tree')
2569
        self.build_tree(['tree/unchanged', 'tree/deleted'])
2570
        tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2571
        preview = TransformPreview(tree)
2572
        self.addCleanup(preview.finalize)
2573
        preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2574
        preview_tree = preview.get_preview_tree()
2575
        self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2576
        self.assertIs(None, preview_tree.path2id('deleted'))
2577
2578
    def test_path2id_created(self):
2579
        tree = self.make_branch_and_tree('tree')
2580
        self.build_tree(['tree/unchanged'])
2581
        tree.add(['unchanged'], ['unchanged-id'])
2582
        preview = TransformPreview(tree)
2583
        self.addCleanup(preview.finalize)
2584
        preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2585
            'contents', 'new-id')
2586
        preview_tree = preview.get_preview_tree()
2587
        self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2588
2589
    def test_path2id_moved(self):
2590
        tree = self.make_branch_and_tree('tree')
2591
        self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2592
        tree.add(['old_parent', 'old_parent/child'],
2593
                 ['old_parent-id', 'child-id'])
2594
        preview = TransformPreview(tree)
2595
        self.addCleanup(preview.finalize)
2596
        new_parent = preview.new_directory('new_parent', preview.root,
2597
                                           'new_parent-id')
2598
        preview.adjust_path('child', new_parent,
2599
                            preview.trans_id_file_id('child-id'))
2600
        preview_tree = preview.get_preview_tree()
2601
        self.assertIs(None, preview_tree.path2id('old_parent/child'))
2602
        self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2603
2604
    def test_path2id_renamed_parent(self):
2605
        tree = self.make_branch_and_tree('tree')
2606
        self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2607
        tree.add(['old_name', 'old_name/child'],
2608
                 ['parent-id', 'child-id'])
2609
        preview = TransformPreview(tree)
2610
        self.addCleanup(preview.finalize)
2611
        preview.adjust_path('new_name', preview.root,
2612
                            preview.trans_id_file_id('parent-id'))
2613
        preview_tree = preview.get_preview_tree()
2614
        self.assertIs(None, preview_tree.path2id('old_name/child'))
2615
        self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
3363.2.21 by Aaron Bentley
Implement iter_entries_by_dir
2616
2617
    def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2618
        preview_tree = tt.get_preview_tree()
2619
        preview_result = list(preview_tree.iter_entries_by_dir(
2620
                              specific_file_ids))
2621
        tree = tt._tree
2622
        tt.apply()
2623
        actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2624
        self.assertEqual(actual_result, preview_result)
2625
2626
    def test_iter_entries_by_dir_new(self):
2627
        tree = self.make_branch_and_tree('tree')
2628
        tt = TreeTransform(tree)
2629
        tt.new_file('new', tt.root, 'contents', 'new-id')
2630
        self.assertMatchingIterEntries(tt)
2631
2632
    def test_iter_entries_by_dir_deleted(self):
2633
        tree = self.make_branch_and_tree('tree')
2634
        self.build_tree(['tree/deleted'])
2635
        tree.add('deleted', 'deleted-id')
2636
        tt = TreeTransform(tree)
2637
        tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2638
        self.assertMatchingIterEntries(tt)
2639
2640
    def test_iter_entries_by_dir_unversioned(self):
2641
        tree = self.make_branch_and_tree('tree')
2642
        self.build_tree(['tree/removed'])
2643
        tree.add('removed', 'removed-id')
2644
        tt = TreeTransform(tree)
2645
        tt.unversion_file(tt.trans_id_file_id('removed-id'))
2646
        self.assertMatchingIterEntries(tt)
2647
2648
    def test_iter_entries_by_dir_moved(self):
2649
        tree = self.make_branch_and_tree('tree')
2650
        self.build_tree(['tree/moved', 'tree/new_parent/'])
2651
        tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2652
        tt = TreeTransform(tree)
2653
        tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2654
                       tt.trans_id_file_id('moved-id'))
2655
        self.assertMatchingIterEntries(tt)
2656
2657
    def test_iter_entries_by_dir_specific_file_ids(self):
2658
        tree = self.make_branch_and_tree('tree')
2659
        tree.set_root_id('tree-root-id')
2660
        self.build_tree(['tree/parent/', 'tree/parent/child'])
2661
        tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2662
        tt = TreeTransform(tree)
2663
        self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
3363.2.26 by Aaron Bentley
Get symlinks working
2664
2665
    def test_symlink_content_summary(self):
2666
        self.requireFeature(SymlinkFeature)
2667
        preview = self.get_empty_preview()
2668
        preview.new_symlink('path', preview.root, 'target', 'path-id')
2669
        summary = preview.get_preview_tree().path_content_summary('path')
2670
        self.assertEqual(('symlink', None, None, 'target'), summary)
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2671
2672
    def test_missing_content_summary(self):
2673
        preview = self.get_empty_preview()
2674
        summary = preview.get_preview_tree().path_content_summary('path')
2675
        self.assertEqual(('missing', None, None, None), summary)
2676
2677
    def test_deleted_content_summary(self):
2678
        tree = self.make_branch_and_tree('tree')
2679
        self.build_tree(['tree/path/'])
2680
        tree.add('path')
2681
        preview = TransformPreview(tree)
2682
        self.addCleanup(preview.finalize)
2683
        preview.delete_contents(preview.trans_id_tree_path('path'))
2684
        summary = preview.get_preview_tree().path_content_summary('path')
2685
        self.assertEqual(('missing', None, None, None), summary)
2686
3363.2.30 by Aaron Bentley
Improve execute bit testing
2687
    def test_file_content_summary_executable(self):
2688
        preview = self.get_empty_preview()
2689
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2690
        preview.set_executability(True, path_id)
2691
        summary = preview.get_preview_tree().path_content_summary('path')
2692
        self.assertEqual(4, len(summary))
2693
        self.assertEqual('file', summary[0])
2694
        # size must be known
2695
        self.assertEqual(len('contents'), summary[1])
2696
        # executable
2697
        self.assertEqual(True, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
2698
        # will not have hash (not cheap to determine)
2699
        self.assertIs(None, summary[3])
3363.2.30 by Aaron Bentley
Improve execute bit testing
2700
2701
    def test_change_executability(self):
2702
        tree = self.make_branch_and_tree('tree')
2703
        self.build_tree(['tree/path'])
2704
        tree.add('path')
2705
        preview = TransformPreview(tree)
2706
        self.addCleanup(preview.finalize)
2707
        path_id = preview.trans_id_tree_path('path')
2708
        preview.set_executability(True, path_id)
2709
        summary = preview.get_preview_tree().path_content_summary('path')
2710
        self.assertEqual(True, summary[2])
2711
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2712
    def test_file_content_summary_non_exec(self):
2713
        preview = self.get_empty_preview()
2714
        preview.new_file('path', preview.root, 'contents', 'path-id')
2715
        summary = preview.get_preview_tree().path_content_summary('path')
2716
        self.assertEqual(4, len(summary))
2717
        self.assertEqual('file', summary[0])
2718
        # size must be known
3363.2.30 by Aaron Bentley
Improve execute bit testing
2719
        self.assertEqual(len('contents'), summary[1])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2720
        # not executable
4789.15.3 by John Arbash Meinel
PreviewTree now returns False for exec bit properly.
2721
        self.assertEqual(False, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
2722
        # will not have hash (not cheap to determine)
2723
        self.assertIs(None, summary[3])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2724
2725
    def test_dir_content_summary(self):
2726
        preview = self.get_empty_preview()
2727
        preview.new_directory('path', preview.root, 'path-id')
2728
        summary = preview.get_preview_tree().path_content_summary('path')
2729
        self.assertEqual(('directory', None, None, None), summary)
2730
2731
    def test_tree_content_summary(self):
2732
        preview = self.get_empty_preview()
2733
        path = preview.new_directory('path', preview.root, 'path-id')
2734
        preview.set_tree_reference('rev-1', path)
2735
        summary = preview.get_preview_tree().path_content_summary('path')
2736
        self.assertEqual(4, len(summary))
2737
        self.assertEqual('tree-reference', summary[0])
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
2738
2739
    def test_annotate(self):
2740
        tree = self.make_branch_and_tree('tree')
2741
        self.build_tree_contents([('tree/file', 'a\n')])
2742
        tree.add('file', 'file-id')
2743
        tree.commit('a', rev_id='one')
2744
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2745
        preview = TransformPreview(tree)
2746
        self.addCleanup(preview.finalize)
2747
        file_trans_id = preview.trans_id_file_id('file-id')
2748
        preview.delete_contents(file_trans_id)
2749
        preview.create_file('a\nb\nc\n', file_trans_id)
2750
        preview_tree = preview.get_preview_tree()
2751
        expected = [
2752
            ('one', 'a\n'),
2753
            ('me:', 'b\n'),
2754
            ('me:', 'c\n'),
2755
        ]
2756
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2757
        self.assertEqual(expected, annotation)
2758
2759
    def test_annotate_missing(self):
2760
        preview = self.get_empty_preview()
2761
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2762
        preview_tree = preview.get_preview_tree()
2763
        expected = [
2764
            ('me:', 'a\n'),
2765
            ('me:', 'b\n'),
2766
            ('me:', 'c\n'),
2767
         ]
2768
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2769
        self.assertEqual(expected, annotation)
2770
3363.7.3 by Aaron Bentley
Add test that annotate correctly handles renames
2771
    def test_annotate_rename(self):
2772
        tree = self.make_branch_and_tree('tree')
2773
        self.build_tree_contents([('tree/file', 'a\n')])
2774
        tree.add('file', 'file-id')
2775
        tree.commit('a', rev_id='one')
2776
        preview = TransformPreview(tree)
2777
        self.addCleanup(preview.finalize)
2778
        file_trans_id = preview.trans_id_file_id('file-id')
2779
        preview.adjust_path('newname', preview.root, file_trans_id)
2780
        preview_tree = preview.get_preview_tree()
2781
        expected = [
2782
            ('one', 'a\n'),
2783
        ]
2784
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2785
        self.assertEqual(expected, annotation)
2786
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
2787
    def test_annotate_deleted(self):
2788
        tree = self.make_branch_and_tree('tree')
2789
        self.build_tree_contents([('tree/file', 'a\n')])
2790
        tree.add('file', 'file-id')
2791
        tree.commit('a', rev_id='one')
2792
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2793
        preview = TransformPreview(tree)
2794
        self.addCleanup(preview.finalize)
2795
        file_trans_id = preview.trans_id_file_id('file-id')
2796
        preview.delete_contents(file_trans_id)
2797
        preview_tree = preview.get_preview_tree()
2798
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2799
        self.assertIs(None, annotation)
2800
3363.2.36 by Aaron Bentley
Fix PreviewTree.stored_kind
2801
    def test_stored_kind(self):
2802
        preview = self.get_empty_preview()
2803
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2804
        preview_tree = preview.get_preview_tree()
2805
        self.assertEqual('file', preview_tree.stored_kind('file-id'))
3363.2.37 by Aaron Bentley
Fix is_executable
2806
2807
    def test_is_executable(self):
2808
        preview = self.get_empty_preview()
2809
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2810
        preview.set_executability(True, preview.trans_id_file_id('file-id'))
2811
        preview_tree = preview.get_preview_tree()
2812
        self.assertEqual(True, preview_tree.is_executable('file-id'))
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2813
3571.1.1 by Aaron Bentley
Allow set/get of parent_ids in PreviewTree
2814
    def test_get_set_parent_ids(self):
2815
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2816
        self.assertEqual([], preview_tree.get_parent_ids())
2817
        preview_tree.set_parent_ids(['rev-1'])
2818
        self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
2819
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2820
    def test_plan_file_merge(self):
2821
        work_a = self.make_branch_and_tree('wta')
2822
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2823
        work_a.add('file', 'file-id')
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
2824
        base_id = work_a.commit('base version')
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2825
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2826
        preview = TransformPreview(work_a)
2827
        self.addCleanup(preview.finalize)
2828
        trans_id = preview.trans_id_file_id('file-id')
2829
        preview.delete_contents(trans_id)
2830
        preview.create_file('b\nc\nd\ne\n', trans_id)
2831
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2832
        tree_a = preview.get_preview_tree()
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
2833
        tree_a.set_parent_ids([base_id])
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2834
        self.assertEqual([
3363.9.5 by Aaron Bentley
Move killed-a from top to bottom
2835
            ('killed-a', 'a\n'),
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2836
            ('killed-b', 'b\n'),
2837
            ('unchanged', 'c\n'),
2838
            ('unchanged', 'd\n'),
2839
            ('new-a', 'e\n'),
2840
            ('new-b', 'f\n'),
2841
        ], 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
2842
2843
    def test_plan_file_merge_revision_tree(self):
2844
        work_a = self.make_branch_and_tree('wta')
2845
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2846
        work_a.add('file', 'file-id')
2847
        base_id = work_a.commit('base version')
2848
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2849
        preview = TransformPreview(work_a.basis_tree())
2850
        self.addCleanup(preview.finalize)
2851
        trans_id = preview.trans_id_file_id('file-id')
2852
        preview.delete_contents(trans_id)
2853
        preview.create_file('b\nc\nd\ne\n', trans_id)
2854
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2855
        tree_a = preview.get_preview_tree()
2856
        tree_a.set_parent_ids([base_id])
2857
        self.assertEqual([
2858
            ('killed-a', 'a\n'),
2859
            ('killed-b', 'b\n'),
2860
            ('unchanged', 'c\n'),
2861
            ('unchanged', 'd\n'),
2862
            ('new-a', 'e\n'),
2863
            ('new-b', 'f\n'),
2864
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
2865
2866
    def test_walkdirs(self):
2867
        preview = self.get_empty_preview()
4634.57.3 by Aaron Bentley
Fix failing test.
2868
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
2869
        # FIXME: new_directory should mark root.
4634.122.6 by John Arbash Meinel
Fix a test that used 'adjust_path' to set the root.
2870
        preview.fixup_new_roots()
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
2871
        preview_tree = preview.get_preview_tree()
2872
        file_trans_id = preview.new_file('a', preview.root, 'contents',
2873
                                         'a-id')
2874
        expected = [(('', 'tree-root'),
2875
                    [('a', 'a', 'file', None, 'a-id', 'file')])]
2876
        self.assertEqual(expected, list(preview_tree.walkdirs()))
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
2877
2878
    def test_extras(self):
2879
        work_tree = self.make_branch_and_tree('tree')
2880
        self.build_tree(['tree/removed-file', 'tree/existing-file',
2881
                         'tree/not-removed-file'])
2882
        work_tree.add(['removed-file', 'not-removed-file'])
2883
        preview = TransformPreview(work_tree)
3363.13.3 by Aaron Bentley
Add cleanup
2884
        self.addCleanup(preview.finalize)
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
2885
        preview.new_file('new-file', preview.root, 'contents')
2886
        preview.new_file('new-versioned-file', preview.root, 'contents',
2887
                         'new-versioned-id')
2888
        tree = preview.get_preview_tree()
2889
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
2890
        self.assertEqual(set(['new-file', 'removed-file', 'existing-file']),
2891
                         set(tree.extras()))
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2892
3363.17.2 by Aaron Bentley
Add text checking
2893
    def test_merge_into_preview(self):
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2894
        work_tree = self.make_branch_and_tree('tree')
3363.17.2 by Aaron Bentley
Add text checking
2895
        self.build_tree_contents([('tree/file','b\n')])
2896
        work_tree.add('file', 'file-id')
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2897
        work_tree.commit('first commit')
2898
        child_tree = work_tree.bzrdir.sprout('child').open_workingtree()
3363.17.2 by Aaron Bentley
Add text checking
2899
        self.build_tree_contents([('child/file','b\nc\n')])
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2900
        child_tree.commit('child commit')
2901
        child_tree.lock_write()
2902
        self.addCleanup(child_tree.unlock)
2903
        work_tree.lock_write()
2904
        self.addCleanup(work_tree.unlock)
2905
        preview = TransformPreview(work_tree)
2906
        self.addCleanup(preview.finalize)
3363.17.6 by Aaron Bentley
Improve test scenario
2907
        file_trans_id = preview.trans_id_file_id('file-id')
2908
        preview.delete_contents(file_trans_id)
2909
        preview.create_file('a\nb\n', file_trans_id)
4634.57.2 by Aaron Bentley
Fix failing test.
2910
        preview_tree = preview.get_preview_tree()
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2911
        merger = Merger.from_revision_ids(None, preview_tree,
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2912
                                          child_tree.branch.last_revision(),
2913
                                          other_branch=child_tree.branch,
2914
                                          tree_branch=work_tree.branch)
2915
        merger.merge_type = Merge3Merger
2916
        tt = merger.make_merger().make_preview_transform()
3363.17.2 by Aaron Bentley
Add text checking
2917
        self.addCleanup(tt.finalize)
2918
        final_tree = tt.get_preview_tree()
2919
        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
2920
2921
    def test_merge_preview_into_workingtree(self):
2922
        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.
2923
        tree.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2924
        tt = TransformPreview(tree)
2925
        self.addCleanup(tt.finalize)
2926
        tt.new_file('name', tt.root, 'content', 'file-id')
2927
        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.
2928
        tree2.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2929
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2930
                                         None, tree.basis_tree())
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2931
        merger.merge_type = Merge3Merger
2932
        merger.do_merge()
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
2933
3363.17.21 by Aaron Bentley
Conflicts are handled when merging from preview trees
2934
    def test_merge_preview_into_workingtree_handles_conflicts(self):
2935
        tree = self.make_branch_and_tree('tree')
2936
        self.build_tree_contents([('tree/foo', 'bar')])
2937
        tree.add('foo', 'foo-id')
2938
        tree.commit('foo')
2939
        tt = TransformPreview(tree)
2940
        self.addCleanup(tt.finalize)
2941
        trans_id = tt.trans_id_file_id('foo-id')
2942
        tt.delete_contents(trans_id)
2943
        tt.create_file('baz', trans_id)
2944
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2945
        self.build_tree_contents([('tree2/foo', 'qux')])
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2946
        pb = None
3363.17.21 by Aaron Bentley
Conflicts are handled when merging from preview trees
2947
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2948
                                         pb, tree.basis_tree())
2949
        merger.merge_type = Merge3Merger
2950
        merger.do_merge()
2951
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
2952
    def test_is_executable(self):
2953
        tree = self.make_branch_and_tree('tree')
2954
        preview = TransformPreview(tree)
2955
        self.addCleanup(preview.finalize)
2956
        preview.new_file('foo', preview.root, 'bar', 'baz-id')
2957
        preview_tree = preview.get_preview_tree()
2958
        self.assertEqual(False, preview_tree.is_executable('baz-id',
2959
                                                           'tree/foo'))
2960
        self.assertEqual(False, preview_tree.is_executable('baz-id'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2961
4354.4.4 by Aaron Bentley
Simplify by using CommitBuilder directly
2962
    def test_commit_preview_tree(self):
2963
        tree = self.make_branch_and_tree('tree')
2964
        rev_id = tree.commit('rev1')
2965
        tree.branch.lock_write()
2966
        self.addCleanup(tree.branch.unlock)
2967
        tt = TransformPreview(tree)
2968
        tt.new_file('file', tt.root, 'contents', 'file_id')
2969
        self.addCleanup(tt.finalize)
2970
        preview = tt.get_preview_tree()
2971
        preview.set_parent_ids([rev_id])
2972
        builder = tree.branch.get_commit_builder([rev_id])
2973
        list(builder.record_iter_changes(preview, rev_id, tt.iter_changes()))
2974
        builder.finish_inventory()
2975
        rev2_id = builder.commit('rev2')
2976
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
2977
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
2978
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2979
    def test_ascii_limbo_paths(self):
4634.79.2 by Aaron Bentley
Avoid runing test on non-unicode filesystems.
2980
        self.requireFeature(tests.UnicodeFilenameFeature)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2981
        branch = self.make_branch('any')
2982
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
2983
        tt = TransformPreview(tree)
4789.25.7 by John Arbash Meinel
We can run the executable tests.
2984
        self.addCleanup(tt.finalize)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2985
        foo_id = tt.new_directory('', ROOT_PARENT)
2986
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
2987
        limbo_path = tt._limbo_name(bar_id)
2988
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
2989
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2990
0.13.13 by Aaron Bentley
Add direct test of serialization records
2991
class FakeSerializer(object):
2992
    """Serializer implementation that simply returns the input.
2993
2994
    The input is returned in the order used by pack.ContainerPushParser.
2995
    """
2996
    @staticmethod
2997
    def bytes_record(bytes, names):
2998
        return names, bytes
2999
3000
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3001
class TestSerializeTransform(tests.TestCaseWithTransport):
3002
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
3003
    _test_needs_features = [tests.UnicodeFilenameFeature]
3004
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3005
    def get_preview(self, tree=None):
3006
        if tree is None:
3007
            tree = self.make_branch_and_tree('tree')
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
3008
        tt = TransformPreview(tree)
3009
        self.addCleanup(tt.finalize)
3010
        return tt
3011
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3012
    def assertSerializesTo(self, expected, tt):
3013
        records = list(tt.serialize(FakeSerializer()))
3014
        self.assertEqual(expected, records)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3015
0.13.13 by Aaron Bentley
Add direct test of serialization records
3016
    @staticmethod
3017
    def default_attribs():
3018
        return {
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3019
            '_id_number': 1,
0.13.13 by Aaron Bentley
Add direct test of serialization records
3020
            '_new_name': {},
3021
            '_new_parent': {},
3022
            '_new_executability': {},
3023
            '_new_id': {},
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3024
            '_tree_path_ids': {'': 'new-0'},
0.13.13 by Aaron Bentley
Add direct test of serialization records
3025
            '_removed_id': [],
3026
            '_removed_contents': [],
3027
            '_non_present_ids': {},
3028
            }
3029
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3030
    def make_records(self, attribs, contents):
3031
        records = [
3032
            (((('attribs'),),), bencode.bencode(attribs))]
3033
        records.extend([(((n, k),), c) for n, k, c in contents])
3034
        return records
3035
0.13.13 by Aaron Bentley
Add direct test of serialization records
3036
    def creation_records(self):
3037
        attribs = self.default_attribs()
3038
        attribs['_id_number'] = 3
3039
        attribs['_new_name'] = {
3040
            'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
3041
        attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
3042
        attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
3043
        attribs['_new_executability'] = {'new-1': 1}
3044
        contents = [
3045
            ('new-1', 'file', 'i 1\nbar\n'),
3046
            ('new-2', 'directory', ''),
3047
            ]
3048
        return self.make_records(attribs, contents)
3049
3050
    def test_serialize_creation(self):
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
3051
        tt = self.get_preview()
0.13.13 by Aaron Bentley
Add direct test of serialization records
3052
        tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
3053
        tt.new_directory('qux', tt.root, 'quxx')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
3054
        self.assertSerializesTo(self.creation_records(), tt)
0.13.13 by Aaron Bentley
Add direct test of serialization records
3055
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
3056
    def test_deserialize_creation(self):
3057
        tt = self.get_preview()
3058
        tt.deserialize(iter(self.creation_records()))
3059
        self.assertEqual(3, tt._id_number)
3060
        self.assertEqual({'new-1': u'foo\u1234',
3061
                          'new-2': 'qux'}, tt._new_name)
3062
        self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
3063
        self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
3064
        self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
3065
        self.assertEqual({'new-1': True}, tt._new_executability)
3066
        self.assertEqual({'new-1': 'file',
3067
                          'new-2': 'directory'}, tt._new_contents)
3068
        foo_limbo = open(tt._limbo_name('new-1'), 'rb')
3069
        try:
3070
            foo_content = foo_limbo.read()
3071
        finally:
3072
            foo_limbo.close()
3073
        self.assertEqual('bar', foo_content)
3074
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3075
    def symlink_creation_records(self):
3076
        attribs = self.default_attribs()
3077
        attribs['_id_number'] = 2
3078
        attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
3079
        attribs['_new_parent'] = {'new-1': 'new-0'}
3080
        contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
3081
        return self.make_records(attribs, contents)
3082
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3083
    def test_serialize_symlink_creation(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3084
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3085
        tt = self.get_preview()
0.13.16 by Aaron Bentley
Add unicode symlink targets to tests
3086
        tt.new_symlink(u'foo\u1234', tt.root, u'bar\u1234')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
3087
        self.assertSerializesTo(self.symlink_creation_records(), tt)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3088
3089
    def test_deserialize_symlink_creation(self):
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
3090
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
3091
        tt = self.get_preview()
3092
        tt.deserialize(iter(self.symlink_creation_records()))
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
3093
        abspath = tt._limbo_name('new-1')
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
3094
        foo_content = osutils.readlink(abspath)
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
3095
        self.assertEqual(u'bar\u1234', foo_content)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3096
0.13.19 by Aaron Bentley
Clean up serialization tests
3097
    def make_destruction_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3098
        tree = self.make_branch_and_tree('.')
3099
        self.build_tree([u'foo\u1234', 'bar'])
3100
        tree.add([u'foo\u1234', 'bar'], ['foo-id', 'bar-id'])
0.13.19 by Aaron Bentley
Clean up serialization tests
3101
        return self.get_preview(tree)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3102
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3103
    def destruction_records(self):
3104
        attribs = self.default_attribs()
3105
        attribs['_id_number'] = 3
3106
        attribs['_removed_id'] = ['new-1']
3107
        attribs['_removed_contents'] = ['new-2']
3108
        attribs['_tree_path_ids'] = {
3109
            '': 'new-0',
3110
            u'foo\u1234'.encode('utf-8'): 'new-1',
3111
            'bar': 'new-2',
3112
            }
3113
        return self.make_records(attribs, [])
3114
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3115
    def test_serialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
3116
        tt = self.make_destruction_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3117
        foo_trans_id = tt.trans_id_tree_file_id('foo-id')
3118
        tt.unversion_file(foo_trans_id)
3119
        bar_trans_id = tt.trans_id_tree_file_id('bar-id')
3120
        tt.delete_contents(bar_trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3121
        self.assertSerializesTo(self.destruction_records(), tt)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3122
3123
    def test_deserialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
3124
        tt = self.make_destruction_preview()
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
3125
        tt.deserialize(iter(self.destruction_records()))
3126
        self.assertEqual({u'foo\u1234': 'new-1',
3127
                          'bar': 'new-2',
3128
                          '': tt.root}, tt._tree_path_ids)
3129
        self.assertEqual({'new-1': u'foo\u1234',
3130
                          'new-2': 'bar',
3131
                          tt.root: ''}, tt._tree_id_paths)
3132
        self.assertEqual(set(['new-1']), tt._removed_id)
3133
        self.assertEqual(set(['new-2']), tt._removed_contents)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3134
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3135
    def missing_records(self):
3136
        attribs = self.default_attribs()
3137
        attribs['_id_number'] = 2
3138
        attribs['_non_present_ids'] = {
3139
            'boo': 'new-1',}
3140
        return self.make_records(attribs, [])
3141
3142
    def test_serialize_missing(self):
3143
        tt = self.get_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3144
        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
3145
        self.assertSerializesTo(self.missing_records(), tt)
3146
3147
    def test_deserialize_missing(self):
3148
        tt = self.get_preview()
3149
        tt.deserialize(iter(self.missing_records()))
3150
        self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
3151
3152
    def make_modification_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3153
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3154
        LINES_TWO = 'z\nbb\nx\ndd\n'
3155
        tree = self.make_branch_and_tree('tree')
3156
        self.build_tree_contents([('tree/file', LINES_ONE)])
3157
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3158
        return self.get_preview(tree), LINES_TWO
3159
3160
    def modification_records(self):
3161
        attribs = self.default_attribs()
3162
        attribs['_id_number'] = 2
3163
        attribs['_tree_path_ids'] = {
3164
            'file': 'new-1',
3165
            '': 'new-0',}
3166
        attribs['_removed_contents'] = ['new-1']
3167
        contents = [('new-1', 'file',
3168
                     'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
3169
        return self.make_records(attribs, contents)
3170
3171
    def test_serialize_modification(self):
3172
        tt, LINES = self.make_modification_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3173
        trans_id = tt.trans_id_file_id('file-id')
3174
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3175
        tt.create_file(LINES, trans_id)
3176
        self.assertSerializesTo(self.modification_records(), tt)
3177
3178
    def test_deserialize_modification(self):
3179
        tt, LINES = self.make_modification_preview()
3180
        tt.deserialize(iter(self.modification_records()))
3181
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3182
3183
    def make_kind_change_preview(self):
3184
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3185
        tree = self.make_branch_and_tree('tree')
3186
        self.build_tree(['tree/foo/'])
3187
        tree.add('foo', 'foo-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3188
        return self.get_preview(tree), LINES
3189
3190
    def kind_change_records(self):
3191
        attribs = self.default_attribs()
3192
        attribs['_id_number'] = 2
3193
        attribs['_tree_path_ids'] = {
3194
            'foo': 'new-1',
3195
            '': 'new-0',}
3196
        attribs['_removed_contents'] = ['new-1']
3197
        contents = [('new-1', 'file',
3198
                     'i 4\na\nb\nc\nd\n\n')]
3199
        return self.make_records(attribs, contents)
3200
3201
    def test_serialize_kind_change(self):
3202
        tt, LINES = self.make_kind_change_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3203
        trans_id = tt.trans_id_file_id('foo-id')
3204
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3205
        tt.create_file(LINES, trans_id)
3206
        self.assertSerializesTo(self.kind_change_records(), tt)
3207
3208
    def test_deserialize_kind_change(self):
3209
        tt, LINES = self.make_kind_change_preview()
3210
        tt.deserialize(iter(self.kind_change_records()))
3211
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3212
3213
    def make_add_contents_preview(self):
3214
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3215
        tree = self.make_branch_and_tree('tree')
3216
        self.build_tree(['tree/foo'])
3217
        tree.add('foo')
3218
        os.unlink('tree/foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3219
        return self.get_preview(tree), LINES
3220
3221
    def add_contents_records(self):
3222
        attribs = self.default_attribs()
3223
        attribs['_id_number'] = 2
3224
        attribs['_tree_path_ids'] = {
3225
            'foo': 'new-1',
3226
            '': 'new-0',}
3227
        contents = [('new-1', 'file',
3228
                     'i 4\na\nb\nc\nd\n\n')]
3229
        return self.make_records(attribs, contents)
3230
3231
    def test_serialize_add_contents(self):
3232
        tt, LINES = self.make_add_contents_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3233
        trans_id = tt.trans_id_tree_path('foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3234
        tt.create_file(LINES, trans_id)
3235
        self.assertSerializesTo(self.add_contents_records(), tt)
3236
3237
    def test_deserialize_add_contents(self):
3238
        tt, LINES = self.make_add_contents_preview()
3239
        tt.deserialize(iter(self.add_contents_records()))
3240
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3241
3242
    def test_get_parents_lines(self):
3243
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3244
        LINES_TWO = 'z\nbb\nx\ndd\n'
3245
        tree = self.make_branch_and_tree('tree')
3246
        self.build_tree_contents([('tree/file', LINES_ONE)])
3247
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3248
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3249
        trans_id = tt.trans_id_tree_path('file')
3250
        self.assertEqual((['aa\n', 'bb\n', 'cc\n', 'dd\n'],),
3251
            tt._get_parents_lines(trans_id))
3252
3253
    def test_get_parents_texts(self):
3254
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3255
        LINES_TWO = 'z\nbb\nx\ndd\n'
3256
        tree = self.make_branch_and_tree('tree')
3257
        self.build_tree_contents([('tree/file', LINES_ONE)])
3258
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3259
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3260
        trans_id = tt.trans_id_tree_path('file')
3261
        self.assertEqual((LINES_ONE,),
3262
            tt._get_parents_texts(trans_id))
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
3263
3264
3265
class TestOrphan(tests.TestCaseWithTransport):
3266
3267
    def test_no_orphan_for_transform_preview(self):
3268
        tree = self.make_branch_and_tree('tree')
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3269
        tt = transform.TransformPreview(tree)
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
3270
        self.addCleanup(tt.finalize)
3271
        self.assertRaises(NotImplementedError, tt.new_orphan, 'foo', 'bar')
3272
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3273
    def _set_orphan_policy(self, wt, policy):
5409.1.24 by Vincent Ladeuil
Rename bzrlib.transform.orphan_policy to bzr.transform.orphan_policy.
3274
        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.
3275
                                               policy)
3276
3277
    def _prepare_orphan(self, wt):
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3278
        self.build_tree(['dir/', 'dir/file', 'dir/foo'])
3279
        wt.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
3280
        wt.commit('add dir and file ignoring foo')
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3281
        tt = transform.TreeTransform(wt)
3282
        self.addCleanup(tt.finalize)
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3283
        # dir and bar are deleted
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3284
        dir_tid = tt.trans_id_tree_path('dir')
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3285
        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.
3286
        orphan_tid = tt.trans_id_tree_path('dir/foo')
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3287
        tt.delete_contents(file_tid)
3288
        tt.unversion_file(file_tid)
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3289
        tt.delete_contents(dir_tid)
3290
        tt.unversion_file(dir_tid)
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3291
        # 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.
3292
        raw_conflicts = tt.find_conflicts()
3293
        self.assertLength(1, raw_conflicts)
3294
        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.
3295
        return tt, orphan_tid
3296
3297
    def test_new_orphan_created(self):
3298
        wt = self.make_branch_and_tree('.')
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
3299
        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.
3300
        tt, orphan_tid = self._prepare_orphan(wt)
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3301
        warnings = []
3302
        def warning(*args):
3303
            warnings.append(args[0] % args[1:])
3304
        self.overrideAttr(trace, 'warning', warning)
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3305
        remaining_conflicts = resolve_conflicts(tt)
5540.3.1 by Vincent Ladeuil
Fix spurious orphan reports.
3306
        self.assertEquals(['dir/foo has been orphaned in bzr-orphans'],
3307
                          warnings)
5409.7.2 by Vincent Ladeuil
Add NEWS entry, a missing test and some cleanup.
3308
        # Yeah for resolved conflicts !
3309
        self.assertLength(0, remaining_conflicts)
3310
        # We have a new orphan
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3311
        self.assertEquals('foo.~1~', tt.final_name(orphan_tid))
5409.7.4 by Vincent Ladeuil
Take jam's review comments into account.
3312
        self.assertEquals('bzr-orphans',
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
3313
                          tt.final_name(tt.final_parent(orphan_tid)))
3314
3315
    def test_never_orphan(self):
3316
        wt = self.make_branch_and_tree('.')
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
3317
        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.
3318
        tt, orphan_tid = self._prepare_orphan(wt)
3319
        remaining_conflicts = resolve_conflicts(tt)
3320
        self.assertLength(1, remaining_conflicts)
3321
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
3322
                         remaining_conflicts.pop())
3323
3324
    def test_orphan_error(self):
3325
        def bogus_orphan(tt, orphan_id, parent_id):
3326
            raise transform.OrphaningError(tt.final_name(orphan_id),
3327
                                           tt.final_name(parent_id))
3328
        transform.orphaning_registry.register('bogus', bogus_orphan,
3329
                                              'Raise an error when orphaning')
3330
        wt = self.make_branch_and_tree('.')
3331
        self._set_orphan_policy(wt, 'bogus')
3332
        tt, orphan_tid = self._prepare_orphan(wt)
3333
        remaining_conflicts = resolve_conflicts(tt)
3334
        self.assertLength(1, remaining_conflicts)
3335
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
3336
                         remaining_conflicts.pop())
5409.1.17 by Vincent Ladeuil
Ensures we fallback to the default policy if a bogus one is specified.
3337
3338
    def test_unknown_orphan_policy(self):
3339
        wt = self.make_branch_and_tree('.')
3340
        # Set a fictional policy nobody ever implemented
3341
        self._set_orphan_policy(wt, 'donttouchmypreciouuus')
3342
        tt, orphan_tid = self._prepare_orphan(wt)
3343
        warnings = []
3344
        def warning(*args):
3345
            warnings.append(args[0] % args[1:])
3346
        self.overrideAttr(trace, 'warning', warning)
3347
        remaining_conflicts = resolve_conflicts(tt)
5409.1.20 by Vincent Ladeuil
Revert to 'conflict' being the default orphaning policy and fix fallouts.
3348
        # We fallback to the default policy which create a conflict
3349
        self.assertLength(1, remaining_conflicts)
3350
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
3351
                         remaining_conflicts.pop())
3352
        self.assertLength(1, warnings)
3353
        self.assertStartsWith(warnings[0], 'donttouchmypreciouuus')