/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
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
18
import stat
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
19
from StringIO import StringIO
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
20
import sys
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
21
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
22
from bzrlib import (
2694.5.4 by Jelmer Vernooij
Move bzrlib.util.bencode to bzrlib._bencode_py.
23
    bencode,
2090.2.1 by Martin Pool
Fix some code which relies on assertions and breaks under python -O
24
    errors,
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
25
    generate_ids,
3199.1.4 by Vincent Ladeuil
Fix 16 leaked tmp dirs. Probably indicates a lock handling problem with TransformPreview
26
    osutils,
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
27
    progress,
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
28
    revision as _mod_revision,
2255.7.48 by Robert Collins
Deprecated and make work with DirState trees 'transform.find_interesting'.
29
    symbol_versioning,
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
30
    tests,
31
    urlutils,
32
    )
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
33
from bzrlib.bzrdir import BzrDir
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
34
from bzrlib.conflicts import (DuplicateEntry, DuplicateID, MissingParent,
3144.4.2 by Aaron Bentley
Handle non-directory parent conflicts (abentley, #177390)
35
                              UnversionedParent, ParentLoop, DeletingParent,
36
                              NonDirectoryParent)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
37
from bzrlib.diff import show_diff_trees
1534.7.32 by Aaron Bentley
Got conflict handling working when conflicts involve existing files
38
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
39
                           ReusingTransform, CantMoveRoot,
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
40
                           PathsNotVersionedError, ExistingLimbo,
2733.2.11 by Aaron Bentley
Detect irregularities with the pending-deletion directory
41
                           ExistingPendingDeletion, ImmortalLimbo,
42
                           ImmortalPendingDeletion, LockError)
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
43
from bzrlib.osutils import file_kind, pathjoin
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
44
from bzrlib.merge import Merge3Merger, Merger
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
45
from bzrlib.tests import (
3136.1.1 by Aaron Bentley
Add support for hardlinks to TreeTransform
46
    HardlinkFeature,
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
47
    SymlinkFeature,
48
    TestCase,
49
    TestCaseInTempDir,
50
    TestSkipped,
51
    )
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
52
from bzrlib.transform import (TreeTransform, ROOT_PARENT, FinalPaths,
53
                              resolve_conflicts, cook_conflicts,
3400.3.6 by Martin Pool
Remove code deprecated prior to 1.1 and its tests
54
                              build_tree, get_backup_name,
55
                              _FileMover, resolve_checkout,
3363.17.24 by Aaron Bentley
Implement create_by_tree
56
                              TransformPreview, create_from_tree)
0.13.13 by Aaron Bentley
Add direct test of serialization records
57
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
58
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
59
class TestTreeTransform(tests.TestCaseWithTransport):
1740.2.4 by Aaron Bentley
Update transform tests and docs
60
1534.7.59 by Aaron Bentley
Simplified tests
61
    def setUp(self):
62
        super(TestTreeTransform, self).setUp()
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
63
        self.wt = self.make_branch_and_tree('.', format='dirstate-with-subtree')
1534.7.161 by Aaron Bentley
Used appropriate control_files
64
        os.chdir('..')
1534.7.59 by Aaron Bentley
Simplified tests
65
66
    def get_transform(self):
67
        transform = TreeTransform(self.wt)
3453.2.7 by Aaron Bentley
Remove test kipple
68
        self.addCleanup(transform.finalize)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
69
        return transform, transform.root
1534.7.59 by Aaron Bentley
Simplified tests
70
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
71
    def test_existing_limbo(self):
72
        transform, root = self.get_transform()
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
73
        limbo_name = transform._limbodir
74
        deletion_path = transform._deletiondir
