/brz/remove-bazaar

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