/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'
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
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
1740.2.4 by Aaron Bentley
Update transform tests and docs
833
    def test_set_executability_order(self):
834
        """Ensure that executability behaves the same, no matter what order.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
835
1740.2.4 by Aaron Bentley
Update transform tests and docs
836
        - create file and set executability simultaneously
837
        - create file and set executability afterward
838
        - unsetting the executability of a file whose executability has not been
839
        declared should throw an exception (this may happen when a
840
        merge attempts to create a file with a duplicate ID)
841
        """
842
        transform, root = self.get_transform()
843
        wt = transform._tree
3034.2.1 by Aaron Bentley
Fix is_executable tests for win32
844
        wt.lock_read()
845
        self.addCleanup(wt.unlock)
1740.2.4 by Aaron Bentley
Update transform tests and docs
846
        transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
847
                           True)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
848
        sac = transform.new_file('set_after_creation', root,
849
                                 'Set after creation', 'sac')
1740.2.4 by Aaron Bentley
Update transform tests and docs
850
        transform.set_executability(True, sac)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
851
        uws = transform.new_file('unset_without_set', root, 'Unset badly',
852
                                 'uws')
1740.2.4 by Aaron Bentley
Update transform tests and docs
853
        self.assertRaises(KeyError, transform.set_executability, None, uws)
854
        transform.apply()
855
        self.assertTrue(wt.is_executable('soc'))
856
        self.assertTrue(wt.is_executable('sac'))
857
1534.12.2 by Aaron Bentley
Added test for preserving file mode
858
    def test_preserve_mode(self):
859
        """File mode is preserved when replacing content"""
860
        if sys.platform == 'win32':
861
            raise TestSkipped('chmod has no effect on win32')
862
        transform, root = self.get_transform()
863
        transform.new_file('file1', root, 'contents', 'file1-id', True)
864
        transform.apply()
3146.4.12 by Aaron Bentley
Add needed write lock to test
865
        self.wt.lock_write()
866
        self.addCleanup(self.wt.unlock)
1534.12.2 by Aaron Bentley
Added test for preserving file mode
867
        self.assertTrue(self.wt.is_executable('file1-id'))
868
        transform, root = self.get_transform()
869
        file1_id = transform.trans_id_tree_file_id('file1-id')
870
        transform.delete_contents(file1_id)
871
        transform.create_file('contents2', file1_id)
872
        transform.apply()
873
        self.assertTrue(self.wt.is_executable('file1-id'))
874
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
875
    def test__set_mode_stats_correctly(self):
876
        """_set_mode stats to determine file mode."""
877
        if sys.platform == 'win32':
878
            raise TestSkipped('chmod has no effect on win32')
879
880
        stat_paths = []
881
        real_stat = os.stat
882
        def instrumented_stat(path):
883
            stat_paths.append(path)
884
            return real_stat(path)
885
886
        transform, root = self.get_transform()
887
888
        bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
889
                                     file_id='bar-id-1', executable=False)
890
        transform.apply()
891
892
        transform, root = self.get_transform()
893
        bar1_id = transform.trans_id_tree_path('bar')
894
        bar2_id = transform.trans_id_tree_path('bar2')
895
        try:
896
            os.stat = instrumented_stat
897
            transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
898
        finally:
899
            os.stat = real_stat
900
            transform.finalize()
901
902
        bar1_abspath = self.wt.abspath('bar')
903
        self.assertEqual([bar1_abspath], stat_paths)