1534.7.176 by abentley
Fixed up tests for Windows
75
        os.mkdir(pathjoin(limbo_name, 'hehe'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
76
        self.assertRaises(ImmortalLimbo, transform.apply)
77
        self.assertRaises(LockError, self.wt.unlock)
78
        self.assertRaises(ExistingLimbo, self.get_transform)
79
        self.assertRaises(LockError, self.wt.unlock)
1534.7.176 by abentley
Fixed up tests for Windows
80
        os.rmdir(pathjoin(limbo_name, 'hehe'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
81
        os.rmdir(limbo_name)
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
82
        os.rmdir(deletion_path)
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
83
        transform, root = self.get_transform()
84
        transform.apply()
1534.7.59 by Aaron Bentley
Simplified tests
85
2733.2.11 by Aaron Bentley
Detect irregularities with the pending-deletion directory
86
    def test_existing_pending_deletion(self):
87
        transform, root = self.get_transform()
88
        deletion_path = self._limbodir = urlutils.local_path_from_url(
3407.2.8 by Martin Pool
Deprecate LockableFiles.controlfilename
89
            transform._tree._transport.abspath('pending-deletion'))
2733.2.11 by Aaron Bentley
Detect irregularities with the pending-deletion directory
90
        os.mkdir(pathjoin(deletion_path, 'blocking-directory'))
91
        self.assertRaises(ImmortalPendingDeletion, transform.apply)
92
        self.assertRaises(LockError, self.wt.unlock)
93
        self.assertRaises(ExistingPendingDeletion, self.get_transform)
94
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
95
    def test_build(self):
3034.2.1 by Aaron Bentley
Fix is_executable tests for win32
96
        transform, root = self.get_transform()
97
        self.wt.lock_tree_write()
98
        self.addCleanup(self.wt.unlock)
1534.7.59 by Aaron Bentley
Simplified tests
99
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
100
        imaginary_id = transform.trans_id_tree_path('imaginary')
1534.10.32 by Aaron Bentley
Test and fix case where name has trailing slash
101
        imaginary_id2 = transform.trans_id_tree_path('imaginary/')
102
        self.assertEqual(imaginary_id, imaginary_id2)
1534.7.59 by Aaron Bentley
Simplified tests
103
        self.assertEqual(transform.get_tree_parent(imaginary_id), root)
104
        self.assertEqual(transform.final_kind(root), 'directory')
105
        self.assertEqual(transform.final_file_id(root), self.wt.get_root_id())
106
        trans_id = transform.create_path('name', root)
107
        self.assertIs(transform.final_file_id(trans_id), None)
108
        self.assertRaises(NoSuchFile, transform.final_kind, trans_id)
109
        transform.create_file('contents', trans_id)
110
        transform.set_executability(True, trans_id)
111
        transform.version_file('my_pretties', trans_id)
112
        self.assertRaises(DuplicateKey, transform.version_file,
113
                          'my_pretties', trans_id)
114
        self.assertEqual(transform.final_file_id(trans_id), 'my_pretties')
115
        self.assertEqual(transform.final_parent(trans_id), root)
116
        self.assertIs(transform.final_parent(root), ROOT_PARENT)
117
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
118
        oz_id = transform.create_path('oz', root)
119
        transform.create_directory(oz_id)
120
        transform.version_file('ozzie', oz_id)
121
        trans_id2 = transform.create_path('name2', root)
122
        transform.create_file('contents', trans_id2)
123
        transform.set_executability(False, trans_id2)
124
        transform.version_file('my_pretties2', trans_id2)
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
125
        modified_paths = transform.apply().modified_paths
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
126
        self.assertEqual('contents', self.wt.get_file_byname('name').read())
1534.7.59 by Aaron Bentley
Simplified tests
127
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
128
        self.assertIs(self.wt.is_executable('my_pretties'), True)
129
        self.assertIs(self.wt.is_executable('my_pretties2'), False)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
130
        self.assertEqual('directory', file_kind(self.wt.abspath('oz')))
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
131
        self.assertEqual(len(modified_paths), 3)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
132
        tree_mod_paths = [self.wt.id2abspath(f) for f in
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
133
                          ('ozzie', 'my_pretties', 'my_pretties2')]
134
        self.assertSubset(tree_mod_paths, modified_paths)
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
135
        # is it safe to finalize repeatedly?
136
        transform.finalize()
1534.7.59 by Aaron Bentley
Simplified tests
137
        transform.finalize()
1534.7.2 by Aaron Bentley
Added convenience function
138
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
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1871
    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.
1872
        if (tests.CaseInsensitiveFilesystemFeature.available()
1873
            or tests.CaseInsCasePresFilenameFeature.available()):
4241.9.4 by Vincent Ladeuil
Fix test_case_insensitive_build_tree_inventory failure on OSX.
1874
            raise tests.UnavailableFeature('Fully case sensitive filesystem')
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1875
        source = self.make_branch_and_tree('source')
1876
        self.build_tree(['source/file', 'source/FILE'])
1877
        source.add(['file', 'FILE'], ['lower-id', 'upper-id'])
1878
        source.commit('added files')
1879
        # Don't try this at home, kids!
1880
        # Force the tree to report that it is case insensitive
1881
        target = self.make_branch_and_tree('target')
1882
        target.case_sensitive = False
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
1883
        build_tree(source.basis_tree(), target, source, delta_from_tree=True)
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1884
        self.assertEqual('file.moved', target.id2path('lower-id'))
1885
        self.assertEqual('FILE', target.id2path('upper-id'))
1886
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1887
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
1888
class TestCommitTransform(tests.TestCaseWithTransport):
1889
1890
    def get_branch(self):
1891
        tree = self.make_branch_and_tree('tree')
1892
        tree.lock_write()
1893
        self.addCleanup(tree.unlock)
1894
        tree.commit('empty commit')
1895
        return tree.branch
1896
1897
    def get_branch_and_transform(self):
1898
        branch = self.get_branch()
1899
        tt = TransformPreview(branch.basis_tree())
1900
        self.addCleanup(tt.finalize)
1901
        return branch, tt
1902
1903
    def test_commit_wrong_basis(self):
1904
        branch = self.get_branch()
1905
        basis = branch.repository.revision_tree(
1906
            _mod_revision.NULL_REVISION)
1907
        tt = TransformPreview(basis)
1908
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
1909
        e = self.assertRaises(ValueError, tt.commit, branch, '')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
1910
        self.assertEqual('TreeTransform not based on branch basis: null:',
1911
                         str(e))
1912
1913
    def test_empy_commit(self):
1914
        branch, tt = self.get_branch_and_transform()
1915
        rev = tt.commit(branch, 'my message')
1916
        self.assertEqual(2, branch.revno())
1917
        repo = branch.repository
1918
        self.assertEqual('my message', repo.get_revision(rev).message)
1919
1920
    def test_merge_parents(self):
1921
        branch, tt = self.get_branch_and_transform()
1922
        rev = tt.commit(branch, 'my message', ['rev1b', 'rev1c'])
1923
        self.assertEqual(['rev1b', 'rev1c'],
1924
                         branch.basis_tree().get_parent_ids()[1:])
1925
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
1926
    def test_first_commit(self):
1927
        branch = self.make_branch('branch')
1928
        branch.lock_write()
1929
        self.addCleanup(branch.unlock)
1930
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
1931
        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.
1932
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
1933
        rev = tt.commit(branch, 'my message')
1934
        self.assertEqual([], branch.basis_tree().get_parent_ids())
4526.8.5 by Aaron Bentley
Updates from review.
1935
        self.assertNotEqual(_mod_revision.NULL_REVISION,
1936
                            branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
1937
4526.8.5 by Aaron Bentley
Updates from review.
1938
    def test_first_commit_with_merge_parents(self):
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
1939
        branch = self.make_branch('branch')
1940
        branch.lock_write()
1941
        self.addCleanup(branch.unlock)
1942
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
1943
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
1944
        e = self.assertRaises(ValueError, tt.commit, branch,
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
1945
                          'my message', ['rev1b-id'])
4526.8.5 by Aaron Bentley
Updates from review.
1946
        self.assertEqual('Cannot supply merge parents for first commit.',
1947
                         str(e))
1948
        self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
1949
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
1950
    def test_add_files(self):
1951
        branch, tt = self.get_branch_and_transform()
1952
        tt.new_file('file', tt.root, 'contents', 'file-id')
1953
        trans_id = tt.new_directory('dir', tt.root, 'dir-id')
1954
        tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
1955
        rev = tt.commit(branch, 'message')
1956
        tree = branch.basis_tree()
1957
        self.assertEqual('file', tree.id2path('file-id'))
1958
        self.assertEqual('contents', tree.get_file_text('file-id'))
1959
        self.assertEqual('dir', tree.id2path('dir-id'))
1960
        self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
1961
        self.assertEqual('target', tree.get_symlink_target('symlink-id'))
1962
4526.8.2 by Aaron Bentley
Proved strict commit handling.
1963
    def test_add_unversioned(self):
1964
        branch, tt = self.get_branch_and_transform()
1965
        tt.new_file('file', tt.root, 'contents')
1966
        self.assertRaises(errors.StrictCommitFailed, tt.commit, branch,
1967
                          'message', strict=True)
1968
1969
    def test_modify_strict(self):
1970
        branch, tt = self.get_branch_and_transform()
1971
        tt.new_file('file', tt.root, 'contents', 'file-id')
1972
        tt.commit(branch, 'message', strict=True)
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.8.2 by Aaron Bentley
Proved strict commit handling.
1975
        trans_id = tt.trans_id_file_id('file-id')
1976
        tt.delete_contents(trans_id)
1977
        tt.create_file('contents', trans_id)
1978
        tt.commit(branch, 'message', strict=True)
1979
4526.8.6 by Aaron Bentley
Check for malformed transforms before committing.
1980
    def test_commit_malformed(self):
1981
        """Committing a malformed transform should raise an exception.
1982
1983
        In this case, we are adding a file without adding its parent.
1984
        """
1985
        branch, tt = self.get_branch_and_transform()
1986
        parent_id = tt.trans_id_file_id('parent-id')
1987
        tt.new_file('file', parent_id, 'contents', 'file-id')
1988
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
1989
                          'message')
1990
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
1991
1534.10.28 by Aaron Bentley
Use numbered backup files
1992
class MockTransform(object):
1993
1994
    def has_named_child(self, by_parent, parent_id, name):
1995
        for child_id in by_parent[parent_id]:
1996
            if child_id == '0':
1997
                if name == "name~":
1998
                    return True
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
1999
            elif name == "name.~%s~" % child_id:
1534.10.28 by Aaron Bentley
Use numbered backup files
2000
                return True
2001
        return False
2002
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
2003
1534.10.28 by Aaron Bentley
Use numbered backup files
2004
class MockEntry(object):
2005
    def __init__(self):
2006
        object.__init__(self)
2007
        self.name = "name"
2008
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
2009
1534.10.28 by Aaron Bentley
Use numbered backup files
2010
class TestGetBackupName(TestCase):
2011
    def test_get_backup_name(self):
2012
        tt = MockTransform()
2013
        name = get_backup_name(MockEntry(), {'a':[]}, 'a', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2014
        self.assertEqual(name, 'name.~1~')
2015
        name = get_backup_name(MockEntry(), {'a':['1']}, 'a', tt)
2016
        self.assertEqual(name, 'name.~2~')
1534.10.28 by Aaron Bentley
Use numbered backup files
2017
        name = get_backup_name(MockEntry(), {'a':['2']}, 'a', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2018
        self.assertEqual(name, 'name.~1~')
1534.10.28 by Aaron Bentley
Use numbered backup files
2019
        name = get_backup_name(MockEntry(), {'a':['2'], 'b':[]}, 'b', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2020
        self.assertEqual(name, 'name.~1~')
2021
        name = get_backup_name(MockEntry(), {'a':['1', '2', '3']}, 'a', tt)
2022
        self.assertEqual(name, 'name.~4~')
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2023
2024
2025
class TestFileMover(tests.TestCaseWithTransport):
2026
2027
    def test_file_mover(self):
2028
        self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
2029
        mover = _FileMover()
2030
        mover.rename('a', 'q')
2031
        self.failUnlessExists('q')
2032
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2033
        self.failUnlessExists('q/b')
2034
        self.failUnlessExists('c')
2035
        self.failUnlessExists('c/d')
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2036
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2037
    def test_pre_delete_rollback(self):
2038
        self.build_tree(['a/'])
2039
        mover = _FileMover()
2040
        mover.pre_delete('a', 'q')
2041
        self.failUnlessExists('q')
2042
        self.failIfExists('a')
2043
        mover.rollback()
2044
        self.failIfExists('q')
2045
        self.failUnlessExists('a')
2046
2047
    def test_apply_deletions(self):
2733.2.12 by Aaron Bentley
Updates from review
2048
        self.build_tree(['a/', 'b/'])
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2049
        mover = _FileMover()
2050
        mover.pre_delete('a', 'q')
2733.2.12 by Aaron Bentley
Updates from review
2051
        mover.pre_delete('b', 'r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2052
        self.failUnlessExists('q')
2733.2.12 by Aaron Bentley
Updates from review
2053
        self.failUnlessExists('r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2054
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2055
        self.failIfExists('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2056
        mover.apply_deletions()
2057
        self.failIfExists('q')
2733.2.12 by Aaron Bentley
Updates from review
2058
        self.failIfExists('r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2059
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2060
        self.failIfExists('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2061
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2062
    def test_file_mover_rollback(self):
2063
        self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
2064
        mover = _FileMover()
2065
        mover.rename('c/d', 'c/f')
2066
        mover.rename('c/e', 'c/d')
2067
        try:
2068
            mover.rename('a', 'c')
3063.1.3 by Aaron Bentley
Update for Linux
2069
        except errors.FileExists, e:
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2070
            mover.rollback()
2071
        self.failUnlessExists('a')
2072
        self.failUnlessExists('c/d')
2733.2.3 by Aaron Bentley
Test tranform rollback
2073
2074
2075
class Bogus(Exception):
2076
    pass
2077
2078
2079
class TestTransformRollback(tests.TestCaseWithTransport):
2080
2081
    class ExceptionFileMover(_FileMover):
2082
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2083
        def __init__(self, bad_source=None, bad_target=None):
2084
            _FileMover.__init__(self)
2085
            self.bad_source = bad_source
2086
            self.bad_target = bad_target
2087
2733.2.3 by Aaron Bentley
Test tranform rollback
2088
        def rename(self, source, target):
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2089
            if (self.bad_source is not None and
2090
                source.endswith(self.bad_source)):
2091
                raise Bogus
2092
            elif (self.bad_target is not None and
2093
                target.endswith(self.bad_target)):
2733.2.3 by Aaron Bentley
Test tranform rollback
2094
                raise Bogus
2095
            else:
2096
                _FileMover.rename(self, source, target)
2097
2098
    def test_rollback_rename(self):
2099
        tree = self.make_branch_and_tree('.')
2100
        self.build_tree(['a/', 'a/b'])
2101
        tt = TreeTransform(tree)
2102
        self.addCleanup(tt.finalize)
2103
        a_id = tt.trans_id_tree_path('a')
2104
        tt.adjust_path('c', tt.root, a_id)
2105
        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
2106
        self.assertRaises(Bogus, tt.apply,
2107
                          _mover=self.ExceptionFileMover(bad_source='a'))
2108
        self.failUnlessExists('a')
2109
        self.failUnlessExists('a/b')
2110
        tt.apply()
2111
        self.failUnlessExists('c')
2112
        self.failUnlessExists('c/d')
2113
2114
    def test_rollback_rename_into_place(self):
2115
        tree = self.make_branch_and_tree('.')
2116
        self.build_tree(['a/', 'a/b'])
2117
        tt = TreeTransform(tree)
2118
        self.addCleanup(tt.finalize)
2119
        a_id = tt.trans_id_tree_path('a')
2120
        tt.adjust_path('c', tt.root, a_id)
2121
        tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
2122
        self.assertRaises(Bogus, tt.apply,
2123
                          _mover=self.ExceptionFileMover(bad_target='c/d'))
2124
        self.failUnlessExists('a')
2125
        self.failUnlessExists('a/b')
2126
        tt.apply()
2127
        self.failUnlessExists('c')
2128
        self.failUnlessExists('c/d')
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
2129
2130
    def test_rollback_deletion(self):
2131
        tree = self.make_branch_and_tree('.')
2132
        self.build_tree(['a/', 'a/b'])
2133
        tt = TreeTransform(tree)
2134
        self.addCleanup(tt.finalize)
2135
        a_id = tt.trans_id_tree_path('a')
2136
        tt.delete_contents(a_id)
2137
        tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
2138
        self.assertRaises(Bogus, tt.apply,
2139
                          _mover=self.ExceptionFileMover(bad_target='d'))
2140
        self.failUnlessExists('a')
2141
        self.failUnlessExists('a/b')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2142
1551.19.6 by Aaron Bentley
Revert doesn't crash restoring a file from a deleted directory
2143
    def test_resolve_no_parent(self):
2144
        wt = self.make_branch_and_tree('.')
2145
        tt = TreeTransform(wt)
2146
        self.addCleanup(tt.finalize)
2147
        parent = tt.trans_id_file_id('parent-id')
2148
        tt.new_file('file', parent, 'Contents')
2149
        resolve_conflicts(tt)
3008.1.13 by Michael Hudson
merge bzr.dev
2150
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2151
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2152
A_ENTRY = ('a-id', ('a', 'a'), True, (True, True),
2153
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2154
                  (False, False))
2155
ROOT_ENTRY = ('TREE_ROOT', ('', ''), False, (True, True), (None, None),
2156
              ('', ''), ('directory', 'directory'), (False, None))
2157
2158
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2159
class TestTransformPreview(tests.TestCaseWithTransport):
2160
2161
    def create_tree(self):
2162
        tree = self.make_branch_and_tree('.')
2163
        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.
2164
        tree.set_root_id('TREE_ROOT')
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2165
        tree.add('a', 'a-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2166
        tree.commit('rev1', rev_id='rev1')
2167
        return tree.branch.repository.revision_tree('rev1')
2168
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2169
    def get_empty_preview(self):
2170
        repository = self.make_repository('repo')
2171
        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
2172
        preview = TransformPreview(tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2173
        self.addCleanup(preview.finalize)
3199.1.4 by Vincent Ladeuil
Fix 16 leaked tmp dirs. Probably indicates a lock handling problem with TransformPreview
2174
        return preview
2175
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2176
    def test_transform_preview(self):
2177
        revision_tree = self.create_tree()
2178
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2179
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2180
2181
    def test_transform_preview_tree(self):
2182
        revision_tree = self.create_tree()
2183
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2184
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2185
        preview.get_preview_tree()
2186
3008.1.5 by Michael Hudson
a more precise test
2187
    def test_transform_new_file(self):
2188
        revision_tree = self.create_tree()
2189
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2190
        self.addCleanup(preview.finalize)
3008.1.5 by Michael Hudson
a more precise test
2191
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2192
        preview_tree = preview.get_preview_tree()
2193
        self.assertEqual(preview_tree.kind('file2-id'), 'file')
2194
        self.assertEqual(
2195
            preview_tree.get_file('file2-id').read(), 'content B\n')
2196
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2197
    def test_diff_preview_tree(self):
2198
        revision_tree = self.create_tree()
2199
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2200
        self.addCleanup(preview.finalize)
3008.1.4 by Michael Hudson
Merge test enhancements
2201
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2202
        preview_tree = preview.get_preview_tree()
2203
        out = StringIO()
2204
        show_diff_trees(revision_tree, preview_tree, out)
3008.1.4 by Michael Hudson
Merge test enhancements
2205
        lines = out.getvalue().splitlines()
2206
        self.assertEqual(lines[0], "=== added file 'file2'")
2207
        # 3 lines of diff administrivia
2208
        self.assertEqual(lines[4], "+content B")
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2209
2210
    def test_transform_conflicts(self):
2211
        revision_tree = self.create_tree()
2212
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2213
        self.addCleanup(preview.finalize)
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2214
        preview.new_file('a', preview.root, 'content 2')
2215
        resolve_conflicts(preview)
2216
        trans_id = preview.trans_id_file_id('a-id')
2217
        self.assertEqual('a.moved', preview.final_name(trans_id))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2218
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2219
    def get_tree_and_preview_tree(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2220
        revision_tree = self.create_tree()
2221
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2222
        self.addCleanup(preview.finalize)
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2223
        a_trans_id = preview.trans_id_file_id('a-id')
2224
        preview.delete_contents(a_trans_id)
2225
        preview.create_file('b content', a_trans_id)
2226
        preview_tree = preview.get_preview_tree()
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2227
        return revision_tree, preview_tree
2228
2229
    def test_iter_changes(self):
2230
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2231
        root = revision_tree.inventory.root.file_id
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2232
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
2233
                          (root, root), ('a', 'a'), ('file', 'file'),
2234
                          (False, False))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2235
                          list(preview_tree.iter_changes(revision_tree)))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2236
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2237
    def test_include_unchanged_succeeds(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2238
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2239
        changes = preview_tree.iter_changes(revision_tree,
2240
                                            include_unchanged=True)
2241
        root = revision_tree.inventory.root.file_id
2242
2243
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2244
2245
    def test_specific_files(self):
2246
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2247
        changes = preview_tree.iter_changes(revision_tree,
2248
                                            specific_files=[''])
2249
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2250
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2251
    def test_want_unversioned(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2252
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2253
        changes = preview_tree.iter_changes(revision_tree,
2254
                                            want_unversioned=True)
2255
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2256
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2257
    def test_ignore_extra_trees_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2258
        # extra_trees is harmless without specific_files, so we'll silently
2259
        # accept it, even though we won't use it.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2260
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2261
        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
2262
2263
    def test_ignore_require_versioned_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2264
        # require_versioned is meaningless without specific_files.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2265
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2266
        preview_tree.iter_changes(revision_tree, require_versioned=False)
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2267
2268
    def test_ignore_pb(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2269
        # 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
2270
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2271
        preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2272
2273
    def test_kind(self):
2274
        revision_tree = self.create_tree()
2275
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2276
        self.addCleanup(preview.finalize)
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2277
        preview.new_file('file', preview.root, 'contents', 'file-id')
2278
        preview.new_directory('directory', preview.root, 'dir-id')
2279
        preview_tree = preview.get_preview_tree()
2280
        self.assertEqual('file', preview_tree.kind('file-id'))
2281
        self.assertEqual('directory', preview_tree.kind('dir-id'))
2282
2283
    def test_get_file_mtime(self):
2284
        preview = self.get_empty_preview()
2285
        file_trans_id = preview.new_file('file', preview.root, 'contents',
2286
                                         'file-id')
2287
        limbo_path = preview._limbo_name(file_trans_id)
2288
        preview_tree = preview.get_preview_tree()
2289
        self.assertEqual(os.stat(limbo_path).st_mtime,
2290
                         preview_tree.get_file_mtime('file-id'))
2291
4635.1.1 by Aaron Bentley
Fix OSError with renamed files in PreviewTree.
2292
    def test_get_file_mtime_renamed(self):
2293
        work_tree = self.make_branch_and_tree('tree')
2294
        self.build_tree(['tree/file'])
2295
        work_tree.add('file', 'file-id')
2296
        preview = TransformPreview(work_tree)
2297
        self.addCleanup(preview.finalize)
2298
        file_trans_id = preview.trans_id_tree_file_id('file-id')
2299
        preview.adjust_path('renamed', preview.root, file_trans_id)
2300
        preview_tree = preview.get_preview_tree()
2301
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
2302
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
2303
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2304
    def test_get_file(self):
2305
        preview = self.get_empty_preview()
2306
        preview.new_file('file', preview.root, 'contents', 'file-id')
2307
        preview_tree = preview.get_preview_tree()
2308
        tree_file = preview_tree.get_file('file-id')
2309
        try:
2310
            self.assertEqual('contents', tree_file.read())
2311
        finally:
2312
            tree_file.close()
3228.1.2 by James Henstridge
Simplify test, and move it down to be next to the other _PreviewTree tests.
2313
2314
    def test_get_symlink_target(self):
2315
        self.requireFeature(SymlinkFeature)
2316
        preview = self.get_empty_preview()
2317
        preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2318
        preview_tree = preview.get_preview_tree()
2319
        self.assertEqual('target',
2320
                         preview_tree.get_symlink_target('symlink-id'))
3363.2.18 by Aaron Bentley
Implement correct all_file_ids for PreviewTree
2321
2322
    def test_all_file_ids(self):
2323
        tree = self.make_branch_and_tree('tree')
2324
        self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2325
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2326
        preview = TransformPreview(tree)
2327
        self.addCleanup(preview.finalize)
2328
        preview.unversion_file(preview.trans_id_file_id('b-id'))
2329
        c_trans_id = preview.trans_id_file_id('c-id')
2330
        preview.unversion_file(c_trans_id)
2331
        preview.version_file('c-id', c_trans_id)
2332
        preview_tree = preview.get_preview_tree()
2333
        self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2334
                         preview_tree.all_file_ids())
3363.2.19 by Aaron Bentley
Make PreviewTree.path2id correct
2335
2336
    def test_path2id_deleted_unchanged(self):
2337
        tree = self.make_branch_and_tree('tree')
2338
        self.build_tree(['tree/unchanged', 'tree/deleted'])
2339
        tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2340
        preview = TransformPreview(tree)
2341
        self.addCleanup(preview.finalize)
2342
        preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2343
        preview_tree = preview.get_preview_tree()
2344
        self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2345
        self.assertIs(None, preview_tree.path2id('deleted'))
2346
2347
    def test_path2id_created(self):
2348
        tree = self.make_branch_and_tree('tree')
2349
        self.build_tree(['tree/unchanged'])
2350
        tree.add(['unchanged'], ['unchanged-id'])
2351
        preview = TransformPreview(tree)
2352
        self.addCleanup(preview.finalize)
2353
        preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2354
            'contents', 'new-id')
2355
        preview_tree = preview.get_preview_tree()
2356
        self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2357
2358
    def test_path2id_moved(self):
2359
        tree = self.make_branch_and_tree('tree')
2360
        self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2361
        tree.add(['old_parent', 'old_parent/child'],
2362
                 ['old_parent-id', 'child-id'])
2363
        preview = TransformPreview(tree)
2364
        self.addCleanup(preview.finalize)
2365
        new_parent = preview.new_directory('new_parent', preview.root,
2366
                                           'new_parent-id')
2367
        preview.adjust_path('child', new_parent,
2368
                            preview.trans_id_file_id('child-id'))
2369
        preview_tree = preview.get_preview_tree()
2370
        self.assertIs(None, preview_tree.path2id('old_parent/child'))
2371
        self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2372
2373
    def test_path2id_renamed_parent(self):
2374
        tree = self.make_branch_and_tree('tree')
2375
        self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2376
        tree.add(['old_name', 'old_name/child'],
2377
                 ['parent-id', 'child-id'])
2378
        preview = TransformPreview(tree)
2379
        self.addCleanup(preview.finalize)
2380
        preview.adjust_path('new_name', preview.root,
2381
                            preview.trans_id_file_id('parent-id'))
2382
        preview_tree = preview.get_preview_tree()
2383
        self.assertIs(None, preview_tree.path2id('old_name/child'))
2384
        self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
3363.2.21 by Aaron Bentley
Implement iter_entries_by_dir
2385
2386
    def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2387
        preview_tree = tt.get_preview_tree()
2388
        preview_result = list(preview_tree.iter_entries_by_dir(
2389
                              specific_file_ids))
2390
        tree = tt._tree
2391
        tt.apply()
2392
        actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2393
        self.assertEqual(actual_result, preview_result)
2394
2395
    def test_iter_entries_by_dir_new(self):
2396
        tree = self.make_branch_and_tree('tree')
2397
        tt = TreeTransform(tree)
2398
        tt.new_file('new', tt.root, 'contents', 'new-id')
2399
        self.assertMatchingIterEntries(tt)
2400
2401
    def test_iter_entries_by_dir_deleted(self):
2402
        tree = self.make_branch_and_tree('tree')
2403
        self.build_tree(['tree/deleted'])
2404
        tree.add('deleted', 'deleted-id')
2405
        tt = TreeTransform(tree)
2406
        tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2407
        self.assertMatchingIterEntries(tt)
2408
2409
    def test_iter_entries_by_dir_unversioned(self):
2410
        tree = self.make_branch_and_tree('tree')
2411
        self.build_tree(['tree/removed'])
2412
        tree.add('removed', 'removed-id')
2413
        tt = TreeTransform(tree)
2414
        tt.unversion_file(tt.trans_id_file_id('removed-id'))
2415
        self.assertMatchingIterEntries(tt)
2416
2417
    def test_iter_entries_by_dir_moved(self):
2418
        tree = self.make_branch_and_tree('tree')
2419
        self.build_tree(['tree/moved', 'tree/new_parent/'])
2420
        tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2421
        tt = TreeTransform(tree)
2422
        tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2423
                       tt.trans_id_file_id('moved-id'))
2424
        self.assertMatchingIterEntries(tt)
2425
2426
    def test_iter_entries_by_dir_specific_file_ids(self):
2427
        tree = self.make_branch_and_tree('tree')
2428
        tree.set_root_id('tree-root-id')
2429
        self.build_tree(['tree/parent/', 'tree/parent/child'])
2430
        tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2431
        tt = TreeTransform(tree)
2432
        self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
3363.2.26 by Aaron Bentley
Get symlinks working
2433
2434
    def test_symlink_content_summary(self):
2435
        self.requireFeature(SymlinkFeature)
2436
        preview = self.get_empty_preview()
2437
        preview.new_symlink('path', preview.root, 'target', 'path-id')
2438
        summary = preview.get_preview_tree().path_content_summary('path')
2439
        self.assertEqual(('symlink', None, None, 'target'), summary)
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2440
2441
    def test_missing_content_summary(self):
2442
        preview = self.get_empty_preview()
2443
        summary = preview.get_preview_tree().path_content_summary('path')
2444
        self.assertEqual(('missing', None, None, None), summary)
2445
2446
    def test_deleted_content_summary(self):
2447
        tree = self.make_branch_and_tree('tree')
2448
        self.build_tree(['tree/path/'])
2449
        tree.add('path')
2450
        preview = TransformPreview(tree)
2451
        self.addCleanup(preview.finalize)
2452
        preview.delete_contents(preview.trans_id_tree_path('path'))
2453
        summary = preview.get_preview_tree().path_content_summary('path')
2454
        self.assertEqual(('missing', None, None, None), summary)
2455
3363.2.30 by Aaron Bentley
Improve execute bit testing
2456
    def test_file_content_summary_executable(self):
2457
        if not osutils.supports_executable():
2458
            raise TestNotApplicable()
2459
        preview = self.get_empty_preview()
2460
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2461
        preview.set_executability(True, path_id)
2462
        summary = preview.get_preview_tree().path_content_summary('path')
2463
        self.assertEqual(4, len(summary))
2464
        self.assertEqual('file', summary[0])
2465
        # size must be known
2466
        self.assertEqual(len('contents'), summary[1])
2467
        # executable
2468
        self.assertEqual(True, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
2469
        # will not have hash (not cheap to determine)
2470
        self.assertIs(None, summary[3])
3363.2.30 by Aaron Bentley
Improve execute bit testing
2471
2472
    def test_change_executability(self):
2473
        if not osutils.supports_executable():
2474
            raise TestNotApplicable()
2475
        tree = self.make_branch_and_tree('tree')
2476
        self.build_tree(['tree/path'])
2477
        tree.add('path')
2478
        preview = TransformPreview(tree)
2479
        self.addCleanup(preview.finalize)
2480
        path_id = preview.trans_id_tree_path('path')
2481
        preview.set_executability(True, path_id)
2482
        summary = preview.get_preview_tree().path_content_summary('path')
2483
        self.assertEqual(True, summary[2])
2484
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2485
    def test_file_content_summary_non_exec(self):
2486
        preview = self.get_empty_preview()
2487
        preview.new_file('path', preview.root, 'contents', 'path-id')
2488
        summary = preview.get_preview_tree().path_content_summary('path')
2489
        self.assertEqual(4, len(summary))
2490
        self.assertEqual('file', summary[0])
2491
        # size must be known
3363.2.30 by Aaron Bentley
Improve execute bit testing
2492
        self.assertEqual(len('contents'), summary[1])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2493
        # not executable
2494
        if osutils.supports_executable():
2495
            self.assertEqual(False, summary[2])
2496
        else:
2497
            self.assertEqual(None, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
2498
        # will not have hash (not cheap to determine)
2499
        self.assertIs(None, summary[3])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2500
2501
    def test_dir_content_summary(self):
2502
        preview = self.get_empty_preview()
2503
        preview.new_directory('path', preview.root, 'path-id')
2504
        summary = preview.get_preview_tree().path_content_summary('path')
2505
        self.assertEqual(('directory', None, None, None), summary)
2506
2507
    def test_tree_content_summary(self):
2508
        preview = self.get_empty_preview()
2509
        path = preview.new_directory('path', preview.root, 'path-id')
2510
        preview.set_tree_reference('rev-1', path)
2511
        summary = preview.get_preview_tree().path_content_summary('path')
2512
        self.assertEqual(4, len(summary))
2513
        self.assertEqual('tree-reference', summary[0])
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
2514
2515
    def test_annotate(self):
2516
        tree = self.make_branch_and_tree('tree')
2517
        self.build_tree_contents([('tree/file', 'a\n')])
2518
        tree.add('file', 'file-id')
2519
        tree.commit('a', rev_id='one')
2520
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2521
        preview = TransformPreview(tree)
2522
        self.addCleanup(preview.finalize)
2523
        file_trans_id = preview.trans_id_file_id('file-id')
2524
        preview.delete_contents(file_trans_id)
2525
        preview.create_file('a\nb\nc\n', file_trans_id)
2526
        preview_tree = preview.get_preview_tree()
2527
        expected = [
2528
            ('one', 'a\n'),
2529
            ('me:', 'b\n'),
2530
            ('me:', 'c\n'),
2531
        ]
2532
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2533
        self.assertEqual(expected, annotation)
2534
2535
    def test_annotate_missing(self):
2536
        preview = self.get_empty_preview()
2537
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2538
        preview_tree = preview.get_preview_tree()
2539
        expected = [
2540
            ('me:', 'a\n'),
2541
            ('me:', 'b\n'),
2542
            ('me:', 'c\n'),
2543
         ]
2544
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2545
        self.assertEqual(expected, annotation)
2546
3363.7.3 by Aaron Bentley
Add test that annotate correctly handles renames
2547
    def test_annotate_rename(self):
2548
        tree = self.make_branch_and_tree('tree')
2549
        self.build_tree_contents([('tree/file', 'a\n')])
2550
        tree.add('file', 'file-id')
2551
        tree.commit('a', rev_id='one')
2552
        preview = TransformPreview(tree)
2553
        self.addCleanup(preview.finalize)
2554
        file_trans_id = preview.trans_id_file_id('file-id')
2555
        preview.adjust_path('newname', preview.root, file_trans_id)
2556
        preview_tree = preview.get_preview_tree()
2557
        expected = [
2558
            ('one', 'a\n'),
2559
        ]
2560
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2561
        self.assertEqual(expected, annotation)
2562
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
2563
    def test_annotate_deleted(self):
2564
        tree = self.make_branch_and_tree('tree')
2565
        self.build_tree_contents([('tree/file', 'a\n')])
2566
        tree.add('file', 'file-id')
2567
        tree.commit('a', rev_id='one')
2568
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2569
        preview = TransformPreview(tree)
2570
        self.addCleanup(preview.finalize)
2571
        file_trans_id = preview.trans_id_file_id('file-id')
2572
        preview.delete_contents(file_trans_id)
2573
        preview_tree = preview.get_preview_tree()
2574
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2575
        self.assertIs(None, annotation)
2576
3363.2.36 by Aaron Bentley
Fix PreviewTree.stored_kind
2577
    def test_stored_kind(self):
2578
        preview = self.get_empty_preview()
2579
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2580
        preview_tree = preview.get_preview_tree()
2581
        self.assertEqual('file', preview_tree.stored_kind('file-id'))
3363.2.37 by Aaron Bentley
Fix is_executable
2582
2583
    def test_is_executable(self):
2584
        preview = self.get_empty_preview()
2585
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2586
        preview.set_executability(True, preview.trans_id_file_id('file-id'))
2587
        preview_tree = preview.get_preview_tree()
2588
        self.assertEqual(True, preview_tree.is_executable('file-id'))
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2589
3571.1.1 by Aaron Bentley
Allow set/get of parent_ids in PreviewTree
2590
    def test_get_set_parent_ids(self):
2591
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2592
        self.assertEqual([], preview_tree.get_parent_ids())
2593
        preview_tree.set_parent_ids(['rev-1'])
2594
        self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
2595
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2596
    def test_plan_file_merge(self):
2597
        work_a = self.make_branch_and_tree('wta')
2598
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2599
        work_a.add('file', 'file-id')
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
2600
        base_id = work_a.commit('base version')
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2601
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2602
        preview = TransformPreview(work_a)
2603
        self.addCleanup(preview.finalize)
2604
        trans_id = preview.trans_id_file_id('file-id')
2605
        preview.delete_contents(trans_id)
2606
        preview.create_file('b\nc\nd\ne\n', trans_id)
2607
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2608
        tree_a = preview.get_preview_tree()
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
2609
        tree_a.set_parent_ids([base_id])
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2610
        self.assertEqual([
3363.9.5 by Aaron Bentley
Move killed-a from top to bottom
2611
            ('killed-a', 'a\n'),
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2612
            ('killed-b', 'b\n'),
2613
            ('unchanged', 'c\n'),
2614
            ('unchanged', 'd\n'),
2615
            ('new-a', 'e\n'),
2616
            ('new-b', 'f\n'),
2617
        ], 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
2618
2619
    def test_plan_file_merge_revision_tree(self):
2620
        work_a = self.make_branch_and_tree('wta')
2621
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2622
        work_a.add('file', 'file-id')
2623
        base_id = work_a.commit('base version')
2624
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2625
        preview = TransformPreview(work_a.basis_tree())
2626
        self.addCleanup(preview.finalize)
2627
        trans_id = preview.trans_id_file_id('file-id')
2628
        preview.delete_contents(trans_id)
2629
        preview.create_file('b\nc\nd\ne\n', trans_id)
2630
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2631
        tree_a = preview.get_preview_tree()
2632
        tree_a.set_parent_ids([base_id])
2633
        self.assertEqual([
2634
            ('killed-a', 'a\n'),
2635
            ('killed-b', 'b\n'),
2636
            ('unchanged', 'c\n'),
2637
            ('unchanged', 'd\n'),
2638
            ('new-a', 'e\n'),
2639
            ('new-b', 'f\n'),
2640
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
2641
2642
    def test_walkdirs(self):
2643
        preview = self.get_empty_preview()
4634.57.3 by Aaron Bentley
Fix failing test.
2644
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
2645
        # FIXME: new_directory should mark root.
2646
        preview.adjust_path('', ROOT_PARENT, root)
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
2647
        preview_tree = preview.get_preview_tree()
2648
        file_trans_id = preview.new_file('a', preview.root, 'contents',
2649
                                         'a-id')
2650
        expected = [(('', 'tree-root'),
2651
                    [('a', 'a', 'file', None, 'a-id', 'file')])]
2652
        self.assertEqual(expected, list(preview_tree.walkdirs()))
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
2653
2654
    def test_extras(self):
2655
        work_tree = self.make_branch_and_tree('tree')
2656
        self.build_tree(['tree/removed-file', 'tree/existing-file',
2657
                         'tree/not-removed-file'])
2658
        work_tree.add(['removed-file', 'not-removed-file'])
2659
        preview = TransformPreview(work_tree)
3363.13.3 by Aaron Bentley
Add cleanup
2660
        self.addCleanup(preview.finalize)
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
2661
        preview.new_file('new-file', preview.root, 'contents')
2662
        preview.new_file('new-versioned-file', preview.root, 'contents',
2663
                         'new-versioned-id')
2664
        tree = preview.get_preview_tree()
2665
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
2666
        self.assertEqual(set(['new-file', 'removed-file', 'existing-file']),
2667
                         set(tree.extras()))
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2668
3363.17.2 by Aaron Bentley
Add text checking
2669
    def test_merge_into_preview(self):
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2670
        work_tree = self.make_branch_and_tree('tree')
3363.17.2 by Aaron Bentley
Add text checking
2671
        self.build_tree_contents([('tree/file','b\n')])
2672
        work_tree.add('file', 'file-id')
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2673
        work_tree.commit('first commit')
2674
        child_tree = work_tree.bzrdir.sprout('child').open_workingtree()
3363.17.2 by Aaron Bentley
Add text checking
2675
        self.build_tree_contents([('child/file','b\nc\n')])
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2676
        child_tree.commit('child commit')
2677
        child_tree.lock_write()
2678
        self.addCleanup(child_tree.unlock)
2679
        work_tree.lock_write()
2680
        self.addCleanup(work_tree.unlock)
2681
        preview = TransformPreview(work_tree)
2682
        self.addCleanup(preview.finalize)
3363.17.6 by Aaron Bentley
Improve test scenario
2683
        file_trans_id = preview.trans_id_file_id('file-id')
2684
        preview.delete_contents(file_trans_id)
2685
        preview.create_file('a\nb\n', file_trans_id)
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2686
        pb = progress.DummyProgress()
4634.57.2 by Aaron Bentley
Fix failing test.
2687
        preview_tree = preview.get_preview_tree()
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2688
        merger = Merger.from_revision_ids(pb, preview_tree,
2689
                                          child_tree.branch.last_revision(),
2690
                                          other_branch=child_tree.branch,
2691
                                          tree_branch=work_tree.branch)
2692
        merger.merge_type = Merge3Merger
2693
        tt = merger.make_merger().make_preview_transform()
3363.17.2 by Aaron Bentley
Add text checking
2694
        self.addCleanup(tt.finalize)
2695
        final_tree = tt.get_preview_tree()
2696
        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
2697
2698
    def test_merge_preview_into_workingtree(self):
2699
        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.
2700
        tree.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2701
        tt = TransformPreview(tree)
2702
        self.addCleanup(tt.finalize)
2703
        tt.new_file('name', tt.root, 'content', 'file-id')
2704
        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.
2705
        tree2.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2706
        pb = progress.DummyProgress()
2707
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2708
                                         pb, tree.basis_tree())
2709
        merger.merge_type = Merge3Merger
2710
        merger.do_merge()
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
2711
3363.17.21 by Aaron Bentley
Conflicts are handled when merging from preview trees
2712
    def test_merge_preview_into_workingtree_handles_conflicts(self):
2713
        tree = self.make_branch_and_tree('tree')
2714
        self.build_tree_contents([('tree/foo', 'bar')])
2715
        tree.add('foo', 'foo-id')
2716
        tree.commit('foo')
2717
        tt = TransformPreview(tree)
2718
        self.addCleanup(tt.finalize)
2719
        trans_id = tt.trans_id_file_id('foo-id')
2720
        tt.delete_contents(trans_id)
2721
        tt.create_file('baz', trans_id)
2722
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2723
        self.build_tree_contents([('tree2/foo', 'qux')])
2724
        pb = progress.DummyProgress()
2725
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2726
                                         pb, tree.basis_tree())
2727
        merger.merge_type = Merge3Merger
2728
        merger.do_merge()
2729
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
2730
    def test_is_executable(self):
2731
        tree = self.make_branch_and_tree('tree')
2732
        preview = TransformPreview(tree)
2733
        self.addCleanup(preview.finalize)
2734
        preview.new_file('foo', preview.root, 'bar', 'baz-id')
2735
        preview_tree = preview.get_preview_tree()
2736
        self.assertEqual(False, preview_tree.is_executable('baz-id',
2737
                                                           'tree/foo'))
2738
        self.assertEqual(False, preview_tree.is_executable('baz-id'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2739
4354.4.4 by Aaron Bentley
Simplify by using CommitBuilder directly
2740
    def test_commit_preview_tree(self):
2741
        tree = self.make_branch_and_tree('tree')
2742
        rev_id = tree.commit('rev1')
2743
        tree.branch.lock_write()
2744
        self.addCleanup(tree.branch.unlock)
2745
        tt = TransformPreview(tree)
2746
        tt.new_file('file', tt.root, 'contents', 'file_id')
2747
        self.addCleanup(tt.finalize)
2748
        preview = tt.get_preview_tree()
2749
        preview.set_parent_ids([rev_id])
2750
        builder = tree.branch.get_commit_builder([rev_id])
2751
        list(builder.record_iter_changes(preview, rev_id, tt.iter_changes()))
2752
        builder.finish_inventory()
2753
        rev2_id = builder.commit('rev2')
2754
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
2755
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
2756
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2757
    def test_ascii_limbo_paths(self):
4634.79.2 by Aaron Bentley
Avoid runing test on non-unicode filesystems.
2758
        self.requireFeature(tests.UnicodeFilenameFeature)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2759
        branch = self.make_branch('any')
2760
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
2761
        tt = TransformPreview(tree)
2762
        foo_id = tt.new_directory('', ROOT_PARENT)
2763
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
2764
        limbo_path = tt._limbo_name(bar_id)
2765
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
2766
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2767
0.13.13 by Aaron Bentley
Add direct test of serialization records
2768
class FakeSerializer(object):
2769
    """Serializer implementation that simply returns the input.
2770
2771
    The input is returned in the order used by pack.ContainerPushParser.
2772
    """
2773
    @staticmethod
2774
    def bytes_record(bytes, names):
2775
        return names, bytes
2776
2777
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2778
class TestSerializeTransform(tests.TestCaseWithTransport):
2779
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
2780
    _test_needs_features = [tests.UnicodeFilenameFeature]
2781
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2782
    def get_preview(self, tree=None):
2783
        if tree is None:
2784
            tree = self.make_branch_and_tree('tree')
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2785
        tt = TransformPreview(tree)
2786
        self.addCleanup(tt.finalize)
2787
        return tt
2788
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2789
    def assertSerializesTo(self, expected, tt):
2790
        records = list(tt.serialize(FakeSerializer()))
2791
        self.assertEqual(expected, records)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2792
0.13.13 by Aaron Bentley
Add direct test of serialization records
2793
    @staticmethod
2794
    def default_attribs():
2795
        return {
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2796
            '_id_number': 1,
0.13.13 by Aaron Bentley
Add direct test of serialization records
2797
            '_new_name': {},
2798
            '_new_parent': {},
2799
            '_new_executability': {},
2800
            '_new_id': {},
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2801
            '_tree_path_ids': {'': 'new-0'},
0.13.13 by Aaron Bentley
Add direct test of serialization records
2802
            '_removed_id': [],
2803
            '_removed_contents': [],
2804
            '_non_present_ids': {},
2805
            }
2806
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2807
    def make_records(self, attribs, contents):
2808
        records = [
2809
            (((('attribs'),),), bencode.bencode(attribs))]
2810
        records.extend([(((n, k),), c) for n, k, c in contents])
2811
        return records
2812
0.13.13 by Aaron Bentley
Add direct test of serialization records
2813
    def creation_records(self):
2814
        attribs = self.default_attribs()
2815
        attribs['_id_number'] = 3
2816
        attribs['_new_name'] = {
2817
            'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
2818
        attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
2819
        attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
2820
        attribs['_new_executability'] = {'new-1': 1}
2821
        contents = [
2822
            ('new-1', 'file', 'i 1\nbar\n'),
2823
            ('new-2', 'directory', ''),
2824
            ]
2825
        return self.make_records(attribs, contents)
2826
2827
    def test_serialize_creation(self):
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2828
        tt = self.get_preview()
0.13.13 by Aaron Bentley
Add direct test of serialization records
2829
        tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
2830
        tt.new_directory('qux', tt.root, 'quxx')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
2831
        self.assertSerializesTo(self.creation_records(), tt)
0.13.13 by Aaron Bentley
Add direct test of serialization records
2832
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2833
    def test_deserialize_creation(self):
2834
        tt = self.get_preview()
2835
        tt.deserialize(iter(self.creation_records()))
2836
        self.assertEqual(3, tt._id_number)
2837
        self.assertEqual({'new-1': u'foo\u1234',
2838
                          'new-2': 'qux'}, tt._new_name)
2839
        self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
2840
        self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
2841
        self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
2842
        self.assertEqual({'new-1': True}, tt._new_executability)
2843
        self.assertEqual({'new-1': 'file',
2844
                          'new-2': 'directory'}, tt._new_contents)
2845
        foo_limbo = open(tt._limbo_name('new-1'), 'rb')
2846
        try:
2847
            foo_content = foo_limbo.read()
2848
        finally:
2849
            foo_limbo.close()
2850
        self.assertEqual('bar', foo_content)
2851
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2852
    def symlink_creation_records(self):
2853
        attribs = self.default_attribs()
2854
        attribs['_id_number'] = 2
2855
        attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
2856
        attribs['_new_parent'] = {'new-1': 'new-0'}
2857
        contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
2858
        return self.make_records(attribs, contents)
2859
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2860
    def test_serialize_symlink_creation(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2861
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2862
        tt = self.get_preview()
0.13.16 by Aaron Bentley
Add unicode symlink targets to tests
2863
        tt.new_symlink(u'foo\u1234', tt.root, u'bar\u1234')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
2864
        self.assertSerializesTo(self.symlink_creation_records(), tt)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2865
2866
    def test_deserialize_symlink_creation(self):
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
2867
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2868
        tt = self.get_preview()
2869
        tt.deserialize(iter(self.symlink_creation_records()))
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
2870
        abspath = tt._limbo_name('new-1')
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
2871
        foo_content = osutils.readlink(abspath)
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
2872
        self.assertEqual(u'bar\u1234', foo_content)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2873
0.13.19 by Aaron Bentley
Clean up serialization tests
2874
    def make_destruction_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2875
        tree = self.make_branch_and_tree('.')
2876
        self.build_tree([u'foo\u1234', 'bar'])
2877
        tree.add([u'foo\u1234', 'bar'], ['foo-id', 'bar-id'])
0.13.19 by Aaron Bentley
Clean up serialization tests
2878
        return self.get_preview(tree)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2879
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2880
    def destruction_records(self):
2881
        attribs = self.default_attribs()
2882
        attribs['_id_number'] = 3
2883
        attribs['_removed_id'] = ['new-1']
2884
        attribs['_removed_contents'] = ['new-2']
2885
        attribs['_tree_path_ids'] = {
2886
            '': 'new-0',
2887
            u'foo\u1234'.encode('utf-8'): 'new-1',
2888
            'bar': 'new-2',
2889
            }
2890
        return self.make_records(attribs, [])
2891
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2892
    def test_serialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
2893
        tt = self.make_destruction_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2894
        foo_trans_id = tt.trans_id_tree_file_id('foo-id')
2895
        tt.unversion_file(foo_trans_id)
2896
        bar_trans_id = tt.trans_id_tree_file_id('bar-id')
2897
        tt.delete_contents(bar_trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2898
        self.assertSerializesTo(self.destruction_records(), tt)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2899
2900
    def test_deserialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
2901
        tt = self.make_destruction_preview()
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2902
        tt.deserialize(iter(self.destruction_records()))
2903
        self.assertEqual({u'foo\u1234': 'new-1',
2904
                          'bar': 'new-2',
2905
                          '': tt.root}, tt._tree_path_ids)
2906
        self.assertEqual({'new-1': u'foo\u1234',
2907
                          'new-2': 'bar',
2908
                          tt.root: ''}, tt._tree_id_paths)
2909
        self.assertEqual(set(['new-1']), tt._removed_id)
2910
        self.assertEqual(set(['new-2']), tt._removed_contents)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2911
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2912
    def missing_records(self):
2913
        attribs = self.default_attribs()
2914
        attribs['_id_number'] = 2
2915
        attribs['_non_present_ids'] = {
2916
            'boo': 'new-1',}
2917
        return self.make_records(attribs, [])
2918
2919
    def test_serialize_missing(self):
2920
        tt = self.get_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2921
        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
2922
        self.assertSerializesTo(self.missing_records(), tt)
2923
2924
    def test_deserialize_missing(self):
2925
        tt = self.get_preview()
2926
        tt.deserialize(iter(self.missing_records()))
2927
        self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
2928
2929
    def make_modification_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2930
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
2931
        LINES_TWO = 'z\nbb\nx\ndd\n'
2932
        tree = self.make_branch_and_tree('tree')
2933
        self.build_tree_contents([('tree/file', LINES_ONE)])
2934
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2935
        return self.get_preview(tree), LINES_TWO
2936
2937
    def modification_records(self):
2938
        attribs = self.default_attribs()
2939
        attribs['_id_number'] = 2
2940
        attribs['_tree_path_ids'] = {
2941
            'file': 'new-1',
2942
            '': 'new-0',}
2943
        attribs['_removed_contents'] = ['new-1']
2944
        contents = [('new-1', 'file',
2945
                     'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
2946
        return self.make_records(attribs, contents)
2947
2948
    def test_serialize_modification(self):
2949
        tt, LINES = self.make_modification_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2950
        trans_id = tt.trans_id_file_id('file-id')
2951
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2952
        tt.create_file(LINES, trans_id)
2953
        self.assertSerializesTo(self.modification_records(), tt)
2954
2955
    def test_deserialize_modification(self):
2956
        tt, LINES = self.make_modification_preview()
2957
        tt.deserialize(iter(self.modification_records()))
2958
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
2959
2960
    def make_kind_change_preview(self):
2961
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2962
        tree = self.make_branch_and_tree('tree')
2963
        self.build_tree(['tree/foo/'])
2964
        tree.add('foo', 'foo-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2965
        return self.get_preview(tree), LINES
2966
2967
    def kind_change_records(self):
2968
        attribs = self.default_attribs()
2969
        attribs['_id_number'] = 2
2970
        attribs['_tree_path_ids'] = {
2971
            'foo': 'new-1',
2972
            '': 'new-0',}
2973
        attribs['_removed_contents'] = ['new-1']
2974
        contents = [('new-1', 'file',
2975
                     'i 4\na\nb\nc\nd\n\n')]
2976
        return self.make_records(attribs, contents)
2977
2978
    def test_serialize_kind_change(self):
2979
        tt, LINES = self.make_kind_change_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2980
        trans_id = tt.trans_id_file_id('foo-id')
2981
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2982
        tt.create_file(LINES, trans_id)
2983
        self.assertSerializesTo(self.kind_change_records(), tt)
2984
2985
    def test_deserialize_kind_change(self):
2986
        tt, LINES = self.make_kind_change_preview()
2987
        tt.deserialize(iter(self.kind_change_records()))
2988
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
2989
2990
    def make_add_contents_preview(self):
2991
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2992
        tree = self.make_branch_and_tree('tree')
2993
        self.build_tree(['tree/foo'])
2994
        tree.add('foo')
2995
        os.unlink('tree/foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2996
        return self.get_preview(tree), LINES
2997
2998
    def add_contents_records(self):
2999
        attribs = self.default_attribs()
3000
        attribs['_id_number'] = 2
3001
        attribs['_tree_path_ids'] = {
3002
            'foo': 'new-1',
3003
            '': 'new-0',}
3004
        contents = [('new-1', 'file',
3005
                     'i 4\na\nb\nc\nd\n\n')]
3006
        return self.make_records(attribs, contents)
3007
3008
    def test_serialize_add_contents(self):
3009
        tt, LINES = self.make_add_contents_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3010
        trans_id = tt.trans_id_tree_path('foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3011
        tt.create_file(LINES, trans_id)
3012
        self.assertSerializesTo(self.add_contents_records(), tt)
3013
3014
    def test_deserialize_add_contents(self):
3015
        tt, LINES = self.make_add_contents_preview()
3016
        tt.deserialize(iter(self.add_contents_records()))
3017
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3018
3019
    def test_get_parents_lines(self):
3020
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3021
        LINES_TWO = 'z\nbb\nx\ndd\n'
3022
        tree = self.make_branch_and_tree('tree')
3023
        self.build_tree_contents([('tree/file', LINES_ONE)])
3024
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3025
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3026
        trans_id = tt.trans_id_tree_path('file')
3027
        self.assertEqual((['aa\n', 'bb\n', 'cc\n', 'dd\n'],),
3028
            tt._get_parents_lines(trans_id))
3029
3030
    def test_get_parents_texts(self):
3031
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3032
        LINES_TWO = 'z\nbb\nx\ndd\n'
3033
        tree = self.make_branch_and_tree('tree')
3034
        self.build_tree_contents([('tree/file', LINES_ONE)])
3035
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3036
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3037
        trans_id = tt.trans_id_tree_path('file')
3038
        self.assertEqual((LINES_ONE,),
3039
            tt._get_parents_texts(trans_id))