/brz/remove-bazaar

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