/brz/remove-bazaar

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