/brz/remove-bazaar

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