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