904
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
905
    def test_iter_changes(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
906
        self.wt.set_root_id('eert_toor')
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
907
        transform, root = self.get_transform()
908
        transform.new_file('old', root, 'blah', 'id-1', True)
909
        transform.apply()
910
        transform, root = self.get_transform()
911
        try:
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
912
            self.assertEqual([], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
913
            old = transform.trans_id_tree_file_id('id-1')
914
            transform.unversion_file(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
915
            self.assertEqual([('id-1', ('old', None), False, (True, False),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
916
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
917
                (True, True))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
918
            transform.new_directory('new', root, 'id-1')
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
919
            self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
920
                ('eert_toor', 'eert_toor'), ('old', 'new'),
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
921
                ('file', 'directory'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
922
                (True, False))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
923
        finally:
924
            transform.finalize()
925
926
    def test_iter_changes_new(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
927
        self.wt.set_root_id('eert_toor')
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
928
        transform, root = self.get_transform()
929
        transform.new_file('old', root, 'blah')
930
        transform.apply()
931
        transform, root = self.get_transform()
932
        try:
933
            old = transform.trans_id_tree_path('old')
934
            transform.version_file('id-1', old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
935
            self.assertEqual([('id-1', (None, 'old'), False, (False, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
936
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
937
                (False, False))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
938
        finally:
939
            transform.finalize()
940
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
941
    def test_iter_changes_modifications(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
942
        self.wt.set_root_id('eert_toor')
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
943
        transform, root = self.get_transform()
944
        transform.new_file('old', root, 'blah', 'id-1')
945
        transform.new_file('new', root, 'blah')
946
        transform.new_directory('subdir', root, 'subdir-id')
947
        transform.apply()
948
        transform, root = self.get_transform()
949
        try:
950
            old = transform.trans_id_tree_path('old')
951
            subdir = transform.trans_id_tree_file_id('subdir-id')
952
            new = transform.trans_id_tree_path('new')
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
953
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
954
955
            #content deletion
956
            transform.delete_contents(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
957
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
958
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
959
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
960
961
            #content change
962
            transform.create_file('blah', old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
963
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
964
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
965
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
966
            transform.cancel_deletion(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
967
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
968
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
969
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
970
            transform.cancel_creation(old)
971
972
            # move file_id to a different file
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
973
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
974
            transform.unversion_file(old)
975
            transform.version_file('id-1', new)
976
            transform.adjust_path('old', root, new)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
977
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
978
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
979
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
980
            transform.cancel_versioning(new)
981
            transform._removed_id = set()
982
983
            #execute bit
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
984
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
985
            transform.set_executability(True, old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
986
            self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
987
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
988
                (False, True))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
989
            transform.set_executability(None, old)
990
991
            # filename
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
992
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
993
            transform.adjust_path('new', root, old)
994
            transform._new_parent = {}
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
995
            self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
996
                ('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
997
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
998
            transform._new_name = {}
999
1000
            # parent directory
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1001
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1002
            transform.adjust_path('new', subdir, old)
1003
            transform._new_name = {}
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1004
            self.assertEqual([('id-1', ('old', 'subdir/old'), False,
2255.2.180 by Martin Pool
merge dirstate
1005
                (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.
1006
                ('file', 'file'), (False, False))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1007
                list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1008
            transform._new_path = {}
1009
1010
        finally:
1011
            transform.finalize()
1012
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1013
    def test_iter_changes_modified_bleed(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1014
        self.wt.set_root_id('eert_toor')
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1015
        """Modified flag should not bleed from one change to another"""
1016
        # unfortunately, we have no guarantee that file1 (which is modified)
1017
        # will be applied before file2.  And if it's applied after file2, it
1018
        # obviously can't bleed into file2's change output.  But for now, it
1019
        # works.
1020
        transform, root = self.get_transform()
1021
        transform.new_file('file1', root, 'blah', 'id-1')
1022
        transform.new_file('file2', root, 'blah', 'id-2')
1023
        transform.apply()
1024
        transform, root = self.get_transform()
1025
        try:
1026
            transform.delete_contents(transform.trans_id_file_id('id-1'))
1027
            transform.set_executability(True,
1028
            transform.trans_id_file_id('id-2'))
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1029
            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
1030
                ('eert_toor', 'eert_toor'), ('file1', u'file1'),
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1031
                ('file', None), (False, False)),
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1032
                ('id-2', (u'file2', u'file2'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1033
                ('eert_toor', 'eert_toor'), ('file2', u'file2'),
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1034
                ('file', 'file'), (False, True))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1035
                list(transform.iter_changes()))
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1036
        finally:
1037
            transform.finalize()
1038
1551.10.37 by Aaron Bentley
recommit of TreeTransform._iter_changes fix with missing files
1039
    def test_iter_changes_move_missing(self):
1040
        """Test moving ids with no files around"""
1041
        self.wt.set_root_id('toor_eert')
1042
        # Need two steps because versioning a non-existant file is a conflict.
1043
        transform, root = self.get_transform()
1044
        transform.new_directory('floater', root, 'floater-id')
1045
        transform.apply()
1046
        transform, root = self.get_transform()
1047
        transform.delete_contents(transform.trans_id_tree_path('floater'))
1048
        transform.apply()
1049
        transform, root = self.get_transform()
1050
        floater = transform.trans_id_tree_path('floater')
1051
        try:
1052
            transform.adjust_path('flitter', root, floater)
1053
            self.assertEqual([('floater-id', ('floater', 'flitter'), False,
1054
            (True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1055
            (None, None), (False, False))], list(transform.iter_changes()))
1551.10.37 by Aaron Bentley
recommit of TreeTransform._iter_changes fix with missing files
1056
        finally:
1057
            transform.finalize()
1058
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1059
    def test_iter_changes_pointless(self):
1060
        """Ensure that no-ops are not treated as modifications"""
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1061
        self.wt.set_root_id('eert_toor')
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1062
        transform, root = self.get_transform()
1063
        transform.new_file('old', root, 'blah', 'id-1')
1064
        transform.new_directory('subdir', root, 'subdir-id')
1065
        transform.apply()
1066
        transform, root = self.get_transform()
1067
        try:
1068
            old = transform.trans_id_tree_path('old')
1069
            subdir = transform.trans_id_tree_file_id('subdir-id')
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1070
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1071
            transform.delete_contents(subdir)
1072
            transform.create_directory(subdir)
1073
            transform.set_executability(False, old)
1074
            transform.unversion_file(old)
1075
            transform.version_file('id-1', old)
1076
            transform.adjust_path('old', root, old)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1077
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1078
        finally:
1079
            transform.finalize()
1534.7.93 by Aaron Bentley
Added text merge test
1080
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1081
    def test_rename_count(self):
1082
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1083
        transform.new_file('name1', root, 'contents')
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1084
        self.assertEqual(transform.rename_count, 0)
1085
        transform.apply()
1086
        self.assertEqual(transform.rename_count, 1)
1087
        transform2, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1088
        transform2.adjust_path('name2', root,
1089
                               transform2.trans_id_tree_path('name1'))
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1090
        self.assertEqual(transform2.rename_count, 0)
1091
        transform2.apply()
1092
        self.assertEqual(transform2.rename_count, 2)
1093
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1094
    def test_change_parent(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1095
        """Ensure that after we change a parent, the results are still right.
1096
1097
        Renames and parent changes on pending transforms can happen as part
1098
        of conflict resolution, and are explicitly permitted by the
1099
        TreeTransform API.
1100
1101
        This test ensures they work correctly with the rename-avoidance
1102
        optimization.
1103
        """
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1104
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1105
        parent1 = transform.new_directory('parent1', root)
1106
        child1 = transform.new_file('child1', parent1, 'contents')
1107
        parent2 = transform.new_directory('parent2', root)
1108
        transform.adjust_path('child1', parent2, child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1109
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1110
        self.failIfExists(self.wt.abspath('parent1/child1'))
1111
        self.failUnlessExists(self.wt.abspath('parent2/child1'))
1112
        # rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
1113
        # 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
1114
        self.failUnlessEqual(2, transform.rename_count)
1115
1116
    def test_cancel_parent(self):
1117
        """Cancelling a parent doesn't cause deletion of a non-empty directory
1118
1119
        This is like the test_change_parent, except that we cancel the parent
1120
        before adjusting the path.  The transform must detect that the
1121
        directory is non-empty, and move children to safe locations.
1122
        """
1123
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1124
        parent1 = transform.new_directory('parent1', root)
1125
        child1 = transform.new_file('child1', parent1, 'contents')
1126
        child2 = transform.new_file('child2', parent1, 'contents')
1127
        try:
1128
            transform.cancel_creation(parent1)
1129
        except OSError:
1130
            self.fail('Failed to move child1 before deleting parent1')
1131
        transform.cancel_creation(child2)
1132
        transform.create_directory(parent1)
1133
        try:
1134
            transform.cancel_creation(parent1)
1135
        # If the transform incorrectly believes that child2 is still in
1136
        # parent1's limbo directory, it will try to rename it and fail
1137
        # because was already moved by the first cancel_creation.
1138
        except OSError:
1139
            self.fail('Transform still thinks child2 is a child of parent1')
1140
        parent2 = transform.new_directory('parent2', root)
1141
        transform.adjust_path('child1', parent2, child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1142
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1143
        self.failIfExists(self.wt.abspath('parent1'))
1144
        self.failUnlessExists(self.wt.abspath('parent2/child1'))
1145
        # 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
1146
        self.failUnlessEqual(2, transform.rename_count)
1147
1148
    def test_adjust_and_cancel(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1149
        """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
1150
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1151
        parent1 = transform.new_directory('parent1', root)
1152
        child1 = transform.new_file('child1', parent1, 'contents')
1153
        parent2 = transform.new_directory('parent2', root)
1154
        transform.adjust_path('child1', parent2, child1)
1155
        transform.cancel_creation(child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1156
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1157
            transform.cancel_creation(parent1)
1158
        # if the transform thinks child1 is still in parent1's limbo
1159
        # 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
1160
        except OSError:
2502.1.8 by Aaron Bentley
Updates from review comments
1161
            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
1162
        transform.finalize()
1163
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1164
    def test_noname_contents(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1165
        """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
1166
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1167
        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
1168
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1169
            transform.create_directory(parent)
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1170
        except KeyError:
1171
            self.fail("Can't handle contents with no name")
1172
        transform.finalize()
1173
2502.1.9 by Aaron Bentley
Add additional test for no-name contents
1174
    def test_noname_contents_nested(self):
1175
        """TreeTransform should permit deferring naming files."""
1176
        transform, root = self.get_transform()
1177
        parent = transform.trans_id_file_id('parent-id')
1178
        try:
1179
            transform.create_directory(parent)
1180
        except KeyError:
1181
            self.fail("Can't handle contents with no name")
1182
        child = transform.new_directory('child', parent)
1183
        transform.adjust_path('parent', root, parent)
1184
        transform.apply()
1185
        self.failUnlessExists(self.wt.abspath('parent/child'))
1186
        self.assertEqual(1, transform.rename_count)
1187
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1188
    def test_reuse_name(self):
1189
        """Avoid reusing the same limbo name for different files"""
1190
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1191
        parent = transform.new_directory('parent', root)
1192
        child1 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1193
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1194
            child2 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1195
        except OSError:
1196
            self.fail('Tranform tried to use the same limbo name twice')
2502.1.8 by Aaron Bentley
Updates from review comments
1197
        transform.adjust_path('child2', parent, child2)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1198
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1199
        # limbo/new-1 => parent, limbo/new-3 => parent/child2
1200
        # child2 is put into top-level limbo because child1 has already
1201
        # claimed the direct limbo path when child2 is created.  There is no
1202
        # advantage in renaming files once they're in top-level limbo, except
1203
        # as part of apply.
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1204
        self.assertEqual(2, transform.rename_count)
1205
1206
    def test_reuse_when_first_moved(self):
1207
        """Don't avoid direct paths when it is safe to use them"""
1208
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1209
        parent = transform.new_directory('parent', root)
1210
        child1 = transform.new_directory('child', parent)
1211
        transform.adjust_path('child1', parent, child1)
1212
        child2 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1213
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1214
        # limbo/new-1 => parent
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1215
        self.assertEqual(1, transform.rename_count)
1216
1217
    def test_reuse_after_cancel(self):
1218
        """Don't avoid direct paths when it is safe to use them"""
1219
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1220
        parent2 = transform.new_directory('parent2', root)
1221
        child1 = transform.new_directory('child1', parent2)
1222
        transform.cancel_creation(parent2)
1223
        transform.create_directory(parent2)
1224
        child2 = transform.new_directory('child1', parent2)
1225
        transform.adjust_path('child2', parent2, child1)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1226
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1227
        # limbo/new-1 => parent2, limbo/new-2 => parent2/child1
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1228
        self.assertEqual(2, transform.rename_count)
1229
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1230
    def test_finalize_order(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1231
        """Finalize must be done in child-to-parent order"""
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1232
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1233
        parent = transform.new_directory('parent', root)
1234
        child = transform.new_directory('child', parent)
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1235
        try:
1236
            transform.finalize()
1237
        except OSError:
2502.1.8 by Aaron Bentley
Updates from review comments
1238
            self.fail('Tried to remove parent before child1')
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1239
2502.1.13 by Aaron Bentley
Updates from review
1240
    def test_cancel_with_cancelled_child_should_succeed(self):
2502.1.12 by Aaron Bentley
Avoid renaming children with no content
1241
        transform, root = self.get_transform()
1242
        parent = transform.new_directory('parent', root)
1243
        child = transform.new_directory('child', parent)
1244
        transform.cancel_creation(child)
2502.1.13 by Aaron Bentley
Updates from review
1245
        transform.cancel_creation(parent)
2502.1.12 by Aaron Bentley
Avoid renaming children with no content
1246
        transform.finalize()
1247
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1248
    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).
1249
        def tt_helper():
3638.3.17 by Vincent Ladeuil
Fixed as per Aaron's review.
1250
            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).
1251
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1252
            try:
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1253
                foo = tt.new_directory('foo', tt.root)
1254
                tt.new_file('bar', foo, 'foobar')
1255
                baz = tt.new_directory('baz', tt.root)
1256
                tt.new_file('qux', baz, 'quux')
1257
                # Ask for a rename 'foo' -> 'baz'
1258
                tt.adjust_path('baz', tt.root, foo)
3063.1.3 by Aaron Bentley
Update for Linux
1259
                # 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).
1260
                tt.apply(no_conflicts=True)
3063.1.3 by Aaron Bentley
Update for Linux
1261
            except:
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1262
                wt.unlock()
3063.1.3 by Aaron Bentley
Update for Linux
1263
                raise
3638.3.17 by Vincent Ladeuil
Fixed as per Aaron's review.
1264
        # The rename will fail because the target directory is not empty (but
1265
        # 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).
1266
        err = self.assertRaises(errors.FileExists, tt_helper)
1267
        self.assertContainsRe(str(err),
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1268
            "^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).
1269
3063.1.2 by Alexander Belchenko
test for two directories clash
1270
    def test_two_directories_clash(self):
1271
        def tt_helper():
1272
            wt = self.make_branch_and_tree('.')
1273
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1274
            try:
3063.1.3 by Aaron Bentley
Update for Linux
1275
                foo_1 = tt.new_directory('foo', tt.root)
1276
                tt.new_directory('bar', foo_1)
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1277
                # Adding the same directory with a different content
3063.1.3 by Aaron Bentley
Update for Linux
1278
                foo_2 = tt.new_directory('foo', tt.root)
1279
                tt.new_directory('baz', foo_2)
1280
                # Lie to tt that we've already resolved all conflicts.
3063.1.2 by Alexander Belchenko
test for two directories clash
1281
                tt.apply(no_conflicts=True)
3063.1.3 by Aaron Bentley
Update for Linux
1282
            except:
3063.1.2 by Alexander Belchenko
test for two directories clash
1283
                wt.unlock()
3063.1.3 by Aaron Bentley
Update for Linux
1284
                raise
3063.1.2 by Alexander Belchenko
test for two directories clash
1285
        err = self.assertRaises(errors.FileExists, tt_helper)
1286
        self.assertContainsRe(str(err),
1287
            "^File exists: .+/foo")
1288
3100.1.1 by Aaron Bentley
Fix ImmortalLimbo errors when transforms fail
1289
    def test_two_directories_clash_finalize(self):
1290
        def tt_helper():
1291
            wt = self.make_branch_and_tree('.')
1292
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1293
            try:
1294
                foo_1 = tt.new_directory('foo', tt.root)
1295
                tt.new_directory('bar', foo_1)
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1296
                # Adding the same directory with a different content
3100.1.1 by Aaron Bentley
Fix ImmortalLimbo errors when transforms fail
1297
                foo_2 = tt.new_directory('foo', tt.root)
1298
                tt.new_directory('baz', foo_2)
1299
                # Lie to tt that we've already resolved all conflicts.
1300
                tt.apply(no_conflicts=True)
1301
            except:
1302
                tt.finalize()
1303
                raise
1304
        err = self.assertRaises(errors.FileExists, tt_helper)
1305
        self.assertContainsRe(str(err),
1306
            "^File exists: .+/foo")
1307
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1308
    def test_file_to_directory(self):
1309
        wt = self.make_branch_and_tree('.')
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1310
        self.build_tree(['foo'])
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1311
        wt.add(['foo'])
3590.3.1 by James Westby
Make TreeTransform update the inventory with new kind information.
1312
        wt.commit("one")
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1313
        tt = TreeTransform(wt)
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1314
        self.addCleanup(tt.finalize)
3535.6.3 by James Westby
Fix the test to not create transform conflicts.
1315
        foo_trans_id = tt.trans_id_tree_path("foo")
1316
        tt.delete_contents(foo_trans_id)
1317
        tt.create_directory(foo_trans_id)
1318
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1319
        tt.create_file(["aa\n"], bar_trans_id)
1320
        tt.version_file("bar-1", bar_trans_id)
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1321
        tt.apply()
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1322
        self.failUnlessExists("foo/bar")
3590.3.2 by James Westby
Handle ->symlink changes as well.
1323
        wt.lock_read()
1324
        try:
1325
            self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1326
                    "directory")
1327
        finally:
1328
            wt.unlock()
3590.3.1 by James Westby
Make TreeTransform update the inventory with new kind information.
1329
        wt.commit("two")
1330
        changes = wt.changes_from(wt.basis_tree())
1331
        self.assertFalse(changes.has_changed(), changes)
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1332
3590.3.2 by James Westby
Handle ->symlink changes as well.
1333
    def test_file_to_symlink(self):
3590.3.3 by James Westby
Make ->file changes work as well.
1334
        self.requireFeature(SymlinkFeature)
3590.3.2 by James Westby
Handle ->symlink changes as well.
1335
        wt = self.make_branch_and_tree('.')
1336
        self.build_tree(['foo'])
1337
        wt.add(['foo'])
1338
        wt.commit("one")
1339
        tt = TreeTransform(wt)
1340
        self.addCleanup(tt.finalize)
1341
        foo_trans_id = tt.trans_id_tree_path("foo")
1342
        tt.delete_contents(foo_trans_id)
1343
        tt.create_symlink("bar", foo_trans_id)
1344
        tt.apply()
1345
        self.failUnlessExists("foo")
1346
        wt.lock_read()
1347
        self.addCleanup(wt.unlock)
1348
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1349
                "symlink")
1350
3590.3.3 by James Westby
Make ->file changes work as well.
1351
    def test_dir_to_file(self):
1352
        wt = self.make_branch_and_tree('.')
1353
        self.build_tree(['foo/', 'foo/bar'])
1354
        wt.add(['foo', 'foo/bar'])
1355
        wt.commit("one")
1356
        tt = TreeTransform(wt)
1357
        self.addCleanup(tt.finalize)
1358
        foo_trans_id = tt.trans_id_tree_path("foo")
1359
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1360
        tt.delete_contents(foo_trans_id)
1361
        tt.delete_versioned(bar_trans_id)
1362
        tt.create_file(["aa\n"], foo_trans_id)
1363
        tt.apply()
1364
        self.failUnlessExists("foo")
1365
        wt.lock_read()
1366
        self.addCleanup(wt.unlock)
1367
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1368
                "file")
1369
3590.3.4 by James Westby
Add a test for creating hardlinks as well.
1370
    def test_dir_to_hardlink(self):
3590.3.5 by James Westby
Use HardlinkFeature for the hardlink test.
1371
        self.requireFeature(HardlinkFeature)
3590.3.4 by James Westby
Add a test for creating hardlinks as well.
1372
        wt = self.make_branch_and_tree('.')
1373
        self.build_tree(['foo/', 'foo/bar'])
1374
        wt.add(['foo', 'foo/bar'])
1375
        wt.commit("one")
1376
        tt = TreeTransform(wt)
1377
        self.addCleanup(tt.finalize)
1378
        foo_trans_id = tt.trans_id_tree_path("foo")
1379
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1380
        tt.delete_contents(foo_trans_id)
1381
        tt.delete_versioned(bar_trans_id)
1382
        self.build_tree(['baz'])
1383
        tt.create_hardlink("baz", foo_trans_id)
1384
        tt.apply()
1385
        self.failUnlessExists("foo")
1386
        self.failUnlessExists("baz")
1387
        wt.lock_read()
1388
        self.addCleanup(wt.unlock)
1389
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1390
                "file")
1391
3619.2.10 by Aaron Bentley
Compensate for stale entries in TT._needs_rename
1392
    def test_no_final_path(self):
1393
        transform, root = self.get_transform()
1394
        trans_id = transform.trans_id_file_id('foo')
1395
        transform.create_file('bar', trans_id)
1396
        transform.cancel_creation(trans_id)
1397
        transform.apply()
1398
3363.17.24 by Aaron Bentley
Implement create_by_tree
1399
    def test_create_from_tree(self):
1400
        tree1 = self.make_branch_and_tree('tree1')
1401
        self.build_tree_contents([('tree1/foo/',), ('tree1/bar', 'baz')])
1402
        tree1.add(['foo', 'bar'], ['foo-id', 'bar-id'])
1403
        tree2 = self.make_branch_and_tree('tree2')
1404
        tt = TreeTransform(tree2)
1405
        foo_trans_id = tt.create_path('foo', tt.root)
1406
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1407
        bar_trans_id = tt.create_path('bar', tt.root)
1408
        create_from_tree(tt, bar_trans_id, tree1, 'bar-id')
1409
        tt.apply()
1410
        self.assertEqual('directory', osutils.file_kind('tree2/foo'))
1411
        self.assertFileEqual('baz', 'tree2/bar')
1412
3363.17.25 by Aaron Bentley
remove get_inventory_entry, replace with create_from_tree
1413
    def test_create_from_tree_bytes(self):
1414
        """Provided lines are used instead of tree content."""
1415
        tree1 = self.make_branch_and_tree('tree1')
1416
        self.build_tree_contents([('tree1/foo', 'bar'),])
1417
        tree1.add('foo', 'foo-id')
1418
        tree2 = self.make_branch_and_tree('tree2')
1419
        tt = TreeTransform(tree2)
1420
        foo_trans_id = tt.create_path('foo', tt.root)
1421
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id', bytes='qux')
1422
        tt.apply()
1423
        self.assertFileEqual('qux', 'tree2/foo')
1424
1425
    def test_create_from_tree_symlink(self):
3363.17.24 by Aaron Bentley
Implement create_by_tree
1426
        self.requireFeature(SymlinkFeature)
1427
        tree1 = self.make_branch_and_tree('tree1')
1428
        os.symlink('bar', 'tree1/foo')
1429
        tree1.add('foo', 'foo-id')
1430
        tt = TreeTransform(self.make_branch_and_tree('tree2'))
1431
        foo_trans_id = tt.create_path('foo', tt.root)
1432
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1433
        tt.apply()
1434
        self.assertEqual('bar', os.readlink('tree2/foo'))
1435
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1436
1534.7.93 by Aaron Bentley
Added text merge test
1437
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).
1438
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1439
    def __init__(self, dirname, root_id):
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1440
        self.name = dirname
1534.7.93 by Aaron Bentley
Added text merge test
1441
        os.mkdir(dirname)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
1442
        self.wt = BzrDir.create_standalone_workingtree(dirname)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1443
        self.wt.set_root_id(root_id)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
1444
        self.b = self.wt.branch
1534.7.93 by Aaron Bentley
Added text merge test
1445
        self.tt = TreeTransform(self.wt)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
1446
        self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
1534.7.93 by Aaron Bentley
Added text merge test
1447
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1448
1534.7.95 by Aaron Bentley
Added more text merge tests
1449
def conflict_text(tree, merge):
1450
    template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
1451
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
1452
1534.7.93 by Aaron Bentley
Added text merge test
1453
1454
class TestTransformMerge(TestCaseInTempDir):
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
1455
1534.7.93 by Aaron Bentley
Added text merge test
1456
    def test_text_merge(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1457
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1458
        base = TransformGroup("base", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1459
        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
1460
        base.tt.new_file('b', base.root, 'b1', 'b')
1461
        base.tt.new_file('c', base.root, 'c', 'c')
1462
        base.tt.new_file('d', base.root, 'd', 'd')
1463
        base.tt.new_file('e', base.root, 'e', 'e')
1464
        base.tt.new_file('f', base.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1465
        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
1466
        base.tt.new_directory('h', base.root, 'h')
1534.7.93 by Aaron Bentley
Added text merge test
1467
        base.tt.apply()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1468
        other = TransformGroup("other", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1469
        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
1470
        other.tt.new_file('b', other.root, 'b2', 'b')
1471
        other.tt.new_file('c', other.root, 'c2', 'c')
1472
        other.tt.new_file('d', other.root, 'd', 'd')
1473
        other.tt.new_file('e', other.root, 'e2', 'e')
1474
        other.tt.new_file('f', other.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1475
        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
1476
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1477
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
1478
        other.tt.apply()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1479
        this = TransformGroup("this", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1480
        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
1481
        this.tt.new_file('b', this.root, 'b', 'b')
1482
        this.tt.new_file('c', this.root, 'c', 'c')
1483
        this.tt.new_file('d', this.root, 'd2', 'd')
1484
        this.tt.new_file('e', this.root, 'e2', 'e')
1485
        this.tt.new_file('f', this.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1486
        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
1487
        this.tt.new_file('h', this.root, '1\n2\n3\n4\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1488
        this.tt.new_file('i', this.root, '1\n2\n3\n4\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
1489
        this.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1490
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
3008.1.6 by Michael Hudson
chop up Merge3Merger.__init__ into pieces
1491
1534.7.95 by Aaron Bentley
Added more text merge tests
1492
        # textual merge
1534.7.93 by Aaron Bentley
Added text merge test
1493
        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
1494
        # three-way text conflict
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1495
        self.assertEqual(this.wt.get_file('b').read(),
1534.7.95 by Aaron Bentley
Added more text merge tests
1496
                         conflict_text('b', 'b2'))
1497
        # OTHER wins
1498
        self.assertEqual(this.wt.get_file('c').read(), 'c2')
1499
        # THIS wins
1500
        self.assertEqual(this.wt.get_file('d').read(), 'd2')
1501
        # Ambigious clean merge
1502
        self.assertEqual(this.wt.get_file('e').read(), 'e2')
1503
        # No change
1504
        self.assertEqual(this.wt.get_file('f').read(), 'f')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1505
        # Correct correct results when THIS == OTHER
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1506
        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
1507
        # Text conflict when THIS & OTHER are text and BASE is dir
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1508
        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
1509
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
1510
        self.assertEqual(this.wt.get_file_byname('h.THIS').read(),
1511
                         '1\n2\n3\n4\n')
1512
        self.assertEqual(this.wt.get_file_byname('h.OTHER').read(),
1513
                         'h\ni\nj\nk\n')
1514
        self.assertEqual(file_kind(this.wt.abspath('h.BASE')), 'directory')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1515
        self.assertEqual(this.wt.get_file('i').read(),
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1516
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
1517
        self.assertEqual(this.wt.get_file_byname('i.THIS').read(),
1518
                         '1\n2\n3\n4\n')
1519
        self.assertEqual(this.wt.get_file_byname('i.OTHER').read(),
1520
                         'h\ni\nj\nk\n')
1521
        self.assertEqual(os.path.exists(this.wt.abspath('i.BASE')), False)
1534.7.192 by Aaron Bentley
Record hashes produced by merges
1522
        modified = ['a', 'b', 'c', 'h', 'i']
1523
        merge_modified = this.wt.merge_modified()
1524
        self.assertSubset(merge_modified, modified)
1525
        self.assertEqual(len(merge_modified), len(modified))
1526
        file(this.wt.id2abspath('a'), 'wb').write('booga')
1527
        modified.pop(0)
1528
        merge_modified = this.wt.merge_modified()
1529
        self.assertSubset(merge_modified, modified)
1530
        self.assertEqual(len(merge_modified), len(modified))
1558.12.10 by Aaron Bentley
Be robust when merge_hash file_id not in inventory
1531
        this.wt.remove('b')
2796.1.4 by Aaron Bentley
Fix up various test cases
1532
        this.wt.revert()
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1533
1534
    def test_file_merge(self):
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1535
        self.requireFeature(SymlinkFeature)
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1536
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1537
        base = TransformGroup("BASE", root_id)
1538
        this = TransformGroup("THIS", root_id)
1539
        other = TransformGroup("OTHER", root_id)
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1540
        for tg in this, base, other:
1541
            tg.tt.new_directory('a', tg.root, 'a')
1542
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
1543
            tg.tt.new_file('c', tg.root, 'c', 'c')
1544
            tg.tt.new_symlink('d', tg.root, tg.name, 'd')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1545
        targets = ((base, 'base-e', 'base-f', None, None),
1546
                   (this, 'other-e', 'this-f', 'other-g', 'this-h'),
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1547
                   (other, 'other-e', None, 'other-g', 'other-h'))
1548
        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
1549
            for link, target in (('e', e_target), ('f', f_target),
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1550
                                 ('g', g_target), ('h', h_target)):
1551
                if target is not None:
1552
                    tg.tt.new_symlink(link, tg.root, target, link)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1553
1554
        for tg in this, base, other:
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1555
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1556
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1557
        self.assertIs(os.path.isdir(this.wt.abspath('a')), True)
1558
        self.assertIs(os.path.islink(this.wt.abspath('b')), True)
1559
        self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
1560
        for suffix in ('THIS', 'BASE', 'OTHER'):
1561
            self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1562
        self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1563
        self.assertEqual(this.wt.id2path('d'), 'd.OTHER')
1564
        self.assertEqual(this.wt.id2path('f'), 'f.THIS')
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1565
        self.assertEqual(os.readlink(this.wt.abspath('e')), 'other-e')
1566
        self.assertIs(os.path.lexists(this.wt.abspath('e.THIS')), False)
1567
        self.assertIs(os.path.lexists(this.wt.abspath('e.OTHER')), False)
1568
        self.assertIs(os.path.lexists(this.wt.abspath('e.BASE')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1569
        self.assertIs(os.path.lexists(this.wt.abspath('g')), True)
1570
        self.assertIs(os.path.lexists(this.wt.abspath('g.BASE')), False)
1571
        self.assertIs(os.path.lexists(this.wt.abspath('h')), False)
1572
        self.assertIs(os.path.lexists(this.wt.abspath('h.BASE')), False)
1573
        self.assertIs(os.path.lexists(this.wt.abspath('h.THIS')), True)
1574
        self.assertIs(os.path.lexists(this.wt.abspath('h.OTHER')), True)
1534.7.105 by Aaron Bentley
Got merge with rename working
1575
1576
    def test_filename_merge(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1577
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1578
        base = TransformGroup("BASE", root_id)
1579
        this = TransformGroup("THIS", root_id)
1580
        other = TransformGroup("OTHER", root_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1581
        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
1582
                                   for t in [base, this, other]]
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1583
        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
1584
                                   for t in [base, this, other]]
1585
        base.tt.new_directory('c', base_a, 'c')
1586
        this.tt.new_directory('c1', this_a, 'c')
1587
        other.tt.new_directory('c', other_b, 'c')
1588
1589
        base.tt.new_directory('d', base_a, 'd')
1590
        this.tt.new_directory('d1', this_b, 'd')
1591
        other.tt.new_directory('d', other_a, 'd')
1592
1593
        base.tt.new_directory('e', base_a, 'e')
1594
        this.tt.new_directory('e', this_a, 'e')
1595
        other.tt.new_directory('e1', other_b, 'e')
1596
1597
        base.tt.new_directory('f', base_a, 'f')
1598
        this.tt.new_directory('f1', this_b, 'f')
1599
        other.tt.new_directory('f1', other_b, 'f')
1600
1601
        for tg in [this, base, other]:
1602
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1603
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.176 by abentley
Fixed up tests for Windows
1604
        self.assertEqual(this.wt.id2path('c'), pathjoin('b/c1'))
1605
        self.assertEqual(this.wt.id2path('d'), pathjoin('b/d1'))
1606
        self.assertEqual(this.wt.id2path('e'), pathjoin('b/e1'))
1607
        self.assertEqual(this.wt.id2path('f'), pathjoin('b/f1'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1608
1609
    def test_filename_merge_conflicts(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1610
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1611
        base = TransformGroup("BASE", root_id)
1612
        this = TransformGroup("THIS", root_id)
1613
        other = TransformGroup("OTHER", root_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1614
        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
1615
                                   for t in [base, this, other]]
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1616
        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
1617
                                   for t in [base, this, other]]
1618
1619
        base.tt.new_file('g', base_a, 'g', 'g')
1620
        other.tt.new_file('g1', other_b, 'g1', 'g')
1621
1622
        base.tt.new_file('h', base_a, 'h', 'h')
1623
        this.tt.new_file('h1', this_b, 'h1', 'h')
1624
1625
        base.tt.new_file('i', base.root, 'i', 'i')
1534.7.153 by Aaron Bentley
Handled test cases involving symlinks
1626
        other.tt.new_directory('i1', this_b, 'i')
1534.7.105 by Aaron Bentley
Got merge with rename working
1627
1628
        for tg in [this, base, other]:
1629
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1630
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.105 by Aaron Bentley
Got merge with rename working
1631
1534.7.176 by abentley
Fixed up tests for Windows
1632
        self.assertEqual(this.wt.id2path('g'), pathjoin('b/g1.OTHER'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1633
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.BASE')), True)
1634
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.THIS')), False)
1534.7.176 by abentley
Fixed up tests for Windows
1635
        self.assertEqual(this.wt.id2path('h'), pathjoin('b/h1.THIS'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1636
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.BASE')), True)
1637
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.OTHER')), False)
1534.7.176 by abentley
Fixed up tests for Windows
1638
        self.assertEqual(this.wt.id2path('i'), pathjoin('b/i1.OTHER'))
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1639
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
1640
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1641
class TestBuildTree(tests.TestCaseWithTransport):
1642
3006.2.2 by Alexander Belchenko
tests added.
1643
    def test_build_tree_with_symlinks(self):
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1644
        self.requireFeature(SymlinkFeature)
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1645
        os.mkdir('a')
1646
        a = BzrDir.create_standalone_workingtree('a')
1647
        os.mkdir('a/foo')
1648
        file('a/foo/bar', 'wb').write('contents')
1649
        os.symlink('a/foo/bar', 'a/foo/baz')
1650
        a.add(['foo', 'foo/bar', 'foo/baz'])
1651
        a.commit('initial commit')
1652
        b = BzrDir.create_standalone_workingtree('b')
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
1653
        basis = a.basis_tree()
1654
        basis.lock_read()
1655
        self.addCleanup(basis.unlock)
1656
        build_tree(basis, b)
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1657
        self.assertIs(os.path.isdir('b/foo'), True)
1658
        self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
1659
        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
1660
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
1661
    def test_build_with_references(self):
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
1662
        tree = self.make_branch_and_tree('source',
1663
            format='dirstate-with-subtree')
1664
        subtree = self.make_branch_and_tree('source/subtree',
1665
            format='dirstate-with-subtree')
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
1666
        tree.add_reference(subtree)
1667
        tree.commit('a revision')
1668
        tree.branch.create_checkout('target')
1669
        self.failUnlessExists('target')
1670
        self.failUnlessExists('target/subtree')
1671
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1672
    def test_file_conflict_handling(self):
1673
        """Ensure that when building trees, conflict handling is done"""
1674
        source = self.make_branch_and_tree('source')
1675
        target = self.make_branch_and_tree('target')
1676
        self.build_tree(['source/file', 'target/file'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1677
        source.add('file', 'new-file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1678
        source.commit('added file')
1679
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1680
        self.assertEqual([DuplicateEntry('Moved existing file to',
1681
                          'file.moved', 'file', None, 'new-file')],
1682
                         target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1683
        target2 = self.make_branch_and_tree('target2')
1684
        target_file = file('target2/file', 'wb')
1685
        try:
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1686
            source_file = file('source/file', 'rb')
1687
            try:
1688
                target_file.write(source_file.read())
1689
            finally:
1690
                source_file.close()
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1691
        finally:
1692
            target_file.close()
1693
        build_tree(source.basis_tree(), target2)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1694
        self.assertEqual([], target2.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1695
1696
    def test_symlink_conflict_handling(self):
1697
        """Ensure that when building trees, conflict handling is done"""
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1698
        self.requireFeature(SymlinkFeature)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1699
        source = self.make_branch_and_tree('source')
1700
        os.symlink('foo', 'source/symlink')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1701
        source.add('symlink', 'new-symlink')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1702
        source.commit('added file')
1703
        target = self.make_branch_and_tree('target')
1704
        os.symlink('bar', 'target/symlink')
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
            'symlink.moved', 'symlink', None, 'new-symlink')],
1708
            target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1709
        target = self.make_branch_and_tree('target2')
1710
        os.symlink('foo', 'target2/symlink')
1711
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1712
        self.assertEqual([], target.conflicts())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1713
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1714
    def test_directory_conflict_handling(self):
1715
        """Ensure that when building trees, conflict handling is done"""
1716
        source = self.make_branch_and_tree('source')
1717
        target = self.make_branch_and_tree('target')
1718
        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
1719
        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
1720
        source.commit('added file')
1721
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1722
        self.assertEqual([], target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1723
        self.failUnlessExists('target/dir1/file')
1724
1725
        # Ensure contents are merged
1726
        target = self.make_branch_and_tree('target2')
1727
        self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
1728
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1729
        self.assertEqual([], target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1730
        self.failUnlessExists('target2/dir1/file2')
1731
        self.failUnlessExists('target2/dir1/file')
1732
1733
        # 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
1734
        target = self.make_branch_and_tree('target3')
1735
        self.make_branch('target3/dir1')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1736
        self.build_tree(['target3/dir1/file2'])
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.failIfExists('target3/dir1/file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1739
        self.failUnlessExists('target3/dir1/file2')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1740
        self.failUnlessExists('target3/dir1.diverted/file')
1741
        self.assertEqual([DuplicateEntry('Diverted to',
1742
            'dir1.diverted', 'dir1', 'new-dir1', None)],
1743
            target.conflicts())
1744
1745
        target = self.make_branch_and_tree('target4')
1746
        self.build_tree(['target4/dir1/'])
1747
        self.make_branch('target4/dir1/file')
1748
        build_tree(source.basis_tree(), target)
1749
        self.failUnlessExists('target4/dir1/file')
1750
        self.assertEqual('directory', file_kind('target4/dir1/file'))
1751
        self.failUnlessExists('target4/dir1/file.diverted')
1752
        self.assertEqual([DuplicateEntry('Diverted to',
1753
            'dir1/file.diverted', 'dir1/file', 'new-file', None)],
1754
            target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1755
1756
    def test_mixed_conflict_handling(self):
1757
        """Ensure that when building trees, conflict handling is done"""
1758
        source = self.make_branch_and_tree('source')
1759
        target = self.make_branch_and_tree('target')
1760
        self.build_tree(['source/name', 'target/name/'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1761
        source.add('name', 'new-name')
1762
        source.commit('added file')
1763
        build_tree(source.basis_tree(), target)
1764
        self.assertEqual([DuplicateEntry('Moved existing file to',
1765
            'name.moved', 'name', None, 'new-name')], target.conflicts())
1766
1767
    def test_raises_in_populated(self):
1768
        source = self.make_branch_and_tree('source')
1769
        self.build_tree(['source/name'])
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1770
        source.add('name')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1771
        source.commit('added name')
1772
        target = self.make_branch_and_tree('target')
1773
        self.build_tree(['target/name'])
1774
        target.add('name')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1775
        self.assertRaises(errors.WorkingTreeAlreadyPopulated,
2090.2.1 by Martin Pool
Fix some code which relies on assertions and breaks under python -O
1776
            build_tree, source.basis_tree(), target)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1777
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1778
    def test_build_tree_rename_count(self):
1779
        source = self.make_branch_and_tree('source')
1780
        self.build_tree(['source/file1', 'source/dir1/'])
1781
        source.add(['file1', 'dir1'])
1782
        source.commit('add1')
1783
        target1 = self.make_branch_and_tree('target1')
2502.1.6 by Aaron Bentley
Update from review comments
1784
        transform_result = build_tree(source.basis_tree(), target1)
1785
        self.assertEqual(2, transform_result.rename_count)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1786
1787
        self.build_tree(['source/dir1/file2'])
1788
        source.add(['dir1/file2'])
1789
        source.commit('add3')
1790
        target2 = self.make_branch_and_tree('target2')
2502.1.6 by Aaron Bentley
Update from review comments
1791
        transform_result = build_tree(source.basis_tree(), target2)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1792
        # children of non-root directories should not be renamed
2502.1.6 by Aaron Bentley
Update from review comments
1793
        self.assertEqual(2, transform_result.rename_count)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1794
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1795
    def create_ab_tree(self):
1796
        """Create a committed test tree with two files"""
1797
        source = self.make_branch_and_tree('source')
1798
        self.build_tree_contents([('source/file1', 'A')])
1799
        self.build_tree_contents([('source/file2', 'B')])
1800
        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1801
        source.commit('commit files')
1802
        source.lock_write()
1803
        self.addCleanup(source.unlock)
1804
        return source
1805
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
1806
    def test_build_tree_accelerator_tree(self):
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1807
        source = self.create_ab_tree()
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
1808
        self.build_tree_contents([('source/file2', 'C')])
1809
        calls = []
1810
        real_source_get_file = source.get_file
1811
        def get_file(file_id, path=None):
1812
            calls.append(file_id)
1813
            return real_source_get_file(file_id, path)
1814
        source.get_file = get_file
1815
        target = self.make_branch_and_tree('target')
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1816
        revision_tree = source.basis_tree()
1817
        revision_tree.lock_read()
1818
        self.addCleanup(revision_tree.unlock)
1819
        build_tree(revision_tree, target, source)
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
1820
        self.assertEqual(['file1-id'], calls)
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1821
        target.lock_read()
1822
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1823
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
1824
3123.5.4 by Aaron Bentley
Use an accelerator tree when branching, handle no-such-id correctly
1825
    def test_build_tree_accelerator_tree_missing_file(self):
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1826
        source = self.create_ab_tree()
3123.5.4 by Aaron Bentley
Use an accelerator tree when branching, handle no-such-id correctly
1827
        os.unlink('source/file1')
1828
        source.remove(['file2'])
1829
        target = self.make_branch_and_tree('target')
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1830
        revision_tree = source.basis_tree()
1831
        revision_tree.lock_read()
1832
        self.addCleanup(revision_tree.unlock)
1833
        build_tree(revision_tree, target, source)
1834
        target.lock_read()
1835
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1836
        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
1837
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
1838
    def test_build_tree_accelerator_wrong_kind(self):
3146.4.8 by Aaron Bentley
Add missing symlink requirement
1839
        self.requireFeature(SymlinkFeature)
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
1840
        source = self.make_branch_and_tree('source')
1841
        self.build_tree_contents([('source/file1', '')])
1842
        self.build_tree_contents([('source/file2', '')])
1843
        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1844
        source.commit('commit files')
1845
        os.unlink('source/file2')
1846
        self.build_tree_contents([('source/file2/', 'C')])
1847
        os.unlink('source/file1')
1848
        os.symlink('file2', 'source/file1')
1849
        calls = []
1850
        real_source_get_file = source.get_file
1851
        def get_file(file_id, path=None):
1852
            calls.append(file_id)
1853
            return real_source_get_file(file_id, path)
1854
        source.get_file = get_file
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)
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
1860
        self.assertEqual([], calls)
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1861
        target.lock_read()
1862
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1863
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
1864
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1865
    def test_build_tree_hardlink(self):
1866
        self.requireFeature(HardlinkFeature)
1867
        source = self.create_ab_tree()
1868
        target = self.make_branch_and_tree('target')
1869
        revision_tree = source.basis_tree()
1870
        revision_tree.lock_read()
1871
        self.addCleanup(revision_tree.unlock)
1872
        build_tree(revision_tree, target, source, hardlink=True)
1873
        target.lock_read()
1874
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1875
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1876
        source_stat = os.stat('source/file1')
1877
        target_stat = os.stat('target/file1')
1878
        self.assertEqual(source_stat, target_stat)
1879
1880
        # Explicitly disallowing hardlinks should prevent them.
1881
        target2 = self.make_branch_and_tree('target2')
1882
        build_tree(revision_tree, target2, source, hardlink=False)
1883
        target2.lock_read()
1884
        self.addCleanup(target2.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1885
        self.assertEqual([], list(target2.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1886
        source_stat = os.stat('source/file1')
1887
        target2_stat = os.stat('target2/file1')
1888
        self.assertNotEqual(source_stat, target2_stat)
1889
3137.1.1 by Aaron Bentley
Fix build_tree acceleration when file is moved in accelerator_tree
1890
    def test_build_tree_accelerator_tree_moved(self):
1891
        source = self.make_branch_and_tree('source')
1892
        self.build_tree_contents([('source/file1', 'A')])
1893
        source.add(['file1'], ['file1-id'])
1894
        source.commit('commit files')
1895
        source.rename_one('file1', 'file2')
1896
        source.lock_read()
1897
        self.addCleanup(source.unlock)
1898
        target = self.make_branch_and_tree('target')
1899
        revision_tree = source.basis_tree()
1900
        revision_tree.lock_read()
1901
        self.addCleanup(revision_tree.unlock)
1902
        build_tree(revision_tree, target, source)
1903
        target.lock_read()
1904
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1905
        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
1906
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1907
    def test_build_tree_hardlinks_preserve_execute(self):
1908
        self.requireFeature(HardlinkFeature)
1909
        source = self.create_ab_tree()
1910
        tt = TreeTransform(source)
1911
        trans_id = tt.trans_id_tree_file_id('file1-id')
1912
        tt.set_executability(True, trans_id)
1913
        tt.apply()
1914
        self.assertTrue(source.is_executable('file1-id'))
1915
        target = self.make_branch_and_tree('target')
1916
        revision_tree = source.basis_tree()
1917
        revision_tree.lock_read()
1918
        self.addCleanup(revision_tree.unlock)
1919
        build_tree(revision_tree, target, source, hardlink=True)
1920
        target.lock_read()
1921
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1922
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1923
        self.assertTrue(source.is_executable('file1-id'))
1924
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
1925
    def install_rot13_content_filter(self, pattern):
1926
        original_registry = filters._reset_registry()
1927
        def restore_registry():
1928
            filters._reset_registry(original_registry)
1929
        self.addCleanup(restore_registry)
1930
        def rot13(chunks, context=None):
1931
            return [''.join(chunks).encode('rot13')]
1932
        rot13filter = filters.ContentFilter(rot13, rot13)
1933
        filters.register_filter_stack_map('rot13', {'yes': [rot13filter]}.get)
1934
        os.mkdir(self.test_home_dir + '/.bazaar')
1935
        rules_filename = self.test_home_dir + '/.bazaar/rules'
4826.1.8 by Andrew Bennetts
Tweaks suggested by John.
1936
        f = open(rules_filename, 'wb')
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
1937
        f.write('[name %s]\nrot13=yes\n' % (pattern,))
1938
        f.close()
1939
        def uninstall_rules():
1940
            os.remove(rules_filename)
1941
            rules.reset_rules()
1942
        self.addCleanup(uninstall_rules)
1943
        rules.reset_rules()
1944
1945
    def test_build_tree_content_filtered_files_are_not_hardlinked(self):
1946
        """build_tree will not hardlink files that have content filtering rules
1947
        applied to them (but will still hardlink other files from the same tree
1948
        if it can).
1949
        """
1950
        self.requireFeature(HardlinkFeature)
1951
        self.install_rot13_content_filter('file1')
1952
        source = self.create_ab_tree()
1953
        target = self.make_branch_and_tree('target')
1954
        revision_tree = source.basis_tree()
1955
        revision_tree.lock_read()
1956
        self.addCleanup(revision_tree.unlock)
1957
        build_tree(revision_tree, target, source, hardlink=True)
1958
        target.lock_read()
1959
        self.addCleanup(target.unlock)
1960
        self.assertEqual([], list(target.iter_changes(revision_tree)))
1961
        source_stat = os.stat('source/file1')
1962
        target_stat = os.stat('target/file1')
1963
        self.assertNotEqual(source_stat, target_stat)
1964
        source_stat = os.stat('source/file2')
1965
        target_stat = os.stat('target/file2')
4826.1.8 by Andrew Bennetts
Tweaks suggested by John.
1966
        self.assertEqualStat(source_stat, target_stat)
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
1967
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1968
    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.
1969
        if (tests.CaseInsensitiveFilesystemFeature.available()
1970
            or tests.CaseInsCasePresFilenameFeature.available()):
4241.9.4 by Vincent Ladeuil
Fix test_case_insensitive_build_tree_inventory failure on OSX.
1971
            raise tests.UnavailableFeature('Fully case sensitive filesystem')
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1972
        source = self.make_branch_and_tree('source')
1973
        self.build_tree(['source/file', 'source/FILE'])
1974
        source.add(['file', 'FILE'], ['lower-id', 'upper-id'])
1975
        source.commit('added files')
1976
        # Don't try this at home, kids!
1977
        # Force the tree to report that it is case insensitive
1978
        target = self.make_branch_and_tree('target')
1979
        target.case_sensitive = False
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
1980
        build_tree(source.basis_tree(), target, source, delta_from_tree=True)
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1981
        self.assertEqual('file.moved', target.id2path('lower-id'))
1982
        self.assertEqual('FILE', target.id2path('upper-id'))
1983
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1984
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
1985
class TestCommitTransform(tests.TestCaseWithTransport):
1986
1987
    def get_branch(self):
1988
        tree = self.make_branch_and_tree('tree')
1989
        tree.lock_write()
1990
        self.addCleanup(tree.unlock)
1991
        tree.commit('empty commit')
1992
        return tree.branch
1993
1994
    def get_branch_and_transform(self):
1995
        branch = self.get_branch()
1996
        tt = TransformPreview(branch.basis_tree())
1997
        self.addCleanup(tt.finalize)
1998
        return branch, tt
1999
2000
    def test_commit_wrong_basis(self):
2001
        branch = self.get_branch()
2002
        basis = branch.repository.revision_tree(
2003
            _mod_revision.NULL_REVISION)
2004
        tt = TransformPreview(basis)
2005
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
2006
        e = self.assertRaises(ValueError, tt.commit, branch, '')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2007
        self.assertEqual('TreeTransform not based on branch basis: null:',
2008
                         str(e))
2009
2010
    def test_empy_commit(self):
2011
        branch, tt = self.get_branch_and_transform()
2012
        rev = tt.commit(branch, 'my message')
2013
        self.assertEqual(2, branch.revno())
2014
        repo = branch.repository
2015
        self.assertEqual('my message', repo.get_revision(rev).message)
2016
2017
    def test_merge_parents(self):
2018
        branch, tt = self.get_branch_and_transform()
2019
        rev = tt.commit(branch, 'my message', ['rev1b', 'rev1c'])
2020
        self.assertEqual(['rev1b', 'rev1c'],
2021
                         branch.basis_tree().get_parent_ids()[1:])
2022
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2023
    def test_first_commit(self):
2024
        branch = self.make_branch('branch')
2025
        branch.lock_write()
2026
        self.addCleanup(branch.unlock)
2027
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2028
        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.
2029
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2030
        rev = tt.commit(branch, 'my message')
2031
        self.assertEqual([], branch.basis_tree().get_parent_ids())
4526.8.5 by Aaron Bentley
Updates from review.
2032
        self.assertNotEqual(_mod_revision.NULL_REVISION,
2033
                            branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2034
4526.8.5 by Aaron Bentley
Updates from review.
2035
    def test_first_commit_with_merge_parents(self):
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2036
        branch = self.make_branch('branch')
2037
        branch.lock_write()
2038
        self.addCleanup(branch.unlock)
2039
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2040
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
2041
        e = self.assertRaises(ValueError, tt.commit, branch,
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2042
                          'my message', ['rev1b-id'])
4526.8.5 by Aaron Bentley
Updates from review.
2043
        self.assertEqual('Cannot supply merge parents for first commit.',
2044
                         str(e))
2045
        self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2046
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2047
    def test_add_files(self):
2048
        branch, tt = self.get_branch_and_transform()
2049
        tt.new_file('file', tt.root, 'contents', 'file-id')
2050
        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
2051
        if SymlinkFeature.available():
2052
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2053
        rev = tt.commit(branch, 'message')
2054
        tree = branch.basis_tree()
2055
        self.assertEqual('file', tree.id2path('file-id'))
2056
        self.assertEqual('contents', tree.get_file_text('file-id'))
2057
        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
2058
        if SymlinkFeature.available():
2059
            self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
2060
            self.assertEqual('target', tree.get_symlink_target('symlink-id'))
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2061
4526.8.2 by Aaron Bentley
Proved strict commit handling.
2062
    def test_add_unversioned(self):
2063
        branch, tt = self.get_branch_and_transform()
2064
        tt.new_file('file', tt.root, 'contents')
2065
        self.assertRaises(errors.StrictCommitFailed, tt.commit, branch,
2066
                          'message', strict=True)
2067
2068
    def test_modify_strict(self):
2069
        branch, tt = self.get_branch_and_transform()
2070
        tt.new_file('file', tt.root, 'contents', 'file-id')
2071
        tt.commit(branch, 'message', strict=True)
2072
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2073
        self.addCleanup(tt.finalize)
4526.8.2 by Aaron Bentley
Proved strict commit handling.
2074
        trans_id = tt.trans_id_file_id('file-id')
2075
        tt.delete_contents(trans_id)
2076
        tt.create_file('contents', trans_id)
2077
        tt.commit(branch, 'message', strict=True)
2078
4526.8.6 by Aaron Bentley
Check for malformed transforms before committing.
2079
    def test_commit_malformed(self):
2080
        """Committing a malformed transform should raise an exception.
2081
2082
        In this case, we are adding a file without adding its parent.
2083
        """
2084
        branch, tt = self.get_branch_and_transform()
2085
        parent_id = tt.trans_id_file_id('parent-id')
2086
        tt.new_file('file', parent_id, 'contents', 'file-id')
2087
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
2088
                          'message')
2089
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2090
1534.10.28 by Aaron Bentley
Use numbered backup files
2091
class MockTransform(object):
2092
2093
    def has_named_child(self, by_parent, parent_id, name):
2094
        for child_id in by_parent[parent_id]:
2095
            if child_id == '0':
2096
                if name == "name~":
2097
                    return True
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2098
            elif name == "name.~%s~" % child_id:
1534.10.28 by Aaron Bentley
Use numbered backup files
2099
                return True
2100
        return False
2101
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
2102
1534.10.28 by Aaron Bentley
Use numbered backup files
2103
class MockEntry(object):
2104
    def __init__(self):
2105
        object.__init__(self)
2106
        self.name = "name"
2107
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
2108
1534.10.28 by Aaron Bentley
Use numbered backup files
2109
class TestGetBackupName(TestCase):
2110
    def test_get_backup_name(self):
2111
        tt = MockTransform()
2112
        name = get_backup_name(MockEntry(), {'a':[]}, 'a', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2113
        self.assertEqual(name, 'name.~1~')
2114
        name = get_backup_name(MockEntry(), {'a':['1']}, 'a', tt)
2115
        self.assertEqual(name, 'name.~2~')
1534.10.28 by Aaron Bentley
Use numbered backup files
2116
        name = get_backup_name(MockEntry(), {'a':['2']}, 'a', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2117
        self.assertEqual(name, 'name.~1~')
1534.10.28 by Aaron Bentley
Use numbered backup files
2118
        name = get_backup_name(MockEntry(), {'a':['2'], 'b':[]}, 'b', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2119
        self.assertEqual(name, 'name.~1~')
2120
        name = get_backup_name(MockEntry(), {'a':['1', '2', '3']}, 'a', tt)
2121
        self.assertEqual(name, 'name.~4~')
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2122
2123
2124
class TestFileMover(tests.TestCaseWithTransport):
2125
2126
    def test_file_mover(self):
2127
        self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
2128
        mover = _FileMover()
2129
        mover.rename('a', 'q')
2130
        self.failUnlessExists('q')
2131
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2132
        self.failUnlessExists('q/b')
2133
        self.failUnlessExists('c')
2134
        self.failUnlessExists('c/d')
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2135
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2136
    def test_pre_delete_rollback(self):
2137
        self.build_tree(['a/'])
2138
        mover = _FileMover()
2139
        mover.pre_delete('a', 'q')
2140
        self.failUnlessExists('q')
2141
        self.failIfExists('a')
2142
        mover.rollback()
2143
        self.failIfExists('q')
2144
        self.failUnlessExists('a')
2145
2146
    def test_apply_deletions(self):
2733.2.12 by Aaron Bentley
Updates from review
2147
        self.build_tree(['a/', 'b/'])
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2148
        mover = _FileMover()
2149
        mover.pre_delete('a', 'q')
2733.2.12 by Aaron Bentley
Updates from review
2150
        mover.pre_delete('b', 'r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2151
        self.failUnlessExists('q')
2733.2.12 by Aaron Bentley
Updates from review
2152
        self.failUnlessExists('r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2153
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2154
        self.failIfExists('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2155
        mover.apply_deletions()
2156
        self.failIfExists('q')
2733.2.12 by Aaron Bentley
Updates from review
2157
        self.failIfExists('r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2158
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2159
        self.failIfExists('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2160
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2161
    def test_file_mover_rollback(self):
2162
        self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
2163
        mover = _FileMover()
2164
        mover.rename('c/d', 'c/f')
2165
        mover.rename('c/e', 'c/d')
2166
        try:
2167
            mover.rename('a', 'c')
3063.1.3 by Aaron Bentley
Update for Linux
2168
        except errors.FileExists, e:
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2169
            mover.rollback()
2170
        self.failUnlessExists('a')
2171
        self.failUnlessExists('c/d')
2733.2.3 by Aaron Bentley
Test tranform rollback
2172
2173
2174
class Bogus(Exception):
2175
    pass
2176
2177
2178
class TestTransformRollback(tests.TestCaseWithTransport):
2179
2180
    class ExceptionFileMover(_FileMover):
2181
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2182
        def __init__(self, bad_source=None, bad_target=None):
2183
            _FileMover.__init__(self)
2184
            self.bad_source = bad_source
2185
            self.bad_target = bad_target
2186
2733.2.3 by Aaron Bentley
Test tranform rollback
2187
        def rename(self, source, target):
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2188
            if (self.bad_source is not None and
2189
                source.endswith(self.bad_source)):
2190
                raise Bogus
2191
            elif (self.bad_target is not None and
2192
                target.endswith(self.bad_target)):
2733.2.3 by Aaron Bentley
Test tranform rollback
2193
                raise Bogus
2194
            else:
2195
                _FileMover.rename(self, source, target)
2196
2197
    def test_rollback_rename(self):
2198
        tree = self.make_branch_and_tree('.')
2199
        self.build_tree(['a/', 'a/b'])
2200
        tt = TreeTransform(tree)
2201
        self.addCleanup(tt.finalize)
2202
        a_id = tt.trans_id_tree_path('a')
2203
        tt.adjust_path('c', tt.root, a_id)
2204
        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
2205
        self.assertRaises(Bogus, tt.apply,
2206
                          _mover=self.ExceptionFileMover(bad_source='a'))
2207
        self.failUnlessExists('a')
2208
        self.failUnlessExists('a/b')
2209
        tt.apply()
2210
        self.failUnlessExists('c')
2211
        self.failUnlessExists('c/d')
2212
2213
    def test_rollback_rename_into_place(self):
2214
        tree = self.make_branch_and_tree('.')
2215
        self.build_tree(['a/', 'a/b'])
2216
        tt = TreeTransform(tree)
2217
        self.addCleanup(tt.finalize)
2218
        a_id = tt.trans_id_tree_path('a')
2219
        tt.adjust_path('c', tt.root, a_id)
2220
        tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
2221
        self.assertRaises(Bogus, tt.apply,
2222
                          _mover=self.ExceptionFileMover(bad_target='c/d'))
2223
        self.failUnlessExists('a')
2224
        self.failUnlessExists('a/b')
2225
        tt.apply()
2226
        self.failUnlessExists('c')
2227
        self.failUnlessExists('c/d')
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
2228
2229
    def test_rollback_deletion(self):
2230
        tree = self.make_branch_and_tree('.')
2231
        self.build_tree(['a/', 'a/b'])
2232
        tt = TreeTransform(tree)
2233
        self.addCleanup(tt.finalize)
2234
        a_id = tt.trans_id_tree_path('a')
2235
        tt.delete_contents(a_id)
2236
        tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
2237
        self.assertRaises(Bogus, tt.apply,
2238
                          _mover=self.ExceptionFileMover(bad_target='d'))
2239
        self.failUnlessExists('a')
2240
        self.failUnlessExists('a/b')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2241
1551.19.6 by Aaron Bentley
Revert doesn't crash restoring a file from a deleted directory
2242
    def test_resolve_no_parent(self):
2243
        wt = self.make_branch_and_tree('.')
2244
        tt = TreeTransform(wt)
2245
        self.addCleanup(tt.finalize)
2246
        parent = tt.trans_id_file_id('parent-id')
2247
        tt.new_file('file', parent, 'Contents')
2248
        resolve_conflicts(tt)
3008.1.13 by Michael Hudson
merge bzr.dev
2249
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2250
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2251
A_ENTRY = ('a-id', ('a', 'a'), True, (True, True),
2252
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2253
                  (False, False))
2254
ROOT_ENTRY = ('TREE_ROOT', ('', ''), False, (True, True), (None, None),
2255
              ('', ''), ('directory', 'directory'), (False, None))
2256
2257
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2258
class TestTransformPreview(tests.TestCaseWithTransport):
2259
2260
    def create_tree(self):
2261
        tree = self.make_branch_and_tree('.')
2262
        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.
2263
        tree.set_root_id('TREE_ROOT')
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2264
        tree.add('a', 'a-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2265
        tree.commit('rev1', rev_id='rev1')
2266
        return tree.branch.repository.revision_tree('rev1')
2267
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2268
    def get_empty_preview(self):
2269
        repository = self.make_repository('repo')
2270
        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
2271
        preview = TransformPreview(tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2272
        self.addCleanup(preview.finalize)
3199.1.4 by Vincent Ladeuil
Fix 16 leaked tmp dirs. Probably indicates a lock handling problem with TransformPreview
2273
        return preview
2274
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2275
    def test_transform_preview(self):
2276
        revision_tree = self.create_tree()
2277
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2278
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2279
2280
    def test_transform_preview_tree(self):
2281
        revision_tree = self.create_tree()
2282
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2283
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2284
        preview.get_preview_tree()
2285
3008.1.5 by Michael Hudson
a more precise test
2286
    def test_transform_new_file(self):
2287
        revision_tree = self.create_tree()
2288
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2289
        self.addCleanup(preview.finalize)
3008.1.5 by Michael Hudson
a more precise test
2290
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2291
        preview_tree = preview.get_preview_tree()
2292
        self.assertEqual(preview_tree.kind('file2-id'), 'file')
2293
        self.assertEqual(
2294
            preview_tree.get_file('file2-id').read(), 'content B\n')
2295
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2296
    def test_diff_preview_tree(self):
2297
        revision_tree = self.create_tree()
2298
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2299
        self.addCleanup(preview.finalize)
3008.1.4 by Michael Hudson
Merge test enhancements
2300
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2301
        preview_tree = preview.get_preview_tree()
2302
        out = StringIO()
2303
        show_diff_trees(revision_tree, preview_tree, out)
3008.1.4 by Michael Hudson
Merge test enhancements
2304
        lines = out.getvalue().splitlines()
2305
        self.assertEqual(lines[0], "=== added file 'file2'")
2306
        # 3 lines of diff administrivia
2307
        self.assertEqual(lines[4], "+content B")
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2308
2309
    def test_transform_conflicts(self):
2310
        revision_tree = self.create_tree()
2311
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2312
        self.addCleanup(preview.finalize)
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2313
        preview.new_file('a', preview.root, 'content 2')
2314
        resolve_conflicts(preview)
2315
        trans_id = preview.trans_id_file_id('a-id')
2316
        self.assertEqual('a.moved', preview.final_name(trans_id))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2317
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2318
    def get_tree_and_preview_tree(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2319
        revision_tree = self.create_tree()
2320
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2321
        self.addCleanup(preview.finalize)
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2322
        a_trans_id = preview.trans_id_file_id('a-id')
2323
        preview.delete_contents(a_trans_id)
2324
        preview.create_file('b content', a_trans_id)
2325
        preview_tree = preview.get_preview_tree()
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2326
        return revision_tree, preview_tree
2327
2328
    def test_iter_changes(self):
2329
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2330
        root = revision_tree.inventory.root.file_id
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2331
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
2332
                          (root, root), ('a', 'a'), ('file', 'file'),
2333
                          (False, False))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2334
                          list(preview_tree.iter_changes(revision_tree)))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2335
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2336
    def test_include_unchanged_succeeds(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2337
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2338
        changes = preview_tree.iter_changes(revision_tree,
2339
                                            include_unchanged=True)
2340
        root = revision_tree.inventory.root.file_id
2341
2342
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2343
2344
    def test_specific_files(self):
2345
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2346
        changes = preview_tree.iter_changes(revision_tree,
2347
                                            specific_files=[''])
2348
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2349
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2350
    def test_want_unversioned(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2351
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2352
        changes = preview_tree.iter_changes(revision_tree,
2353
                                            want_unversioned=True)
2354
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2355
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2356
    def test_ignore_extra_trees_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2357
        # extra_trees is harmless without specific_files, so we'll silently
2358
        # accept it, even though we won't use it.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2359
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2360
        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
2361
2362
    def test_ignore_require_versioned_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2363
        # require_versioned is meaningless without specific_files.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2364
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2365
        preview_tree.iter_changes(revision_tree, require_versioned=False)
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2366
2367
    def test_ignore_pb(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2368
        # 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
2369
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2370
        preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2371
2372
    def test_kind(self):
2373
        revision_tree = self.create_tree()
2374
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2375
        self.addCleanup(preview.finalize)
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2376
        preview.new_file('file', preview.root, 'contents', 'file-id')
2377
        preview.new_directory('directory', preview.root, 'dir-id')
2378
        preview_tree = preview.get_preview_tree()
2379
        self.assertEqual('file', preview_tree.kind('file-id'))
2380
        self.assertEqual('directory', preview_tree.kind('dir-id'))
2381
2382
    def test_get_file_mtime(self):
2383
        preview = self.get_empty_preview()
2384
        file_trans_id = preview.new_file('file', preview.root, 'contents',
2385
                                         'file-id')
2386
        limbo_path = preview._limbo_name(file_trans_id)
2387
        preview_tree = preview.get_preview_tree()
2388
        self.assertEqual(os.stat(limbo_path).st_mtime,
2389
                         preview_tree.get_file_mtime('file-id'))
2390
4635.1.1 by Aaron Bentley
Fix OSError with renamed files in PreviewTree.
2391
    def test_get_file_mtime_renamed(self):
2392
        work_tree = self.make_branch_and_tree('tree')
2393
        self.build_tree(['tree/file'])
2394
        work_tree.add('file', 'file-id')
2395
        preview = TransformPreview(work_tree)
2396
        self.addCleanup(preview.finalize)
2397
        file_trans_id = preview.trans_id_tree_file_id('file-id')
2398
        preview.adjust_path('renamed', preview.root, file_trans_id)
2399
        preview_tree = preview.get_preview_tree()
2400
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
2401
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
2402
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2403
    def test_get_file(self):
2404
        preview = self.get_empty_preview()
2405
        preview.new_file('file', preview.root, 'contents', 'file-id')
2406
        preview_tree = preview.get_preview_tree()
2407
        tree_file = preview_tree.get_file('file-id')
2408
        try:
2409
            self.assertEqual('contents', tree_file.read())
2410
        finally:
2411
            tree_file.close()
3228.1.2 by James Henstridge
Simplify test, and move it down to be next to the other _PreviewTree tests.
2412
2413
    def test_get_symlink_target(self):
2414
        self.requireFeature(SymlinkFeature)
2415
        preview = self.get_empty_preview()
2416
        preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2417
        preview_tree = preview.get_preview_tree()
2418
        self.assertEqual('target',
2419
                         preview_tree.get_symlink_target('symlink-id'))
3363.2.18 by Aaron Bentley
Implement correct all_file_ids for PreviewTree
2420
2421
    def test_all_file_ids(self):
2422
        tree = self.make_branch_and_tree('tree')
2423
        self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2424
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2425
        preview = TransformPreview(tree)
2426
        self.addCleanup(preview.finalize)
2427
        preview.unversion_file(preview.trans_id_file_id('b-id'))
2428
        c_trans_id = preview.trans_id_file_id('c-id')
2429
        preview.unversion_file(c_trans_id)
2430
        preview.version_file('c-id', c_trans_id)
2431
        preview_tree = preview.get_preview_tree()
2432
        self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2433
                         preview_tree.all_file_ids())
3363.2.19 by Aaron Bentley
Make PreviewTree.path2id correct
2434
2435
    def test_path2id_deleted_unchanged(self):
2436
        tree = self.make_branch_and_tree('tree')
2437
        self.build_tree(['tree/unchanged', 'tree/deleted'])
2438
        tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2439
        preview = TransformPreview(tree)
2440
        self.addCleanup(preview.finalize)
2441
        preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2442
        preview_tree = preview.get_preview_tree()
2443
        self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2444
        self.assertIs(None, preview_tree.path2id('deleted'))
2445
2446
    def test_path2id_created(self):
2447
        tree = self.make_branch_and_tree('tree')
2448
        self.build_tree(['tree/unchanged'])
2449
        tree.add(['unchanged'], ['unchanged-id'])
2450
        preview = TransformPreview(tree)
2451
        self.addCleanup(preview.finalize)
2452
        preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2453
            'contents', 'new-id')
2454
        preview_tree = preview.get_preview_tree()
2455
        self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2456
2457
    def test_path2id_moved(self):
2458
        tree = self.make_branch_and_tree('tree')
2459
        self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2460
        tree.add(['old_parent', 'old_parent/child'],
2461
                 ['old_parent-id', 'child-id'])
2462
        preview = TransformPreview(tree)
2463
        self.addCleanup(preview.finalize)
2464
        new_parent = preview.new_directory('new_parent', preview.root,
2465
                                           'new_parent-id')
2466
        preview.adjust_path('child', new_parent,
2467
                            preview.trans_id_file_id('child-id'))
2468
        preview_tree = preview.get_preview_tree()
2469
        self.assertIs(None, preview_tree.path2id('old_parent/child'))
2470
        self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2471
2472
    def test_path2id_renamed_parent(self):
2473
        tree = self.make_branch_and_tree('tree')
2474
        self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2475
        tree.add(['old_name', 'old_name/child'],
2476
                 ['parent-id', 'child-id'])
2477
        preview = TransformPreview(tree)
2478
        self.addCleanup(preview.finalize)
2479
        preview.adjust_path('new_name', preview.root,
2480
                            preview.trans_id_file_id('parent-id'))
2481
        preview_tree = preview.get_preview_tree()
2482
        self.assertIs(None, preview_tree.path2id('old_name/child'))
2483
        self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
3363.2.21 by Aaron Bentley
Implement iter_entries_by_dir
2484
2485
    def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2486
        preview_tree = tt.get_preview_tree()
2487
        preview_result = list(preview_tree.iter_entries_by_dir(
2488
                              specific_file_ids))
2489
        tree = tt._tree
2490
        tt.apply()
2491
        actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2492
        self.assertEqual(actual_result, preview_result)
2493
2494
    def test_iter_entries_by_dir_new(self):
2495
        tree = self.make_branch_and_tree('tree')
2496
        tt = TreeTransform(tree)
2497
        tt.new_file('new', tt.root, 'contents', 'new-id')
2498
        self.assertMatchingIterEntries(tt)
2499
2500
    def test_iter_entries_by_dir_deleted(self):
2501
        tree = self.make_branch_and_tree('tree')
2502
        self.build_tree(['tree/deleted'])
2503
        tree.add('deleted', 'deleted-id')
2504
        tt = TreeTransform(tree)
2505
        tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2506
        self.assertMatchingIterEntries(tt)
2507
2508
    def test_iter_entries_by_dir_unversioned(self):
2509
        tree = self.make_branch_and_tree('tree')
2510
        self.build_tree(['tree/removed'])
2511
        tree.add('removed', 'removed-id')
2512
        tt = TreeTransform(tree)
2513
        tt.unversion_file(tt.trans_id_file_id('removed-id'))
2514
        self.assertMatchingIterEntries(tt)
2515
2516
    def test_iter_entries_by_dir_moved(self):
2517
        tree = self.make_branch_and_tree('tree')
2518
        self.build_tree(['tree/moved', 'tree/new_parent/'])
2519
        tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2520
        tt = TreeTransform(tree)
2521
        tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2522
                       tt.trans_id_file_id('moved-id'))
2523
        self.assertMatchingIterEntries(tt)
2524
2525
    def test_iter_entries_by_dir_specific_file_ids(self):
2526
        tree = self.make_branch_and_tree('tree')
2527
        tree.set_root_id('tree-root-id')
2528
        self.build_tree(['tree/parent/', 'tree/parent/child'])
2529
        tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2530
        tt = TreeTransform(tree)
2531
        self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
3363.2.26 by Aaron Bentley
Get symlinks working
2532
2533
    def test_symlink_content_summary(self):
2534
        self.requireFeature(SymlinkFeature)
2535
        preview = self.get_empty_preview()
2536
        preview.new_symlink('path', preview.root, 'target', 'path-id')
2537
        summary = preview.get_preview_tree().path_content_summary('path')
2538
        self.assertEqual(('symlink', None, None, 'target'), summary)
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2539
2540
    def test_missing_content_summary(self):
2541
        preview = self.get_empty_preview()
2542
        summary = preview.get_preview_tree().path_content_summary('path')
2543
        self.assertEqual(('missing', None, None, None), summary)
2544
2545
    def test_deleted_content_summary(self):
2546
        tree = self.make_branch_and_tree('tree')
2547
        self.build_tree(['tree/path/'])
2548
        tree.add('path')
2549
        preview = TransformPreview(tree)
2550
        self.addCleanup(preview.finalize)
2551
        preview.delete_contents(preview.trans_id_tree_path('path'))
2552
        summary = preview.get_preview_tree().path_content_summary('path')
2553
        self.assertEqual(('missing', None, None, None), summary)
2554
3363.2.30 by Aaron Bentley
Improve execute bit testing
2555
    def test_file_content_summary_executable(self):
2556
        preview = self.get_empty_preview()
2557
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2558
        preview.set_executability(True, path_id)
2559
        summary = preview.get_preview_tree().path_content_summary('path')
2560
        self.assertEqual(4, len(summary))
2561
        self.assertEqual('file', summary[0])
2562
        # size must be known
2563
        self.assertEqual(len('contents'), summary[1])
2564
        # executable
2565
        self.assertEqual(True, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
2566
        # will not have hash (not cheap to determine)
2567
        self.assertIs(None, summary[3])
3363.2.30 by Aaron Bentley
Improve execute bit testing
2568
2569
    def test_change_executability(self):
2570
        tree = self.make_branch_and_tree('tree')
2571
        self.build_tree(['tree/path'])
2572
        tree.add('path')
2573
        preview = TransformPreview(tree)
2574
        self.addCleanup(preview.finalize)
2575
        path_id = preview.trans_id_tree_path('path')
2576
        preview.set_executability(True, path_id)
2577
        summary = preview.get_preview_tree().path_content_summary('path')
2578
        self.assertEqual(True, summary[2])
2579
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2580
    def test_file_content_summary_non_exec(self):
2581
        preview = self.get_empty_preview()
2582
        preview.new_file('path', preview.root, 'contents', 'path-id')
2583
        summary = preview.get_preview_tree().path_content_summary('path')
2584
        self.assertEqual(4, len(summary))
2585
        self.assertEqual('file', summary[0])
2586
        # size must be known
3363.2.30 by Aaron Bentley
Improve execute bit testing
2587
        self.assertEqual(len('contents'), summary[1])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2588
        # not executable
4789.15.3 by John Arbash Meinel
PreviewTree now returns False for exec bit properly.
2589
        self.assertEqual(False, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
2590
        # will not have hash (not cheap to determine)
2591
        self.assertIs(None, summary[3])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2592
2593
    def test_dir_content_summary(self):
2594
        preview = self.get_empty_preview()
2595
        preview.new_directory('path', preview.root, 'path-id')
2596
        summary = preview.get_preview_tree().path_content_summary('path')
2597
        self.assertEqual(('directory', None, None, None), summary)
2598
2599
    def test_tree_content_summary(self):
2600
        preview = self.get_empty_preview()
2601
        path = preview.new_directory('path', preview.root, 'path-id')
2602
        preview.set_tree_reference('rev-1', path)
2603
        summary = preview.get_preview_tree().path_content_summary('path')
2604
        self.assertEqual(4, len(summary))
2605
        self.assertEqual('tree-reference', summary[0])
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
2606
2607
    def test_annotate(self):
2608
        tree = self.make_branch_and_tree('tree')
2609
        self.build_tree_contents([('tree/file', 'a\n')])
2610
        tree.add('file', 'file-id')
2611
        tree.commit('a', rev_id='one')
2612
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2613
        preview = TransformPreview(tree)
2614
        self.addCleanup(preview.finalize)
2615
        file_trans_id = preview.trans_id_file_id('file-id')
2616
        preview.delete_contents(file_trans_id)
2617
        preview.create_file('a\nb\nc\n', file_trans_id)
2618
        preview_tree = preview.get_preview_tree()
2619
        expected = [
2620
            ('one', 'a\n'),
2621
            ('me:', 'b\n'),
2622
            ('me:', 'c\n'),
2623
        ]
2624
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2625
        self.assertEqual(expected, annotation)
2626
2627
    def test_annotate_missing(self):
2628
        preview = self.get_empty_preview()
2629
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2630
        preview_tree = preview.get_preview_tree()
2631
        expected = [
2632
            ('me:', 'a\n'),
2633
            ('me:', 'b\n'),
2634
            ('me:', 'c\n'),
2635
         ]
2636
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2637
        self.assertEqual(expected, annotation)
2638
3363.7.3 by Aaron Bentley
Add test that annotate correctly handles renames
2639
    def test_annotate_rename(self):
2640
        tree = self.make_branch_and_tree('tree')
2641
        self.build_tree_contents([('tree/file', 'a\n')])
2642
        tree.add('file', 'file-id')
2643
        tree.commit('a', rev_id='one')
2644
        preview = TransformPreview(tree)
2645
        self.addCleanup(preview.finalize)
2646
        file_trans_id = preview.trans_id_file_id('file-id')
2647
        preview.adjust_path('newname', preview.root, file_trans_id)
2648
        preview_tree = preview.get_preview_tree()
2649
        expected = [
2650
            ('one', 'a\n'),
2651
        ]
2652
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2653
        self.assertEqual(expected, annotation)
2654
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
2655
    def test_annotate_deleted(self):
2656
        tree = self.make_branch_and_tree('tree')
2657
        self.build_tree_contents([('tree/file', 'a\n')])
2658
        tree.add('file', 'file-id')
2659
        tree.commit('a', rev_id='one')
2660
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2661
        preview = TransformPreview(tree)
2662
        self.addCleanup(preview.finalize)
2663
        file_trans_id = preview.trans_id_file_id('file-id')
2664
        preview.delete_contents(file_trans_id)
2665
        preview_tree = preview.get_preview_tree()
2666
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2667
        self.assertIs(None, annotation)
2668
3363.2.36 by Aaron Bentley
Fix PreviewTree.stored_kind
2669
    def test_stored_kind(self):
2670
        preview = self.get_empty_preview()
2671
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2672
        preview_tree = preview.get_preview_tree()
2673
        self.assertEqual('file', preview_tree.stored_kind('file-id'))
3363.2.37 by Aaron Bentley
Fix is_executable
2674
2675
    def test_is_executable(self):
2676
        preview = self.get_empty_preview()
2677
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2678
        preview.set_executability(True, preview.trans_id_file_id('file-id'))
2679
        preview_tree = preview.get_preview_tree()
2680
        self.assertEqual(True, preview_tree.is_executable('file-id'))
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2681
3571.1.1 by Aaron Bentley
Allow set/get of parent_ids in PreviewTree
2682
    def test_get_set_parent_ids(self):
2683
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2684
        self.assertEqual([], preview_tree.get_parent_ids())
2685
        preview_tree.set_parent_ids(['rev-1'])
2686
        self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
2687
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2688
    def test_plan_file_merge(self):
2689
        work_a = self.make_branch_and_tree('wta')
2690
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2691
        work_a.add('file', 'file-id')
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
2692
        base_id = work_a.commit('base version')
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2693
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2694
        preview = TransformPreview(work_a)
2695
        self.addCleanup(preview.finalize)
2696
        trans_id = preview.trans_id_file_id('file-id')
2697
        preview.delete_contents(trans_id)
2698
        preview.create_file('b\nc\nd\ne\n', trans_id)
2699
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2700
        tree_a = preview.get_preview_tree()
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
2701
        tree_a.set_parent_ids([base_id])
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2702
        self.assertEqual([
3363.9.5 by Aaron Bentley
Move killed-a from top to bottom
2703
            ('killed-a', 'a\n'),
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2704
            ('killed-b', 'b\n'),
2705
            ('unchanged', 'c\n'),
2706
            ('unchanged', 'd\n'),
2707
            ('new-a', 'e\n'),
2708
            ('new-b', 'f\n'),
2709
        ], 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
2710
2711
    def test_plan_file_merge_revision_tree(self):
2712
        work_a = self.make_branch_and_tree('wta')
2713
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2714
        work_a.add('file', 'file-id')
2715
        base_id = work_a.commit('base version')
2716
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2717
        preview = TransformPreview(work_a.basis_tree())
2718
        self.addCleanup(preview.finalize)
2719
        trans_id = preview.trans_id_file_id('file-id')
2720
        preview.delete_contents(trans_id)
2721
        preview.create_file('b\nc\nd\ne\n', trans_id)
2722
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2723
        tree_a = preview.get_preview_tree()
2724
        tree_a.set_parent_ids([base_id])
2725
        self.assertEqual([
2726
            ('killed-a', 'a\n'),
2727
            ('killed-b', 'b\n'),
2728
            ('unchanged', 'c\n'),
2729
            ('unchanged', 'd\n'),
2730
            ('new-a', 'e\n'),
2731
            ('new-b', 'f\n'),
2732
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
2733
2734
    def test_walkdirs(self):
2735
        preview = self.get_empty_preview()
4634.57.3 by Aaron Bentley
Fix failing test.
2736
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
2737
        # FIXME: new_directory should mark root.
4634.122.6 by John Arbash Meinel
Fix a test that used 'adjust_path' to set the root.
2738
        preview.fixup_new_roots()
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
2739
        preview_tree = preview.get_preview_tree()
2740
        file_trans_id = preview.new_file('a', preview.root, 'contents',
2741
                                         'a-id')
2742
        expected = [(('', 'tree-root'),
2743
                    [('a', 'a', 'file', None, 'a-id', 'file')])]
2744
        self.assertEqual(expected, list(preview_tree.walkdirs()))
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
2745
2746
    def test_extras(self):
2747
        work_tree = self.make_branch_and_tree('tree')
2748
        self.build_tree(['tree/removed-file', 'tree/existing-file',
2749
                         'tree/not-removed-file'])
2750
        work_tree.add(['removed-file', 'not-removed-file'])
2751
        preview = TransformPreview(work_tree)
3363.13.3 by Aaron Bentley
Add cleanup
2752
        self.addCleanup(preview.finalize)
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
2753
        preview.new_file('new-file', preview.root, 'contents')
2754
        preview.new_file('new-versioned-file', preview.root, 'contents',
2755
                         'new-versioned-id')
2756
        tree = preview.get_preview_tree()
2757
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
2758
        self.assertEqual(set(['new-file', 'removed-file', 'existing-file']),
2759
                         set(tree.extras()))
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2760
3363.17.2 by Aaron Bentley
Add text checking
2761
    def test_merge_into_preview(self):
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2762
        work_tree = self.make_branch_and_tree('tree')
3363.17.2 by Aaron Bentley
Add text checking
2763
        self.build_tree_contents([('tree/file','b\n')])
2764
        work_tree.add('file', 'file-id')
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2765
        work_tree.commit('first commit')
2766
        child_tree = work_tree.bzrdir.sprout('child').open_workingtree()
3363.17.2 by Aaron Bentley
Add text checking
2767
        self.build_tree_contents([('child/file','b\nc\n')])
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2768
        child_tree.commit('child commit')
2769
        child_tree.lock_write()
2770
        self.addCleanup(child_tree.unlock)
2771
        work_tree.lock_write()
2772
        self.addCleanup(work_tree.unlock)
2773
        preview = TransformPreview(work_tree)
2774
        self.addCleanup(preview.finalize)
3363.17.6 by Aaron Bentley
Improve test scenario
2775
        file_trans_id = preview.trans_id_file_id('file-id')
2776
        preview.delete_contents(file_trans_id)
2777
        preview.create_file('a\nb\n', file_trans_id)
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2778
        pb = progress.DummyProgress()
4634.57.2 by Aaron Bentley
Fix failing test.
2779
        preview_tree = preview.get_preview_tree()
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2780
        merger = Merger.from_revision_ids(pb, preview_tree,
2781
                                          child_tree.branch.last_revision(),
2782
                                          other_branch=child_tree.branch,
2783
                                          tree_branch=work_tree.branch)
2784
        merger.merge_type = Merge3Merger
2785
        tt = merger.make_merger().make_preview_transform()
3363.17.2 by Aaron Bentley
Add text checking
2786
        self.addCleanup(tt.finalize)
2787
        final_tree = tt.get_preview_tree()
2788
        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
2789
2790
    def test_merge_preview_into_workingtree(self):
2791
        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.
2792
        tree.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2793
        tt = TransformPreview(tree)
2794
        self.addCleanup(tt.finalize)
2795
        tt.new_file('name', tt.root, 'content', 'file-id')
2796
        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.
2797
        tree2.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2798
        pb = progress.DummyProgress()
2799
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2800
                                         pb, tree.basis_tree())
2801
        merger.merge_type = Merge3Merger
2802
        merger.do_merge()
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
2803
3363.17.21 by Aaron Bentley
Conflicts are handled when merging from preview trees
2804
    def test_merge_preview_into_workingtree_handles_conflicts(self):
2805
        tree = self.make_branch_and_tree('tree')
2806
        self.build_tree_contents([('tree/foo', 'bar')])
2807
        tree.add('foo', 'foo-id')
2808
        tree.commit('foo')
2809
        tt = TransformPreview(tree)
2810
        self.addCleanup(tt.finalize)
2811
        trans_id = tt.trans_id_file_id('foo-id')
2812
        tt.delete_contents(trans_id)
2813
        tt.create_file('baz', trans_id)
2814
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2815
        self.build_tree_contents([('tree2/foo', 'qux')])
2816
        pb = progress.DummyProgress()
2817
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2818
                                         pb, tree.basis_tree())
2819
        merger.merge_type = Merge3Merger
2820
        merger.do_merge()
2821
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
2822
    def test_is_executable(self):
2823
        tree = self.make_branch_and_tree('tree')
2824
        preview = TransformPreview(tree)
2825
        self.addCleanup(preview.finalize)
2826
        preview.new_file('foo', preview.root, 'bar', 'baz-id')
2827
        preview_tree = preview.get_preview_tree()
2828
        self.assertEqual(False, preview_tree.is_executable('baz-id',
2829
                                                           'tree/foo'))
2830
        self.assertEqual(False, preview_tree.is_executable('baz-id'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2831
4354.4.4 by Aaron Bentley
Simplify by using CommitBuilder directly
2832
    def test_commit_preview_tree(self):
2833
        tree = self.make_branch_and_tree('tree')
2834
        rev_id = tree.commit('rev1')
2835
        tree.branch.lock_write()
2836
        self.addCleanup(tree.branch.unlock)
2837
        tt = TransformPreview(tree)
2838
        tt.new_file('file', tt.root, 'contents', 'file_id')
2839
        self.addCleanup(tt.finalize)
2840
        preview = tt.get_preview_tree()
2841
        preview.set_parent_ids([rev_id])
2842
        builder = tree.branch.get_commit_builder([rev_id])
2843
        list(builder.record_iter_changes(preview, rev_id, tt.iter_changes()))
2844
        builder.finish_inventory()
2845
        rev2_id = builder.commit('rev2')
2846
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
2847
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
2848
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2849
    def test_ascii_limbo_paths(self):
4634.79.2 by Aaron Bentley
Avoid runing test on non-unicode filesystems.
2850
        self.requireFeature(tests.UnicodeFilenameFeature)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2851
        branch = self.make_branch('any')
2852
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
2853
        tt = TransformPreview(tree)
4789.25.7 by John Arbash Meinel
We can run the executable tests.
2854
        self.addCleanup(tt.finalize)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2855
        foo_id = tt.new_directory('', ROOT_PARENT)
2856
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
2857
        limbo_path = tt._limbo_name(bar_id)
2858
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
2859
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2860
0.13.13 by Aaron Bentley
Add direct test of serialization records
2861
class FakeSerializer(object):
2862
    """Serializer implementation that simply returns the input.
2863
2864
    The input is returned in the order used by pack.ContainerPushParser.
2865
    """
2866
    @staticmethod
2867
    def bytes_record(bytes, names):
2868
        return names, bytes
2869
2870
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2871
class TestSerializeTransform(tests.TestCaseWithTransport):
2872
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
2873
    _test_needs_features = [tests.UnicodeFilenameFeature]
2874
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2875
    def get_preview(self, tree=None):
2876
        if tree is None:
2877
            tree = self.make_branch_and_tree('tree')
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2878
        tt = TransformPreview(tree)
2879
        self.addCleanup(tt.finalize)
2880
        return tt
2881
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2882
    def assertSerializesTo(self, expected, tt):
2883
        records = list(tt.serialize(FakeSerializer()))
2884
        self.assertEqual(expected, records)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2885
0.13.13 by Aaron Bentley
Add direct test of serialization records
2886
    @staticmethod
2887
    def default_attribs():
2888
        return {
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2889
            '_id_number': 1,
0.13.13 by Aaron Bentley
Add direct test of serialization records
2890
            '_new_name': {},
2891
            '_new_parent': {},
2892
            '_new_executability': {},
2893
            '_new_id': {},
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2894
            '_tree_path_ids': {'': 'new-0'},
0.13.13 by Aaron Bentley
Add direct test of serialization records
2895
            '_removed_id': [],
2896
            '_removed_contents': [],
2897
            '_non_present_ids': {},
2898
            }
2899
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2900
    def make_records(self, attribs, contents):
2901
        records = [
2902
            (((('attribs'),),), bencode.bencode(attribs))]
2903
        records.extend([(((n, k),), c) for n, k, c in contents])
2904
        return records
2905
0.13.13 by Aaron Bentley
Add direct test of serialization records
2906
    def creation_records(self):
2907
        attribs = self.default_attribs()
2908
        attribs['_id_number'] = 3
2909
        attribs['_new_name'] = {
2910
            'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
2911
        attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
2912
        attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
2913
        attribs['_new_executability'] = {'new-1': 1}
2914
        contents = [
2915
            ('new-1', 'file', 'i 1\nbar\n'),
2916
            ('new-2', 'directory', ''),
2917
            ]
2918
        return self.make_records(attribs, contents)
2919
2920
    def test_serialize_creation(self):
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2921
        tt = self.get_preview()
0.13.13 by Aaron Bentley
Add direct test of serialization records
2922
        tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
2923
        tt.new_directory('qux', tt.root, 'quxx')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
2924
        self.assertSerializesTo(self.creation_records(), tt)
0.13.13 by Aaron Bentley
Add direct test of serialization records
2925
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2926
    def test_deserialize_creation(self):
2927
        tt = self.get_preview()
2928
        tt.deserialize(iter(self.creation_records()))
2929
        self.assertEqual(3, tt._id_number)
2930
        self.assertEqual({'new-1': u'foo\u1234',
2931
                          'new-2': 'qux'}, tt._new_name)
2932
        self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
2933
        self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
2934
        self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
2935
        self.assertEqual({'new-1': True}, tt._new_executability)
2936
        self.assertEqual({'new-1': 'file',
2937
                          'new-2': 'directory'}, tt._new_contents)
2938
        foo_limbo = open(tt._limbo_name('new-1'), 'rb')
2939
        try:
2940
            foo_content = foo_limbo.read()
2941
        finally:
2942
            foo_limbo.close()
2943
        self.assertEqual('bar', foo_content)
2944
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2945
    def symlink_creation_records(self):
2946
        attribs = self.default_attribs()
2947
        attribs['_id_number'] = 2
2948
        attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
2949
        attribs['_new_parent'] = {'new-1': 'new-0'}
2950
        contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
2951
        return self.make_records(attribs, contents)
2952
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2953
    def test_serialize_symlink_creation(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2954
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2955
        tt = self.get_preview()
0.13.16 by Aaron Bentley
Add unicode symlink targets to tests
2956
        tt.new_symlink(u'foo\u1234', tt.root, u'bar\u1234')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
2957
        self.assertSerializesTo(self.symlink_creation_records(), tt)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2958
2959
    def test_deserialize_symlink_creation(self):
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
2960
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2961
        tt = self.get_preview()
2962
        tt.deserialize(iter(self.symlink_creation_records()))
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
2963
        abspath = tt._limbo_name('new-1')
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
2964
        foo_content = osutils.readlink(abspath)
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
2965
        self.assertEqual(u'bar\u1234', foo_content)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2966
0.13.19 by Aaron Bentley
Clean up serialization tests
2967
    def make_destruction_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2968
        tree = self.make_branch_and_tree('.')
2969
        self.build_tree([u'foo\u1234', 'bar'])
2970
        tree.add([u'foo\u1234', 'bar'], ['foo-id', 'bar-id'])
0.13.19 by Aaron Bentley
Clean up serialization tests
2971
        return self.get_preview(tree)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2972
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2973
    def destruction_records(self):
2974
        attribs = self.default_attribs()
2975
        attribs['_id_number'] = 3
2976
        attribs['_removed_id'] = ['new-1']
2977
        attribs['_removed_contents'] = ['new-2']
2978
        attribs['_tree_path_ids'] = {
2979
            '': 'new-0',
2980
            u'foo\u1234'.encode('utf-8'): 'new-1',
2981
            'bar': 'new-2',
2982
            }
2983
        return self.make_records(attribs, [])
2984
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2985
    def test_serialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
2986
        tt = self.make_destruction_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2987
        foo_trans_id = tt.trans_id_tree_file_id('foo-id')
2988
        tt.unversion_file(foo_trans_id)
2989
        bar_trans_id = tt.trans_id_tree_file_id('bar-id')
2990
        tt.delete_contents(bar_trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2991
        self.assertSerializesTo(self.destruction_records(), tt)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2992
2993
    def test_deserialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
2994
        tt = self.make_destruction_preview()
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2995
        tt.deserialize(iter(self.destruction_records()))
2996
        self.assertEqual({u'foo\u1234': 'new-1',
2997
                          'bar': 'new-2',
2998
                          '': tt.root}, tt._tree_path_ids)
2999
        self.assertEqual({'new-1': u'foo\u1234',
3000
                          'new-2': 'bar',
3001
                          tt.root: ''}, tt._tree_id_paths)
3002
        self.assertEqual(set(['new-1']), tt._removed_id)
3003
        self.assertEqual(set(['new-2']), tt._removed_contents)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3004
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3005
    def missing_records(self):
3006
        attribs = self.default_attribs()
3007
        attribs['_id_number'] = 2
3008
        attribs['_non_present_ids'] = {
3009
            'boo': 'new-1',}
3010
        return self.make_records(attribs, [])
3011
3012
    def test_serialize_missing(self):
3013
        tt = self.get_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3014
        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
3015
        self.assertSerializesTo(self.missing_records(), tt)
3016
3017
    def test_deserialize_missing(self):
3018
        tt = self.get_preview()
3019
        tt.deserialize(iter(self.missing_records()))
3020
        self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
3021
3022
    def make_modification_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3023
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3024
        LINES_TWO = 'z\nbb\nx\ndd\n'
3025
        tree = self.make_branch_and_tree('tree')
3026
        self.build_tree_contents([('tree/file', LINES_ONE)])
3027
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3028
        return self.get_preview(tree), LINES_TWO
3029
3030
    def modification_records(self):
3031
        attribs = self.default_attribs()
3032
        attribs['_id_number'] = 2
3033
        attribs['_tree_path_ids'] = {
3034
            'file': 'new-1',
3035
            '': 'new-0',}
3036
        attribs['_removed_contents'] = ['new-1']
3037
        contents = [('new-1', 'file',
3038
                     'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
3039
        return self.make_records(attribs, contents)
3040
3041
    def test_serialize_modification(self):
3042
        tt, LINES = self.make_modification_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3043
        trans_id = tt.trans_id_file_id('file-id')
3044
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3045
        tt.create_file(LINES, trans_id)
3046
        self.assertSerializesTo(self.modification_records(), tt)
3047
3048
    def test_deserialize_modification(self):
3049
        tt, LINES = self.make_modification_preview()
3050
        tt.deserialize(iter(self.modification_records()))
3051
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3052
3053
    def make_kind_change_preview(self):
3054
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3055
        tree = self.make_branch_and_tree('tree')
3056
        self.build_tree(['tree/foo/'])
3057
        tree.add('foo', 'foo-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3058
        return self.get_preview(tree), LINES
3059
3060
    def kind_change_records(self):
3061
        attribs = self.default_attribs()
3062
        attribs['_id_number'] = 2
3063
        attribs['_tree_path_ids'] = {
3064
            'foo': 'new-1',
3065
            '': 'new-0',}
3066
        attribs['_removed_contents'] = ['new-1']
3067
        contents = [('new-1', 'file',
3068
                     'i 4\na\nb\nc\nd\n\n')]
3069
        return self.make_records(attribs, contents)
3070
3071
    def test_serialize_kind_change(self):
3072
        tt, LINES = self.make_kind_change_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3073
        trans_id = tt.trans_id_file_id('foo-id')
3074
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3075
        tt.create_file(LINES, trans_id)
3076
        self.assertSerializesTo(self.kind_change_records(), tt)
3077
3078
    def test_deserialize_kind_change(self):
3079
        tt, LINES = self.make_kind_change_preview()
3080
        tt.deserialize(iter(self.kind_change_records()))
3081
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3082
3083
    def make_add_contents_preview(self):
3084
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3085
        tree = self.make_branch_and_tree('tree')
3086
        self.build_tree(['tree/foo'])
3087
        tree.add('foo')
3088
        os.unlink('tree/foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3089
        return self.get_preview(tree), LINES
3090
3091
    def add_contents_records(self):
3092
        attribs = self.default_attribs()
3093
        attribs['_id_number'] = 2
3094
        attribs['_tree_path_ids'] = {
3095
            'foo': 'new-1',
3096
            '': 'new-0',}
3097
        contents = [('new-1', 'file',
3098
                     'i 4\na\nb\nc\nd\n\n')]
3099
        return self.make_records(attribs, contents)
3100
3101
    def test_serialize_add_contents(self):
3102
        tt, LINES = self.make_add_contents_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3103
        trans_id = tt.trans_id_tree_path('foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3104
        tt.create_file(LINES, trans_id)
3105
        self.assertSerializesTo(self.add_contents_records(), tt)
3106
3107
    def test_deserialize_add_contents(self):
3108
        tt, LINES = self.make_add_contents_preview()
3109
        tt.deserialize(iter(self.add_contents_records()))
3110
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3111
3112
    def test_get_parents_lines(self):
3113
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3114
        LINES_TWO = 'z\nbb\nx\ndd\n'
3115
        tree = self.make_branch_and_tree('tree')
3116
        self.build_tree_contents([('tree/file', LINES_ONE)])
3117
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3118
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3119
        trans_id = tt.trans_id_tree_path('file')
3120
        self.assertEqual((['aa\n', 'bb\n', 'cc\n', 'dd\n'],),
3121
            tt._get_parents_lines(trans_id))
3122
3123
    def test_get_parents_texts(self):
3124
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3125
        LINES_TWO = 'z\nbb\nx\ndd\n'
3126
        tree = self.make_branch_and_tree('tree')
3127
        self.build_tree_contents([('tree/file', LINES_ONE)])
3128
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3129
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3130
        trans_id = tt.trans_id_tree_path('file')
3131
        self.assertEqual((LINES_ONE,),
3132
            tt._get_parents_texts(trans_id))