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