/brz/remove-bazaar

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